前端微服务-qiankun结合Vue3的使用
安装qiankun
$ yarn add qiankun # 或者 npm i qiankun -S
创建基座项目,并在基座项目中引入qiankun
这里我们基座项目使用的是vue项目,版本为[email protected],具体创建项目教程请参考创建vue,项目目录结构如下:
|-- qiankun|-- .DS_Store|-- .browserslistrc|-- .eslintrc.js|-- .gitignore|-- README.md|-- babel.config.js|-- package-lock.json|-- package.json|-- public| |-- favicon.ico| |-- index.html|-- src|-- .DS_Store|-- App.vue|-- main.js|-- assets| |-- logo.png|-- components| |-- HelloWorld.vue|-- router| |-- index.js|-- views|-- About.vue|-- Home.vue
创建两个子应用,分别为Vue项目和React项目
vue目录结构:
|-- .DS_Store|-- .browserslistrc|-- .eslintrc.js|-- .gitignore|-- README.md|-- babel.config.js|-- package-lock.json|-- package.json|-- vue.config.js|-- public| |-- favicon.ico| |-- index.html|-- src|-- App.vue|-- main.js|-- assets| |-- logo.png|-- components| |-- HelloWorld.vue|-- router| |-- index.js|-- views|-- About.vue|-- Home.vue
react目录结构,react项目创建请参考创建react
|-- .DS_Store|-- .eslintrc.js|-- .gitignore|-- README.md|-- config-overrides.js|-- package-lock.json|-- package.json|-- yarn.lock|-- public| |-- favicon.ico| |-- index.html| |-- logo192.png| |-- logo512.png| |-- manifest.json| |-- robots.txt|-- src|-- App.css|-- App.js|-- App.test.js|-- index.css|-- index.js|-- logo.svg|-- reportWebVitals.js|-- setupTests.js
-
在基座项目中引入
qiankun,修改main.js文件import { registerMicroApps, start } from "qiankun";const apps = [{name: 'vueApp',entry: '//localhost:8081', // 默认会加载这个html,解析里面的js,动态执行(子应用必须支持跨域)container: '#vue',activeRule: '/vue',props: { a: 1 }},{name: 'reactApp',entry: "//localhost:3000",container: "#react",activeRule: '/react'}]registerMicroApps(apps);start({// sandbox: { experimentalStyleIsolation: true } //沙箱默认开启})createApp(App).use(ElementPlus).use(router).mount('#appBase')registerMicroApps的相关入参请参考入参,其中: -
container是针对微应用挂载的节点, -
-
activeRule微应用的激活规则,当配置为字符串时会直接跟 url 中的路径部分做前缀匹配,匹配成功表明当前应用会被激活。所以我们需要在基座项目中修改
App.vue,在该项目中增加微应用的挂载节点,修改如下: -
子应用修改
我们需要根据协议,在子应用的入口文件中导出三个生命周期函数,以供主应用在适当的时机调用:
/*** 只会在微应用初始化的时候调用一次,下次微应用重新进入时会直接调用 mount 钩子,不会再重复触发 bootstrap*/export async function bootstrap() { }/*** 应用每次进入都会调用 mount 方法,通常我们在这里触发应用的渲染方法* @param {*} props*/export async function mount(props) {console.log(props);}/*** 应用每次 切出/卸载 会调用的方法,通常在这里我们会卸载微应用的应用实例* @param {*} props*/export async function unmount(props) {console.log(app);}为了能让子应用也可独立运行,我们可以根据
qiankun在全局注册一个变量window.__POWERED_BY_QIANKUN__,来区分子应用是否运行在qiankun中:// vueimport { createApp } from 'vue'import App from './App.vue'import router from './router'let app = nullfunction render(props) {app = createApp(App).use(router) //挂载到自己的html.基座会拿到挂载后的html,直接插入app.mount('#app')}if (window.__POWERED_BY_QIANKUN__) { // 动态添加publicPath__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;}if (!window.__POWERED_BY_QIANKUN__) { //render()}// 子组件的协议/*** 只会在微应用初始化的时候调用一次,下次微应用重新进入时会直接调用 mount 钩子,不会再重复触发 bootstrap*/export async function bootstrap() { }/*** 应用每次进入都会调用 mount 方法,通常我们在这里触发应用的渲染方法* @param {*} props*/export async function mount(props) {console.log(props);render(props)}/*** 应用每次 切出/卸载 会调用的方法,通常在这里我们会卸载微应用的应用实例* @param {*} props*/export async function unmount(props) {console.log(app);app.unmount() // 卸载}// reactimport 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__) { // 动态添加publicPath__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;}if (!window.__POWERED_BY_QIANKUN__) {render()}export async function bootstrap() { };export async function mount() {render()};export async function unmount() {ReactDOM.unmountComponentAtNode(document.getElementById('root'))}; -
子应用配置修改
<template><div id="nav"><el-menu class="el-menu-demo" :router="true" mode="horizontal"><el-menu-item index="/">Home</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 /><div id="vue"></div><div id="react"></div></div></template>
-
//vue vue.config.jsmodule.exports = {devServer: {headers: {'Access-Control-Allow-Origin': '*' //支持跨域}},configureWebpack: {output: {library: 'vueApp',libraryTarget: 'umd',}},publicPath: 'http://localhost:8081/'}// react config-overrides.jsmodule.exports = {webpack: (config) => {config.output.library = 'reactApp';config.output.libraryTarget = 'umd';config.output.publicPath = 'http://localhost:3000/' // 静态资源路径return config},devServer: (configFunction) => {return function (proxy, allowedHost) {const config = configFunction(proxy, allowedHost);config.headers = {"Access-Control-Allow-Origin": "*"}return config}}}
