2022年了,我还在研究qiankun,都被用烂了。看到招聘要求上一栏写着会qiankun,我默默的学起来。这里主应用和子应用都是用vue-cli4X框架,期间遇到了一些坑也都解决
2022年了,我还在研究qiankun,都被用烂了。看到招聘要求上一栏写着会qiankun,我默默的学起来。
这里主应用和子应用都是用vue-cli4X框架,期间遇到了一些坑也都解决了。
第一步安装qiankun
yarn add qiankun # 或者 npm i qiankun -S
main为主应用,sub-app1,sub-app2为微应用,如下图。
第二步,在主应用入口文件注册微应用
/qiankun-vue/main/main.js
import './public-path.js' import { createApp } from 'vue' import router from './router' import store from './store' import App from './App.vue' const app = createApp(App); app.use(store) app.use(router) app.mount('#app') function genActiveRule(routerPrefix) { return location => location.pathname.startsWith(routerPrefix); } import { registerMicroApps, start } from 'qiankun'; registerMicroApps([ { name: 'sub-app1', entry: '//localhost:3012', // 运行微应用的地址 container: '#container', // 展示的DOM容器 id activeRule: genActiveRule('/sub-app1'), // 跳转路径 },{ name: 'sub-app2', entry: '//localhost:3013', container: '#container', activeRule: genActiveRule('/sub-app2'), }, ], { beforeLoad: [ app => { console.log('before load', app); }, ], beforeMount: [ app => { console.log('before mount', app); }, ], afterMount: [ app => { console.log('after mount', app); }, ], afterUnmount: [ app => { console.log('after unload', app); // app.render({appContent: '', loading: false}); }, ], } ); // 启动 qiankun start();
第三步,配置主应用路由
/qiankun-vue/main/...router/index.js
import { createRouter,createWebHistory } from 'vue-router'; const Home = () => import(/*WebpackChunkName*/'@/views/Home.vue') const About = () => import(/*WebpackChunkName*/'@/views/About.vue') const routes = [ {path:'/',name:'home',component: Home}, {path:'/about',name:'about',component: About}, {path:'/sub:catchAll(.*)',name:'Child',component:()=>import(/*webpackChunkName:'Empty.vue'*/'@/views/Empty.vue')} //这里遇到一个坑,就是找不到/sub-app1 /sub-app2路由路径,我就在此设置默认路径
]; const router = createRouter({ history: createWebHistory(), routes, }) export default router
/qiankun-vue/main/App.vue
Home | About | sub-app1 | sub-app2
第四步,就需要在微应用上做对接了,只在主应用上配置了,微应用不配置也跑不起来
/qiankun-vue/sub-app1/main.js
import './public-path.js' import { createApp } from 'vue' import App from './App.vue' import routes from './router' import { createRouter, createWebHistory } from 'vue-router'; import store from './store' let router = null; let instance = null; let history = null; function render(props = {}) { const { container } = props; history = createWebHistory(window.__POWERED_BY_QIANKUN__ ? '/sub-app1' : '/'); router = createRouter({ history, routes: routes, }); instance = createApp(App); instance.use(router); instance.use(store); instance.mount(container ? container.querySelector('#app') : '#app'); } if (!window.__POWERED_BY_QIANKUN__) { render(); } export async function bootstrap() { console.log('%c%s', 'color: green;', 'vue3.0 app bootstraped'); } function storeTest(props) { props.onGlobalStateChange && props.onGlobalStateChange( (value, prev) => console.log(`[onGlobalStateChange - ${props.name}]:`, value, prev), true, ); props.setGlobalState && props.setGlobalState({ }); } export async function mount(props) { storeTest(props); render(props); instance.config.globalProperties.$OnGlobalStateChange= props.onGlobalStateChange; instance.config.globalProperties.$setGlobalState = props.setGlobalState; } export async function unmount() { instance.unmount(); instance._container.innerHTML = ''; instance = null; router = null; history.destroy(); }
在/sub-app1根目录下新建一个public-path.js文件
if (window.__POWERED_BY_QIANKUN__) { __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__; }
然后配置vue.config.js
const { defineConfig } = require('@vue/cli-service') const path = require('path') const packageName = require('./package').name; function resolve(dir){ return path.join(__dirname,dir) } module.exports = defineConfig({ transpileDependencies: true, lintOnSave:false, publicPath: '//localhost:3012', devServer:{ port:3012, client:{ overlay: { warnings: false, errors: true }, }, headers: { 'Access-Control-Allow-Origin': '*', }, }, configureWebpack: { resolve: { alias: { '@': resolve('src') } }, output: { library: `sub-app1`, libraryTarget: 'umd', // 把微应用打包成 umd 库格式 chunkLoadingGlobal: `webpackJsonp_${packageName}`, }, } })
第五步配置sub-app2的微任务
/sub-app2/main.js
import './public-path.js'
import { createApp } from 'vue'
import App from './App.vue'
import routes from './router'
import { createRouter, createWebHistory } from 'vue-router';
import store from './store'
let router = null;
let instance = null;
let history = null;
function render(props = {}) {
const { container } = props;
history = createWebHistory(window.__POWERED_BY_QIANKUN__ ? '/sub-app2' : '/');
router = createRouter({
history,
routes: routes,
});
instance = createApp(App);
instance.use(router);
instance.use(store);
instance.mount(container ? container.querySelector('#app') : '#app');
}
if (!window.__POWERED_BY_QIANKUN__) {
render();
}
export async function bootstrap() {
console.log('%c%s', 'color: green;', 'sub-app2 page');
}
function storeTest(props) {
props.onGlobalStateChange &&
props.onGlobalStateChange(
(value, prev) => console.log(`[onGlobalStateChange - ${props.name}]:`, value, prev),
true,
);
props.setGlobalState &&
props.setGlobalState({
ignore: props.name,
user: {
name: props.name,
},
});
}
export async function mount(props) {
storeTest(props);
render(props);
instance.config.globalProperties.$OnGlobalStateChange= props.onGlobalStateChange;
instance.config.globalProperties.$setGlobalState = props.setGlobalState;
}
export async function unmount() {
instance.unmount();
instance._container.innerHTML = '';
instance = null;
router = null;
history.destroy();
}
新键public-path.js,同sub-app1方法一样,再重复一次,我直接放代码了。
vue.config.js
const { defineConfig } = require('@vue/cli-service') const path = require('path') const packageName = require('./package').name; function resolve(dir){ return path.join(__dirname,dir) } module.exports = defineConfig({ transpileDependencies: true, lintOnSave:false, publicPath: '//localhost:3013', devServer:{ port:3013, client:{ overlay: { warnings: false, errors: true }, }, headers: { 'Access-Control-Allow-Origin': '*', }, }, configureWebpack: { resolve: { alias: { '@': resolve('src') } }, output: { library: `sub-app2`, libraryTarget: 'umd', // 把微应用打包成 umd 库格式 chunkLoadingGlobal: `webpackJsonp_${packageName}`, }, } })
最后就可以跑起来啦