什么是微前端?
要回答这个问题,需要从 why, how, what 三个方面来讲
why:
随着公司业务的膨胀,处理业务的系统数量也跟着膨胀,运营人员处理一单业务需要在各个系统之间来回穿梭。 为了使运营人员在一个系统里可以完成所有操作,技术人员必须给出解决方案。
how:
其实 iframe 在 “微前端” 这个概念被喊出来之前一直是整合系统的利器,但它有些不理想的地方具体原因戳这里 why not iframe,现阶段的前端开发必须找到一种替代方案,优雅的解决掉这些问题。
what:
为了弥补 iframe 方案的不足,让前端开发更方便的把多个业务系统整合到一起,微前端被提出并实现,目前业界使用的方案基本都是基于蚂蚁金服的 qiankun [乾坤], 有天下大一统的味道.
实践前准备
概念: 父应用,子应用
使用 iframe 整合系统时,假设我们有系统 A, 当我们想把系统 B 引入 A 系统时,只需要 B 系统提供一个 url 给 A 系统引用即可,这里我们把 A 系统叫做父应用,把 B 系统叫做子应用。同样的,微前端也延续了这个概念,微前端在使用起来基本和使用 iframe 一样平滑。
乾坤架构图
如图所示,乾坤整合的主要是基于当前主流前端框架 vue, react, agular 实现的系统,jquery 应用支持相地较弱(主要因为大多是多页应用)
整合乾坤
为方便,我们直接使用乾坤提供的 Demo, 请自行 clone 代码库 乾坤demo github
所涉及的项目
父应用
qiankun-base
三个子应用
qiankun-react
qiankun-vue
qiankun-jq
1. 配置 qiankun-base 父应用
1.1 在 main.js 里引入乾坤,配置要被引入的子应用列表,并启动乾坤
// qiankun-base/src/main.js
// 略去不相关代码
import {registerMicroApps, start } from 'qiankun';
// 定义要整合的微应用列表
const apps = [
{
name: 'vueApp', // 应用的名字
entry: 'http://localhost:10000/', // 默认加载这个html,解析里面的js动态的执行(子应用必须支持跨域,内部使用的是 fetch)
container: '#vue', // 要渲染到的容器名id
activeRule: '/vue' // 通过哪一个路由来激活
},
{
name: 'reactApp',
entry: 'http://localhost:20000/',
container: '#react',
activeRule: '/react'
},
{
name: 'jqApp',
entry: 'http://localhost:5501/qiankun/qiankun-jq/',
container: '#jq',
activeRule: '/jq',
props: { a: 1 } // 父应用向子应用传递参数
}
];
// 注册应用
registerMicroApps(apps);
// 开启应用
start();
// 正常挂载 vue
new Vue({
router,
render: h => h(App)
}).$mount('#app')
1.2 在 App.vue 里预留 dom 节点,等待子应用被加载并插入
<!-- qiankun-base/src/App.vue -->
<template>
<div>
<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 id="vue"></div>
<div id="react"></div>
</div>
</template>
2. 分别在三个子应用里做处理,准备被 qiankun-base 父应用引用
根据 qiankun 的协议需要导出 bootstrap/mount/unmount 三个引用生命周期钩子函数用于父应用加载子应用时执行,另外父应用会在 window 上添加 POWERED_BY_QIANKUN 属性用于子应用区分当前是否被父应用加载,还是单独加载。所有子应用就围绕 钩子函数 和 属性 做相应配置, 各技术技术栈下处理方式一致
2.1 配置 vue 子应用
// qiankun-vue/src/main.js
// 略去不相关代码
let instance = null;
function render(props) {
// props 组件通信
instance = new Vue({
router,
render: h => h(App)
}).$mount('#app') // 这里是挂载到自己的HTML中,基座会拿到这个挂载后的HTML,将其插入进去
}
if (!window.__POWERED_BY_QIANKUN__) { // 如果是独立运行,则手动调用渲染
render();
}
if(window.__POWERED_BY_QIANKUN__){ // 如果是qiankun使用到了,则会动态注入路径
__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}
// 根据 qiankun 的协议需要导出 bootstrap/mount/unmount
export async function bootstrap(props) {
};
export async function mount(props) {
render(props);
};
export async function unmount(props) { // 卸载时销毁应用
instance.$destroy();
};
// 配置打包 vue.config.js
module.exports = {
devServer: {
port: 10000,
headers:{
'Access-Control-Allow-Origin': '*' // 允许跨域
}
},
configureWebpack: {
output: {
library: 'vueApp',
libraryTarget: 'umd'
}
}
};
2.2 配置 react 子应用
// qiankun-react/src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
function render(){
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
}
if(!window.__POWERED_BY_QIANKUN__){
render();
}
export async function bootstrap(){
}
export async function mount() {
render()
}
export async function unmount(){
ReactDOM.unmountComponentAtNode( document.getElementById('root'));
}
// 配置启动 config-overrides.js
module.exports = {
webpack:(config)=>{
config.output.library = 'reactApp';
config.output.libraryTarget = 'umd';
config.output.publicPath = 'http://localhost:20000/';
return config;
},
devServer:(configFunction)=>{
return function (proxy,allowedHost){
const config = configFunction(proxy,allowedHost);
config.headers = {
"Access-Control-Allow-Origin":'*'
}
return config
}
}
}
2.3 关于 webpack 的 config 文件说明
注意:config 文件主要改动有两个地方,vue 和 react 子应用一样
1:"Access-Control-Allow-Origin":'*' 作用:由于子应用被父应用 fetch 加载,需要允许跨域
2:output.libraryTarget: 'umd'; 作用:使用 umd 让被webpack打包出来的文件在加载时兼容性更强
2.4 配置 jquery 子应用
注意,微应用一般整合的项目技术栈是基于 vue/react/angular 这种单页应用,而jquery应用一般是多页应用, 这里整合进来的只是一个页面,如果有多个页面的jquery应用不太适合使用乾坤整合,直接用 iframe 引入比较合适
// qiankun-jq/js/example.js
const render = ($) => {
$('#example').html("Hello, render with jQuery");
return Promise.resolve();
}
(global => {
global['purehtml'] = {
bootstrap: () => {
console.log('purehtml bootstrap');
return Promise.resolve();
},
mount: (prop) => {
console.log('purehtml mount', prop);
return render($);
},
unmount: () => {
console.log('purehtml unmount');
return Promise.resolve();
},
};
})(window);
if (!window.__POWERED_BY_QIANKUN__) { // 如果是独立运行,则手动调用渲染
render($);
}
3. 启动
分别进入 qiankun-base, qiankun-vue, qiankun-react 启动应用,在父应用里查看即可
注意,jquery 子应用如果想启动需要把它丢到 nginx 服务下
参考: