一、为什么需要微前端
1.what什么是微前端
将不同功能按照不同维度拆分成多个子应用,通过主应用加载子应用。
微前端核心:在于拆,拆完后再合。
例如:
网厅项目:(1)已经实现的基座(中信方正),子应用:方正obs-fcf,中信obs-zx,中信自研zx-online
(2)即将开发的场景机构预约开户考虑怎么拆分,放在基座还是子应用,公共模块
2.why为什么使用
(1)技术栈不同解决协同(vue, react , angle, jquery)
(2)团队独立开发部署
(3)老的应用代码,老的应用很稳定,如果重构时间不允许,稳定性短时间无法保证
3.how怎么去落地微前端
架构方案:
(1)singleSPA
核心功能实现了路由劫持和应用加载
缺点:1.没有处理父子应用或者平级应用的css样式隔离
2.js未执行隔离,都使用window,命名一致的话相互覆盖
(2)qiankun
qiankun:基于singleSPA t提供了开箱即用的API,做到了(singleSPA + sandbox + import-html-entry),与技术栈无关,通过协议接入(子应用必须导出bootstrap,mount,unmount方法供父应用调用)
4.Why Not Iframe
(1)iframe 最大的特性就是提供了浏览器原生的硬隔离方案,不论是样式隔离、js 隔离这类问题统统都能被完美解决。但他的最大问题也在于他的隔离性无法被突破,导致应用间上下文无法被共享,随之带来的开发体验、产品体验的问题。
(2)
- url 不同步。浏览器刷新 iframe url 状态丢失、后退前进按钮无法使用。
- UI 不同步,DOM 结构不共享。想象一下屏幕右下角 1/4 的 iframe 里来一个带遮罩层的弹框,同时我们要求这个弹框要浏览器居中显示,还要浏览器 resize 时自动居中…
- 全局上下文完全隔离,内存变量不共享。iframe 内外系统的通信、数据同步等需求,主应用的 cookie 要透传到根域名都不同的子应用中实现免登效果。
- 慢。每次子应用进入都是一次浏览器上下文重建、资源重新加载的过程。
(3)举例。中信机构线上化pdf协议阅读签署。
使用:
dom拓展性差,监听滚动到底(无法监听,通过ele.contentWindow可以,但兼容性极差)
二、实战
1.singleSPA实战
(1)构建子应用
// main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import singleSpaVue from 'single-spa-vue'
Vue.config.productionTip = false
// 步骤一:
const appOptions = {
el: '#vue', // 挂载到父应用的id为vue的标签中
router,
render: h => h(App)
}
const vueLifeCycle = singleSpaVue({
Vue,
appOptions
})
// 协议接入,定好协议,未来父应用会调用这些方法
export const boostrap = vueLifeCycle.bootstrap
export const mount = vueLifeCycle.mount
export const unmount = vueLifeCycle.unmount
// 步骤二: 父应用加载子应用,将子应用打包成一个个lib给父应用使用
// 步骤三: 细节处理
// 处理公共路径,处理独立加载
(2)子应用配置库打包
// vue.config.js
module.exports = {
configureWebpack: {
output: {
library:'singleVue', // lib名称
libraryTarget:'umd' // 格式
},
devServer: {
port: 10000
}
}
}
(3)主应用搭建
// main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import { registerApplication, start} from 'single-spa'
Vue.config.productionTip = false
async function loadScript(url) {
return new Promise((resolve,reject)=>{
let script = document.createElement('script')
script.src = url
script.onload = resolve
script.onerror = reject
document.head.appendChild(script)
})
}
registerApplication('myVueApp',
async ()=>{
console.log('load')
await loadScript('http://localhost:10000/js/chunk-vendors.js')
await loadScript('http://localhost:10000/js/app.js')
return window.singleVue; // boostrap mount unmount
},
location => location.pathname.startsWith('/vue') // 用户切换到/vue的路径下,需要记载刚才定义的子应用
)
start()
new Vue({
router,
render: h => h(App)
}).$mount('#app')
// 一:注册子应用 registerApplication
// 二:加载子应用文件 loadScript
// 三:细节处理 路由匹配,加载容器
(4)到目前为止的问题总结:
1.基础路径不是以/vue(待处理)
base: '/vue'
2.动态设置子应用的publicPath
window.singleSpaNavigate // 标识
__webpack_public_path__ // 设置值 'http://localhost:10000/'
3.webpack_public_path暂时不能独立运行;(待处理)
new Vue(appOptions).$mount('#app')
4.父子应用css没有隔离;
父应用样式:
子应用加载后样式:
5.不够灵活不能动态加载js文件;
6.没有js沙箱机制,全局变量覆盖;
父:window.a 子:window.a相互覆盖
(5)singleSpa整理流程来一个梳理;
父应用做了什么事:
1.注册子应用
2.引入子应用文件
3.准备容器
4.匹配路由
子应用做了什么事情:
1.引入生态,暴露方法。
export const boostrap = vueLifeCycle.bootstrap
export const mount = vueLifeCycle.mount
export const unmount = vueLifeCycle.unmount
2.子应用配置库打包
module.exports = {
configureWebpack: {
output: {
library:'singleVue',
libraryTarget:'umd'
},
devServer: {
port: 10000
}
}
}
3.基础路径webpack_public_path设置
4.base路径’/vue’设置
5.子应用独立运行
2.qiankun实战
(1)主应用编写
引入,注册,启动
准备容器,匹配路由
主应用做了什么?
(2)子vue应用
接入协议:暴露三个方法(调用方法加载,卸载)
设置打包类库,支持跨域
基础路径
(3)子react应用
接入协议:暴露三个方法(调用方法加载,卸载)
设置打包类库,支持跨域
基础路径
三、css隔离方案
1.子应用之间样式隔离动
乾坤实现的是:动态样式表,当应用切换时移除老样式,添加新应用的样式
2.主应用和子应用之间的样式隔离
约定项目前缀(既然是约定,肯定会有不遵守)
css-modules 打包时生成不冲突的选择器名
shadom dom 处理父子应用真正意义上的隔离
3.shadom dom
<div>
<p>hello world</p>
<div id="shadow"></div>
</div>
<script>
let shadowDOM = document.getElementById('shadow').attachShadow({mode:'closed'})
let pElm = document.createElement('p')
pElm.innerHTML = 'hello china'
let styleElm = document.createElement('style')
styleElm.textContent = `p{color:red}`
shadowDOM.appendChild(styleElm)
shadowDOM.appendChild(pElm)
</script>
4.代码 shadow-dom
四、js沙箱机制(快照沙箱)
1.沙箱是什么:
(1)就是让你的程序跑在一个隔离的环境下,不对外界的其他程序造成影响;
(2)单应用切换时, 沙箱:创造一个干净的环境给子应用使用,当切换时可以选择丢弃和回复属性
2.快照沙箱: 一年前拍一张照片 一年后再拍一张 (将前后对比的区别保存起来) 应用: 将区别应用回到一年前 或者是回复到一年前后再此恢复到当前
3.现象
4.代码sandbox
5.图形理解链路
激活
失活