微前端架构思想:把多个不同的功能按照不同的纬度拆分成多个子应用,通过主应用来加载不同的子应用,微前端的核心在于拆完了合,合完了拆。
使用原因
不同团队间开发同一个应用技术栈不同怎么破?
希望每个团队都可以独立开发,独立部署怎么破?
项目中还需要老的应用代码怎么破?
我们是不是可以将一个应用划分成若干个子应用,将子应用打包成一个个的lib。当路径切换
时加载不同的子应用。这样每个子应用都是独立的,技术栈也不用做限制了!从而解决了前
端协同开发问题
应用通信方式:
基于URL来进行数据传递,但是传递消息能力弱
基于CustomEvent实现通信
基于props主子应用通信
使用全局变量,redux进行通信
qiankun实践:
<el-menu :router="true" mode="horizontal"> <el-menu-item index="/">首页</el-menu-item> <el-menu-item index="/vue">vue应用</el-menu-item> <el-menu-item index="/react">react应用</el-menu-item> </el-menu> <router-view v-show="$route.name"></router-view> <div v-show="!$route.name" id="vue"></div> <div v-show="!$route.name" id="react"></div>
注册子应用
import {registerMicroApps,start} from 'qiankun' const apps = [ { name:'vueApp', entry:'//localhost:10000',container:'#vue', activeRule:'/vue' },{ name:'reactApp', entry:'//localhost:20000', container:'#react', activeRule:'/react' } ]registerMicroApps(apps); start();
子Vue应用
let instance = null; function render(){ instance = new Vue({ router, render: h => h(App) }).$mount('#app') }if(window.__POWERED_BY_QIANKUN__){ __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__; }if(!window.__POWERED_BY_QIANKUN__){render()} export async function bootstrap(){} export async function mount(props){render();} export async function unmount(){instance.$destroy();}
打包配置
module.exports = { devServer:{ port:10000, headers:{ 'Access-Control-Allow-Origin':'*' } },configureWebpack:{ output:{ library:'vueApp', libraryTarget:'umd'
} } }
React路由配置
import { BrowserRouter, Route, Link } from "react-router-dom" const BASE_NAME = window.__POWERED_BY_QIANKUN__ ? "/react" : ""; function App() { return ( <BrowserRouter basename={BASE_NAME}> <Link to="/">首页</Link> <Link to="/about">关于</Link> <Route path="/" exact render={() => <h1>hello home</h1>}></Route> <Route path="/about" render={() => <h1>hello about</h1>}></Route> </BrowserRouter> ); }
CSS 隔离方案
let shadowDom = shadow.attachShadow({ mode: 'open' });
let pElement = document.createElement('p');
pElement.innerHTML = 'hello world';
let styleElement = document.createElement('style');
styleElement.textContent = `
p{color:red}
`
shadowDom.appendChild(pElement);
shadowDom.appendChild(styleElement)
js隔离方案
沙箱机制-Proxy 代理沙箱
class ProxySandbox { constructor() { const rawWindow = window; const fakeWindow = {} const proxy = new Proxy(fakeWindow, { set(target, p, value) { target[p] = value; return true },get(target, p) { return target[p] || rawWindow[p]; } });
let sandbox1 = new ProxySandbox(); let sandbox2 = new ProxySandbox(); window.a = 1; ((window) => { window.a = 'hello'; console.log(window.a) })(sandbox1.proxy); ((window) => { window.a = 'world';console.log(window.a) })(sandbox2.proxy);
每个应用都创建一个proxy来代理window,好处是每个应用都是相对独立,不需要直接更
改全局window属性!