前言
用 vue3 官方脚手架创建出来的工程是基于 vite
的。vite
和webpack
是有差别的,vite
的开发时运用了浏览器支持原生的 es6 语法点的优势,但是这种优势对于接入 qiankun
是有问题的。qiankun
是使用 import-entry-html
进行 html 的获取和解析,并通过 eval + with
执行入口文件拿到生命周期,在执行时原生的 import A from 'A.js'
语法会报错。
因此其实 vue3 接入 qiankun 的问题并不在 vue3 ,而在于 vite。
针对这个问题,开源社区有人开发了 vite-plugin-qiankun
插件可以让 vite 工程接入 qiankun,这里就是使用该插件实现的接入。
安装插件并使用
npm i vite-plugin-qiankun
// vite.config.ts
import { defineConfig } from 'vite'
import qiankun from 'vite-plugin-qiankun';
const useDevMode = true
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
qiankun('vue3-app1', {
useDevMode
})
]
})
导出生命周期
import { renderWithQiankun, qiankunWindow } from 'vite-plugin-qiankun/dist/helper';
let app: any = null
function render(props: any) {
const { container } = props;
app = createApp(App)
app.use(createPinia())
app.use(router)
app.mount(container ? container.querySelector('#app') : '#app');
}
renderWithQiankun({
mount(props) {
console.log('mount');
render(props);
},
bootstrap() {
console.log('bootstrap');
},
unmount(props: any) {
console.log('unmount');
app.unmount();
app = null;
},
update() {
}
});
if (!qiankunWindow.__POWERED_BY_QIANKUN__) {
render({});
}
设置路由 base
import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue'
import { qiankunWindow } from 'vite-plugin-qiankun/dist/helper';
const router = createRouter({
// 路由 base
history: createWebHistory(qiankunWindow.__POWERED_BY_QIANKUN__ ? "/app1" : import.meta.env.BASE_URL),
routes: [
{
path: '/',
name: 'home',
component: HomeView
}
]
})
export default router
配置 vite
资源路径问题
qiankun 在加载子应用的资源的时候由于子应用资源是 /xx/x
这样的路径,会自动拼接主应用的域名导致资源加载 404。qiankun 有提供一个运行时的变量 window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__
,该值为加载的子应用的域名地址。修改打包工具的资源动态 base 即可。
但是 vite 没有提供动态配置 base 的功能。
export default defineConfig({
server: {
origin: 'http://localhost:5173/', // 开发环境的资源完整域名前缀
},
base: "http://localhost:5173/" // 完整域名路径只在生产环境生效
})
js / css 没有隔离的问题
vite-plugin-qiankun
插件的原理是将入口文件改成了 import()
函数的方式。因此 js 的 eval + with
建立沙箱失效,导致在开发环境 js 没有隔离,js 没有隔离导致 css 的 style 的 appendChild 拦截失效,css 隔离也失效。
但是生产环境下,js / css 隔离还是生效的。