前言:最近有种感受,好像微前端成为当下前端工程师的标配,从single-spa到qiankun,各类微前端架构解决方案层出不穷。那一晚上,我在翻阅github时,留意到一个新的微前端框架,来自京东零售开源的
MicroApp
,号称无需像上面提到那两个框架同样须要对子应用的渲染逻辑调整,甚至还不用修改webpack配置。还有一个成功引发我注意的是:它把web-components的概念给用上了!让咱们一探究竟!css
众所周知,Web Components 是一种原生实现可服用web组件的方案,你能够理解为相似在vue、React这类框架下开发的组件。不一样的是,基于这个标准下开发的组件能够直接在html下使用,不用依赖其余第三方的库。html
换句话说:
部分现代浏览器提供的API使咱们建立一个可复用的组件而无需依赖任何框架成为一种可能
,不会被框架所限制前端
主要包括如下几个特征:vue
那 Web Components是如何建立一个组件的?咱们来看下下面这个demo实践node
针对
web components
的实践, 我在github上找到一个demo。以下图所示,假设一个页面是由三个不一样团队负责独立开发,A团队负责红色区域的总体展现功能,B团队和C团队分别负责蓝色和绿色区域(在红色区域内展现),那他们是怎么实现的?webpack
咱们以绿色区域的功能为示例,来看看demo的代码实例,本质上能够理解为定义一个组件green-recos
git
经过上图,咱们来分析这段代码,主要包括如下几点信息:github
window.customElements
中的defind方法来定义注册好的实例HTMLElement
定义一个是实例类CustomEvent
来自定义一个新的事件,而后经过addEventListener
来监听以及element.dispatchEvent()
来分发事件constructor(元素初始化) -> attributeChangedCallback(当元素增长、删除、修改自身属性时,被调用) -> connectedCallback(当元素首次被插入文档DOM时,被调用) -> disconnectedCallback(当 custom element从文档DOM中删除时,被调用)`web
拓展:面试
👨🎓 啊乐同窗:树酱,据说web component兼容性不太好?咋整?
你能够看上图👆 ,大部分浏览器新版本支持,若是想兼容旧版本,莫慌,能够经过引入polyfill来解决兼容问题 webcomponents/polyfills
你也能够经过坚挺WebComponentsReady
这个事件来得知web components是否成功加载
关于样式,上面例子的样式是全局引用的,并无解决样式冲突的问题,那若是想基于Web Components 开发组件,又担忧各组件间存在样式冲突,这个时候你可使用Shadow DOM
来解决,有点相似vue中定义组件中的scoped处理
Shadow DOM: 也称影子DOM,它能够将一个隐藏的、独立的 DOM 附加到一个元素上。以下图MDN官方介绍图所示
那基于web component如何开发一个挂在#shadow-root
的组件?
咱们能够看到经过上图对比上一节的例子,多了attachShadow
的方法使用。它是啥玩意?
官方介绍:经过attachShadow来将一个 shadow root 附加到任何一个元素上。它接受一个配置对象做为参数,该对象有一个
mode
属性。当mode为true,则表示能够经过页面内的 JavaScript 方法来获取 Shadow DOM
🌲 扩展阅读:
啊乐同窗:树君,那我在vue中可使用Web Component开发的自定义组件吗?
能够的,可是有一点要注意就是,Vue
组件开发很相似自定义元素,若是咱们不作点“手段”处理,vue会把你基于Web Component开发的组件看成自己框架下的组件来看待,so 咱们须要配置ignoredElements
,下图是vue官网的示例
若是想了解更多关于Web Component的组件开发,能够看看下面这个开源的组件库
一不当心绕远了,言归正传,聊聊今日主角:micro-app
使用过qiankun的童鞋知道,咱们要在基座集成一个微应用离不开下面👇 这三要素:
虽然改形成本不算特别高,可是能尽可能下降对源代码的侵入性不香吗?
Mrcio-app 走的就是极简的路线,只要修改一丢丢代码就能够实现微应用的集成,号称是目前市面上接入微前端成本最低的方案。那它是如何作到的?
本质上 micro-app 是基于类WebComponent + HTML Entry
实现的微前端架构
官方介绍:经过自定义元素
micro-app
的生命周期函数connectedCallback
监听元素被渲染,加载子应用的html并转换为DOM结构,递归查询全部js和css等静态资源并加载,设置元素隔离,拦截全部动态建立的script、link等标签,提取标签内容。将加载的js通过插件系统处理后放入沙箱中运行,对css资源进行样式隔离,最后将格式化后的元素放入micro-app
中,最终将micro-app
元素渲染为一个微前端的子应用。在渲染的过程当中,会执行开发者绑定的生命周期函数,用于进一步操做。
关于HTML Entry
:相信用过qiankun 的童鞋应该都很熟悉,就是加载微应用的入口文件,一方面对微应用的静态资源js、CSS等文件进行fetch,一方面渲染微应用的dom
类WebComponent
: 咱们在上一节学习web Component中了解到两个特征:CustomElement
和 ShadowDom
,前者使得咱们能够建立自定义标签,后者则促使咱们能够建立支持隔离样式和元素隔离的阴影DOM。而首次说起的类WebComponent是个啥玩意?本质上就是经过使用CustomElement结合自定义的ShadowDom实现WebComponent基本一致的功能
换句话说:让微前端下微应用实现真正意义上的组件化
micro-app 有这几个机制我以为很赞:
created
、mounted
等,而是另辟蹊径,当你在基座集成后,在基座能够直接定义,也能够进行全局监听。以下所示上图的属性配置中name是微应用的名称配置,url是子应用页面地址配置,其余则是各个生命周期函数的定义
上手也很简单,以vue2应用为例,具体参考 github文档。这里不作重复陈述
经过官方在线演示vue微应用Demo,咱们来看看集成后的效果
在控制台咱们能够看到,基座加载完微应用"vue2",在自定义标签micro-app
渲染后就是一个完整子应用Dom,有点相似iframe的感受,而后该子应用的css样式,都多了一个前缀 micro-app[name=vue2]
。这是利用标签的name
属性为每一个样式添加前缀,将子应用的样式影响禁锢在当前标签区域,避免各个微应用之间的样式冲突。这是micro-app的默认隔离机制
啊乐同窗:树酱,他这个元素隔离是怎么实现的?
你听我解释,看下一节源码分析
渲染微应用的过程主要流程图能够参照官方提供,主要包括如下流程
目的是为了提取微应用的link和script,绑定style做用域。最后实现将微应用的style挂在micro-app-head
中 核心源码以下
经过源码的阅读,当咱们在微应用的初始化定义的app.scopecss
配置时(默认开启),就会调用scopedCSS处理dom ,以此实现绑定微应用的css做用域,让咱们看下这个方法的实现 源码连接
我在源码中看到scoped_css主要针对几种cssRule
来作区分处理
啊恒同窗:树酱,什么是Css Rule?
这是一个有历史的概念了,CSSRule
表示一条 CSS 规则。而一个 CSS 样式表包含了一组表示规则CSSRule
对象。 CSSRule 有几种不一样的规则类型,你能够在micro-app主要针对如下几种常规的cssRule区分处理
@media
媒体属性查询的规则@support
能够根据浏览器对CSS特性的支持状况来定义不一样的样式的规则最后将转化成功的style内容,append到micro-app-head中
啊恒同窗:树酱,你说micro-app隔离元素支持shadowDom ?
是的,若是开启shadowDOM
后,上面提到的默认的样式隔离将失效。 且兼容性会比较差
下面是个删减版:关于mircro-app经过Web Component + shadowDOM
的实现子应用初始化的定义,具体的源码你能够阅读框架源码中关于micro_app_element
的定义 源码连接
本质上开启shadowDom后,<micro-app>
标签才算真正实现意义上的WebComponent
关于JS沙箱(sandbox)和数据通讯的实现机制等,在后面展开跟童鞋们分享
往期热门文章📖:
你好,我是🌲 树酱,请你喝杯🍵 记得三连哦~
1.阅读完记得点个赞哦,有👍 有动力
2.关注公众号前端那些趣事,陪你聊聊前端的趣事
3.文章收录在Github frontendThings 感谢Star✨