微前端系列 - 京东micro-app框架源码分析(带视频)

1,898 阅读4分钟

分析

源码分析视频

micro-app 源码解读,分析框架内js隔离和css隔离具体做法:

  • 整体流程是采用WebComponent自定义好micro-app组件

  • 页面渲染时触发组件钩子attributeChangedCallbackconnectedCallback

  • 根据当前子应用的url首页地址,fetch到Html Entry入口html源代码

  • 将上述html代码中head和body标签改为 micro-app-headmicro-app-body

  • 继续将上述html代码中 metaiconprefetchpreload等连接去掉,因为后面主要需要css和js文件

  • 获取上述html代码中js和css文件,进一步根据地址获取到文件内容

  • 如果是css外联文件,则请求css文件内容,向micro-app-head执行 appendChild 方法,添加style标签,标签内容就是css外联文件内容,此时 appendChild 会触发判断是style标签,则给所有样式增加前缀,区分每个子应用样式,做到样式隔离,唯一注意的一个小点是,基座样式会影响子应用的样式,所以需要注意基座中不要写太多样式

  • 如果是js外联文件,则请求js文件文件内容,同步做windowProxy = new Proxy代理,请求到js文件内容后,根据inline参数不同,却是用script标签执行js或者用new Function执行js,外面套代理;(function(proxyWindow){with(proxyWindow.__MICRO_APP_WINDOW__){})(windowProxy),做到js隔离。如果其中有style的appendChild,又会执行上一条,给css增加前缀

  • micro-app默认是不开启shadowDOM,并且不建议开启,原因说是shadowDOM在React框架及一些UI库中的兼容不是很好

启动源码调试

  • 当前micro-app版本是v0.8.10 micro-app

  • 使用yarn

  • 执行 yarn bootstrap 装包

  • 执行 yarn start:main-vue2 启动,可以源代码写debugger调试

  • 打开浏览器 http://localhost:4000/vue2/#/,因为vue2项目的启动是inline可以直接调试,默认的react16没有inline不能调试

一、初始化全局环境和配置项

备份全局环境

首先执行在 MicroApp.start() 方法,其中 initGlobalEnv() 方法 备份全局环境, 因为后面会代理window,并且会重写 document.appendChild 等方法,所以先备份纯净的全局环境

image.png

image.png

初始化配置项参数

重点几个需要关注的:

name,url,data,inline,shadowDOM,disableScopecss,disableSandbox,lifeCycles,preFetchApps

image.png

二、注册组件micro-app

image.png

这里有个细节,是data参数如何生效的?

看过我前面 微前端系列 - Web组件自定义元素介绍 会指定,html中attribute 和 类中property 是各自独立,所以像主应用中data属性的gettersetter会响应

<micro-app name="vue2" url="http://localhost:4001/micro-app/vue2" :data="data" inline></micro-app>

image.png

组件挂着到document后,connectedCallback触发,并将 生命周期Created压入微任务队列 image.png

三、组件生效

此时,我们在主应用中写<micro-app name="vue2" url="http://localhost:4001/micro-app/vue2"></micro-app>应用子应用,发生了什么呢?

  • 组件 appendChild 到document上,此时页面还是空白组件内容,仅仅只有下面这一句 <micro-app name="vue2" url="http://localhost:4001/micro-app/vue2"></micro-app>

  • 组件渲染时,先赋值属性就会先多次执行钩子函数attributeChangedCallback,比如nameurl属性

  • 组件 appendChild 到document上后,会执行钩子函数 connectedCallback,开始执行组件实现内容

四、组件渲染过程

1、是否生成 shadowDom 确定根节点

image.png

2、生成运行时实例并报错

实例中,开启沙箱,请求Html Entry内容,js文件请求,js执行,css文件请求,css隔离,元素隔离 等等

image.png

image.png

到这里,loadSourceCode() 方法是异步请求,所以当前单线程同步就逻辑就走完了,后续是怎么处理获得的子应用html,js,css了

五、fetch子应用入口html文件

  • 直接fetch子应用html文件源代码

  • 将head标签改为micro-app-head,将body标签改为micro-app-body

  • 将注册的插件应用到html中

image.png

六、js文件内容和css文件内容请求并存起来

  • 上述获得html文件内容后,回调extractSourceDom方法

  • 将子应用html改后的源代码添加到div

  • 在html源文件里面去掉meta、icon、preload等标签,并筛选出js和css外联文件地址,如果是css内联代码,就scopeCss方法加上前缀

  • 请求css外联后,将请求到的内容通过style标签appcentChild到micro-app-head头中,以为appendChild已经重写,会触发scopeCss给css内容增加子应用前缀

  • 请求js外联后,将请求到的内容存起来

image.png

七、子应用执行

1、window事件拦截和快照

image.png

init里面回调recordUmdSnapshot方法,里面做window快照,记录子应用生效前全局window事件

image.png

2、html应用到指定容器

  • 上述html文件、js和css文件都请求到并存起来后

  • 根据 app.onLoad()逐步进入到 mount() 方法

  • 请求js外联后,将请求到的内容根据配置项inline判断,如果有inline则用script标签appendChild到micro-app-body底部,当然需要包裹windowProxy;如果没有inlin则用new Function带有windowProxy内存执行

image.png

image.png

至此,子应用的 html,css,js 都应用到主应用容器上了

相关推荐