我个人理解就是,微前端就像一个游戏盒子,每个项目都是独立的游戏,有了这个微前端盒子平台,我可以快速启动任何一个项目,并且还能让项目之间进行联动(传参-通信)。
结构
— main 乾坤主应用
— v2 子应用
— v3 子应用
主应用
main 该项目我采用vue3开发的,实际上主应用可以是原生的,也可以是index.html页面都可以的。
不过这里还是使用相对高级的vue3项目搭建。
- 创建项目
vue create main
- 安装qiankun
npm i qiankun
我的项目中是”qiankun”: “^2.7.3” - src/qk.js 配置我们的乾坤服务
import { registerMicroApps, start, setDefaultMountApp } from "qiankun"; // 子应用的配置 registerMicroApps([ { name: "v3", // 必须唯一 entry: "http://localhost:8080", // 用来匹配子应用程序的 container: "#child", // 指的是子应用渲染在父应用的某个元素上 activeRule: "/v3", // 匹配子应用的基础路由地址 }, { name: "v2", // 必须唯一 entry: "http://localhost:8081", // 用来匹配子应用程序的 container: "#child", // 指的是子应用渲染在父应用的某个元素上 activeRule: "/v2", // 匹配子应用的基础路由地址 }, ]); start(); // 自动打开一个子应用 setDefaultMountApp("/v3/");
- 在main.js中引入qk.js
- 在App.vue中创建div,id值为child,这一步很重要,它是用来渲染子应用的根元素,相当于视图组件。不同的应用可以用不同的元素接收,我这里图省事,全都用一个元素来渲染了。
- App.vue里的代码
<nav> <router-link to="/">主应用首页</router-link> | <router-link to="/about">主应用关于</router-link>| <router-link to="/v3/">子应用首页</router-link>| <router-link to="/v3/about">子应用关于</router-link> </nav> <!-- 这里的router-view只是用来显示主应用的路由组件的 --> <router-view /> <!-- 挂载子应用的容器 --> <div id="child"></div>
vue2子应用
- 创建子项目
vue create v2
- 子项目不需要安装qiankun,只需要配置之后,启动就可以了
- 配置‘vue.config.js’
const { defineConfig } = require("@vue/cli-service"); module.exports = defineConfig({ transpileDependencies: true, devServer: { port: 8081, headers: { "Access-Control-Allow-Origin": "*", }, }, configureWebpack: { output: { library: `v2`, // 这里得值和主应用得名称保持一致 libraryTarget: "umd", // 把微应用打包成 umd 库格式 // jsonpFunction: `webpackJsonp_${name}`, // 新版webpack5不支持此api }, }, });
- 在main.js中编辑如下内容
import Vue from "vue"; import App from "./App.vue"; import router from "./router"; // 这个主要解决的是子应用动态载入的脚本,样式,图片等地址不正确的问题。 if (window.__POWERED_BY_QIANKUN__) { __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__; } let instance = null; function render(props = {}) { const { container } = props; instance = new Vue({ router, render: (h) => h(App), }).$mount(container ? container.querySelector("#app") : "#app"); } // 独立运行项目时 if (!window.__POWERED_BY_QIANKUN__) { render(); } // 如下几个是给乾坤用得生命周期,可以用来子应用间通信等操作 export async function bootstrap() { console.log("[vue] vue app bootstraped"); } export async function mount(props) { console.log("[vue] props from main framework", props); render(props); } export async function unmount() { instance.$destroy(); instance.$el.innerHTML = ""; instance = null; router = null; }
- 子应用的router.js 配置
const router = new VueRouter({ mode: "history", // 如果是在乾坤里运行的话,使用主应用配置的路由, // 否则就是.env.xx 里配置的,默认是 / base: window.__POWERED_BY_QIANKUN__ ? "/v2" : process.env.BASE_URL, routes, }); export default router;
vue3子应用
// 1. vue.config.js
const { defineConfig } = require("@vue/cli-service");
module.exports = defineConfig({
transpileDependencies: true,
devServer: {
headers: {
"Access-Control-Allow-Origin": "*", // 解决了父子应用间的跨域问题
},
},
configureWebpack: {
output: {
library: `v3`,
libraryTarget: "umd", // 把微应用打包成 umd 库格式
// jsonpFunction: `webpackJsonp_${name}`,
},
},
});
// 2. main.js
import { createApp } from "vue";
import App from "./App.vue";
import router from "./router";
if (window.__POWERED_BY_QIANKUN__) {
__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}
let instance = null;
function render(props = {}) {
const { container } = props;
instance = createApp(App)
.use(router)
.mount(container ? container.querySelector("#app") : "#app");
}
// 独立运行时
if (!window.__POWERED_BY_QIANKUN__) {
render();
}
export async function bootstrap() {
console.log("[vue] vue app bootstraped");
}
export async function mount(props) {
console.log("[vue] props from main framework", props);
render(props);
}
export async function unmount() {
instance.$destroy();
instance.$el.innerHTML = "";
instance = null;
router = null;
}
// 3.router.js
const router = createRouter({
history: createWebHistory(
window.__POWERED_BY_QIANKUN__ ? "/v3" : process.env.BASE_URL
),
routes,
});
export default router;
总结
先启动所有的子应用,注意,所有项目的端口号不可以重复。最后启动微前端项目。
运行机制其实很简单,当我们在主应用里使用子应用路由的时候,乾坤会去匹配到子应用路由,并将其加载到主应用的指定dom元素中显示。
但是,每次都手动启动那么多项目,很烦,所以我们可以使用工具,来一次性启动多个项目。
这里我配置在主应用里了。
- 安装 concurrently 目前是”concurrently”: “^7.2.2”
"scripts": { "all": "concurrently \"npm run serve\" \"cd ../v2 && npm run serve\" \"cd ../v3 && npm run serve\"", "serve": "vue-cli-service serve", "build": "vue-cli-service build" },
- 使用’npm run all’ 就可以启动所有项目了