Vue3.0 + TypeScript 微前端架构落地方案
前言
微前端架构是方便企业级后端管理系统的更加灵活、解耦性高的新型前端架构,至于具体落地配置如下
一、主应用
- 主应用依赖
{
"name": "main-app",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
},
"dependencies": {
"core-js": "^3.6.5",
"qiankun": "^2.4.1",
"vue": "^3.0.0",
"vue-router": "^4.0.0-0"
},
"devDependencies": {
"@typescript-eslint/eslint-plugin": "^4.18.0",
"@typescript-eslint/parser": "^4.18.0",
"@vue/cli-plugin-babel": "~4.5.0",
"@vue/cli-plugin-eslint": "~4.5.0",
"@vue/cli-plugin-router": "~4.5.0",
"@vue/cli-plugin-typescript": "~4.5.0",
"@vue/cli-service": "~4.5.0",
"@vue/compiler-sfc": "^3.0.0",
"@vue/eslint-config-typescript": "^7.0.0",
"eslint": "^6.7.2",
"eslint-plugin-vue": "^7.0.0",
"less": "^3.0.4",
"less-loader": "^5.0.0",
"typescript": "~4.1.5"
}
}
2.主应用main.ts主应用入口
import {createApp} from 'vue'
import App from './App.vue'
import router from './router'
import {registerMicroApps, start ,setDefaultMountApp, runAfterFirstMounted} from 'qiankun';
// 首先创建主应用实例
const app = createApp(App)
// 路由可不注册,即routes可以为空数组 []
app.use(router)
app.mount('#app')
// 主-子应用全部采用vue-router的history模式
// 注册子应用
registerMicroApps(
[
{
name: "qiankun-app-1", // 子应用1
entry: "http://localhost:8082",
container: '#subapp-container', // 容器不限制
activeRule: "/app1" // 子应用路由base
},
{
name: "qiankun-app-2", // 子应用2
entry: "http://localhost:8083",
container: '#subapp-container', // 容器不限制
activeRule: '/app2', // 子应用路由base,
},
]
);
// 第一个子应用加载完毕回调
runAfterFirstMounted(()=>{
console.log("runAfterFirstMounted")
});
// 设置默认挂载应用
setDefaultMountApp("/app1");
// 启动微前端服务
start();
3.主应用App.vue
<template>
<h1>微前端主应用</h1>
<div id="nav">
<router-link to="/app1">子应用1</router-link> |
<router-link to="/app2">子应用2</router-link>
</div>
<div id="subapp-container"></div>
</template>
二、子应用
- 子应用main.ts入口
import './public-path';
import {createApp} from 'vue'
import App from './App.vue'
import router from './router'
let instance = null;
function render(props?: { container: any; }) {
let target = '#app'
if (props) {
target = props.container.querySelector('#app');
}
instance = createApp(App)
instance.use(router)
instance.mount(target)
}
// 独立运行时
if (!window.__POWERED_BY_QIANKUN__) {
render()
}
// 主应用加载微应用时只会执行一次
export async function bootstrap() {
console.log('bootstrap app1 bootstraped');
}
// 子应用被挂载时,即每次path被激活时
export async function mount(props: any) {
console.log('bootstrap app1', props);
render(props);
}
// 子应用被移除时
export async function unmount(props: any) {
console.log(props)
}
- public-path.ts文件
if (window.__POWERED_BY_QIANKUN__) {
// eslint-disable-next-line no-undef
__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}
3.window.d.ts声明(主要解决typescript环境下的ts监测报错问题)
interface Window {
[key: string]: any;
}
4.子应用vue.config.js
const { name } = require('./package');
module.exports = {
devServer: {
headers: {
'Access-Control-Allow-Origin': '*',
},
},
configureWebpack: {
output: {
library: `${name}-[name]`,
libraryTarget: 'umd', // 把微应用打包成 umd 库格式
jsonpFunction: `webpackJsonp_${name}`,
},
},
};