Vue与Qiankun微前端组合
2022-02-17 本文已影响0人
WebGiser
参考:https://blog.csdn.net/qq_42268364/article/details/116127872
https://gitee.com/zhihua0123/qiankun-demo/tree/master
https://blog.csdn.net/weixin_48726650/article/details/106905193
主应用 main-app
创建新项目 main-app
// 创建项目
vue create main-app
// 安装qiankun
npm i qiankun -S

改造项目
1、修改 App.vue
我们要在app.vue中创建一个容器,负责把获取到的子应用加载到这里容器里面
<div id="app">
<div id="nav">
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link> |
<router-link to="/hello-app">hello-app</router-link>
</div>
<router-view />
<!-- id为appContainer就是放置子应用的容器 -->
<div id="appContainer"></div>
</div>
2、新建 arc/qiankun.js文件,引用qiankun并且封装好
import { registerMicroApps, start } from "qiankun";
export const useQiankun = () => {
const apps = [
{
// 必填,微应用的名称,必须保证唯一
name: "hello-app",
// 必填,微应用的入口
entry: "http://localhost:8082",
// 必填,微应用的容器节点的选择器或者Element实例
container: "#appContainer",
// 必填,微应用的激活规则
activeRule: "/hello-app",
// 可填,主应用需要传递给微应用的数据
props: {
msg: "我是main-app传过来的值,传递给hello-app应用。",
},
},
];
registerMicroApps(apps, {
beforeLoad: [
(app) => {
console.log(`${app.name}的beforeLoad阶段`);
},
],
beforeMount: [
(app) => {
console.log(`${app.name}的beforeMount阶段`);
},
],
afterMount: [
(app) => {
console.log(`${app.name}的afterMount阶段`);
},
],
beforeUnmount: [
(app) => {
console.log(`${app.name}的beforeUnmount阶段`);
},
],
afterUnmount: [
(app) => {
console.log(`${app.name}的afterUnmount阶段`);
},
]
})
start({
experimentalStyleIsolation: true,
prefetch: "all",
})
}
3、修改 main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import {useQiankun} from './qiankun'
Vue.config.productionTip = false
const vueApp = new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
vueApp.$nextTick(()=>{
useQiankun()
})
4、修改 src/views/Home.vue
<div class="home">
<h1>main-app的Home页面</h1>
</div>
5、修改 src/views/About.vue
<div class="home">
<h1>main-app的About页面</h1>
</div>
6、新建 vue.config.js
"use strict";
const path = require("path");
function resolve(dir) {
return path.join(__dirname, dir);
}
const port = 8011; // 端口配置
const name = "main-app";
module.exports = {
// hash 模式下可使用
publicPath: process.env.NODE_ENV === "development" ? "/" : "/main-app/",
outputDir: "dist",
assetsDir: "static",
lintOnSave: process.env.NODE_ENV === "development",
productionSourceMap: false,
devServer: {
port: port,
open: false, // 启动项目以后自动打开浏览器
hot: true, // 模块热替换(HMR - hot module replacement)功能会在应用程序运行过程中,替换、添加或删除 模块,而无需重新加载整个页面。主要是通过以下几种方式,来显著加快开发速度
hotOnly: false, // hot 和 hotOnly 的区别是在某些模块不支持热更新的情况下,前者会自动刷新页面,后者不会刷新页面,而是在控制台输出热更新失败
},
configureWebpack: {
// provide the app's title in webpack's name field, so that
// it can be accessed in index.html to inject the correct title.
name: name,
resolve: {
alias: {
"@": resolve("src"),
},
},
},
};
子应用 hello-app
创建新项目 hello-app
// 创建项目
vue create hello-app

改造项目
1、新增 src/public-path.js
if (window.__POWERED_BY_QIANKUN__) {
// eslint-disable-next-line no-undef
__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}
2、修改main.js
在main.js,引入public-path.js 并配合主项目导出single-spa需要的三个生命周期。
注意:路由实例化需要在main.js里面完成,以便于路由的销毁,所以路由文件只需要导出路由配置即可(原模板导出的是路由实例)
import Vue from "vue";
import App from "./App.vue";
import routes from "./router";
import store from "./store";
import "./public-path";
import VueRouter from "vue-router";
let router = null;
let instance = null;
function render({ container, parentStore } = {}) {
router = new VueRouter({
base: window.__POWERED_BY_QIANKUN__
? "/hello-app"
: process.env.BASE_URL,
mode: "history",
routes,
});
instance = new Vue({
router,
store,
data() {
return {
parentStore,
};
},
render: (h) => h(App),
}).$mount(container ? container.querySelector("#hello-app") : "#hello-app");
}
if (!window.__POWERED_BY_QIANKUN__) {
// 全局变量来判断环境
render();
}
export async function bootstrap() {
console.log("现在进入子应用hello-app的bootstraped阶段");
}
/**
* 应用每次进入都会调用 mount 方法,通常我们在这里触发应用的渲染方法
*/
export async function mount(props) {
if (props.parentStore) {
await props.parentStore.dispatch("getResource", {
name: "hello-app应用的资源",
});
}
console.log("现在进入子应用hello-app的mount周期", props);
render(props);
}
/**
* 应用每次 切出/卸载 会调用的方法,通常在这里我们会卸载微应用的应用实例
*/
export async function unmount() {
console.log("现在进入子应用hello-app的unmount阶段");
instance.$destroy();
instance.$el.innerHTML = "";
instance = null;
router = null;
}
/**
* 可选生命周期钩子,仅使用 loadMicroApp 方式加载微应用时生效
*/
export async function update(props) {
console.log("update props", props);
}
3、vue.config.js
"use strict";
const path = require("path");
function resolve(dir) {
return path.join(__dirname, dir);
}
const sysName = "hello-app";
const port = 8082; // 端口配置
const { name } = require("./package");
module.exports = {
publicPath: process.env.NODE_ENV === "development" ? "/" : "/hello-app/",
outputDir: "dist",
assetsDir: "static",
lintOnSave: process.env.NODE_ENV === "development",
productionSourceMap: false,
devServer: {
port: port,
open: false, // 启动项目以后自动打开浏览器
hot: true,
hotOnly: false,
headers: {
"Access-Control-Allow-Origin": "*",
},
},
configureWebpack: {
name: name,
resolve: {
alias: {
"@": resolve("src"),
},
},
output: {
// 把子应用打包成 umd 库格式
library: `${sysName}`, // 微应用的包名,这里与主应用中注册的微应用名称一致
libraryTarget: "umd", // 将你的 library 暴露为所有的模块定义下都可运行的方式
jsonpFunction: `webpackJsonp_${sysName}`, // 按需加载相关,设置为 webpackJsonp_vue-projec 即可
},
}
};
4、修改 src/router/index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'
Vue.use(VueRouter)
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/about',
name: 'About',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
}
]
// const router = new VueRouter({
// mode: 'history',
// base: process.env.BASE_URL,
// routes
// })
// export default router
export default routes
5、修改 src/views/Home.vue
<div class="home">
<h1>hello-app的Home页面</h1>
</div>
6、修改 src/views/About.vue
<div class="home">
<h1>hello-app的About页面</h1>
</div>
7、修改 public/index.html
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="hello-app"></div>
<!-- built files will be auto injected -->
</body>
</html>
测试
分别启动 main-app 和 hello-app 项目,然后访问main-app的
