最近在做qiankun项目搭建工作,遇到了一些坑和大家一起分享一下,如有写得不对的或者不好的地方,希望大家指点。这边讲的是在路由页面里面添加子应用容器,任意切换主子应用页面
- 首先创建一个vue3.0的项目
vue create qiankun-app,版本要选择vue3.0作为基座使用,创建项目的时候最好把路由也一并选上 - 在main.js中写入
import { createApp } from 'vue'
import App from './App.vue'
import router from './router';
createApp(App)
.use(router)
.mount('#base-app');
这边要注意的是app.vue和index.html里面的id也要是base-app 3. 在项目根目录下新建vue.config.js,添加内容如下
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true,
devServer: {
// 可以在配置中 配置端口 VUE_APP_PORT = 8080
port: 8080,
headers: {
'Access-Control-Allow-Origin': '*' // 允许跨域访问子应用页面
}
},
})
- 创建子应用
vue create qiankun-vue-child,这边需要使用vue2.0,如何搭建省略 - 添加路由
const router = createRouter({
// 有些时候希望直接启动微应用从而更方便的开发调试,你可以使用这个全局变量来区分当前是否运行在 qiankun 的主应用的上下文中
base: window.__POWERED_BY_QIANKUN__ ? '/vue' : '/',
history: createWebHistory(),
routes
})
这边需要注意的是base对应主应用里面路由激活规则activeRule的路径
7.在main.js中引入路由,内容如下
import { createApp } from 'vue'
import App from './App.vue'
import router from './router`';`
function render (props = {}) {
const { container } = props
createApp(App)
.use(router)
.mount(container ? container.querySelector('#app') : '#app');
// 为了避免根id#app与其他DOM冲突,需要限制查找范围
}
- 在项目根目录下新建vue.config.js,添加内容如下
const { defineConfig } = require('@vue/cli-service')
const packageName = require('./package.json').name;
module.exports = defineConfig({
transpileDependencies: true,
devServer: {
port: 8083, // 重点6
headers: { // 重点7:同重点1,允许子应用跨域
'Access-Control-Allow-Origin': '*'
}
},
configureWebpack: {
output: {
library: `${packageName}-[name]`,
libraryTarget: 'umd', // 把子应用打包成 umd 库格式
// jsonpFunction: `webpackJsonp_${packageName}`
chunkLoadingGlobal: `webpackJsonp_${packageName}`
}
}
})
- 准备好这些之后 在主应用中 安装乾坤
npm i qiankun -S - 在主应用入口文件src/main.js中注册子应用
import { registerMicroApps, start } from 'qiankun'
import { createApp } from 'vue'
import App from './App.vue'
import router from './router';
<!-- import qiankun -->
import { registerMicroApps, start } from 'qiankun'
// 在主应用中注册子应用
registerMicroApps([{
name: 'vue app', // 微应用的名称 要求唯一
entry: '//localhost:8083', // 通俗理解就是(微应用的访问地址)
container: '#vue', // 微应用挂载到主应用上的容器
activeRule: '/vue', // 微应用激活条件
}]
)
createApp(App)
.use(router)
.mount('#base-app');
- 子应用需要在src目录新增
public-path.js,然后在main.js中引入
if (window.__POWERED_BY_QIANKUN__) {
__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__ + 'vue/' // +后面的内容是有配置publicPath的时候需要使用,没有配置可以不用写
}
- 子应用的main.js需要修改为
import { createApp } from 'vue'
import App from './App.vue'
import router from './router';
function render (props = {}) {
const { container } = props
createApp(App)
.use(router)
.mount(container ? container.querySelector('#app') : '#app'); // 为了避免根id#app与其他DOM冲突,需要限制查找范围
}
if (!window.__POWERED_BY_QIANKUN__) {
render()
}
/**
* bootstrap 只会在微应用初始化的时候调用一次,下次微应用重新进入时会直接调用 mount 钩子,不会再重复触发 bootstrap。
* 通常我们可以在这里做一些全局变量的初始化,比如不会在 unmount 阶段被销毁的应用级别的缓存等。
*/
export async function bootstrap() {
console.log('react app bootstraped');
}
/**
* 应用每次进入都会调用 mount 方法,通常我们在这里触发应用的渲染方法
*/
export async function mount(props) {
// ReactDOM.render(<App />, props.container ? props.container.querySelector('#root') : document.getElementById('root'));
console.log('乾坤子应用容器加载完成,开始渲染 child')
console.log('props from main mount', props)
render(props)
}
/**
* 应用每次 切出/卸载 会调用的方法,通常在这里我们会卸载微应用的应用实例
*/
export async function unmount() {
}
/**
* 可选生命周期钩子,仅使用 loadMicroApp 方式加载微应用时生效
*/
export async function update(props) {
console.log('update props', props);
}
13.主应用在需要使用到微应用的组件位置添加容器<div id="vue" /> 对应配置的container,在mounted函数里面启动,代码如下:
onMounted(() => {
if (!window.qiankunStart) {
window.qiankunStart = true;
start({
sandbox: { strictStyleIsolation: true } // 开启沙箱严格模式 防止主应用的样式污染到微应用
});
}
});
- 13点需要注意,有时候多个微应用切换的时候会显示白屏,这时候一定是路由的问题,一定要往路由这边去排查问题
- 微应用内部使用keepalive是可以正常使用的,跨应用的时候keepalive是没有用的,需要保持输入框的内容能够缓存住,可以使用本地缓存的方式,在vue的声明周期函数中去存储和删除。这个是个人的看法,有什么更好的想法欢迎交流。
- 希望大家的qiankun学习没有那么多的坑相伴。