vue3+vite改造子系统
更新时间: 2023-03-07 13:36:47
公司的新项目需要能够单独运行,也能够作为子系统接入公司的主系统中,但是vue2我写得有点烦了,所以新项目决定采用vue3+ts+vite+pinia+element-plus。
# 遇到问题
改造成子系统的过程中遇到了问题
开发模式下,如果我们使用vite来构建vue3子应用,基于vite的构建机制,会在子应用的html的入口文件script标签携带type=module。而我们知道qiankun父应用直接引入子应用,本质上是将html作为入口文件,并通过import-html-entry这个库去加载子应用所需要的资源列表js,css,然后通过eval直接执行,而基于vite构建的js中import、export并没有被转码,会导致直接报错(不允许在非type=module的script里面使用import)
生产模式下,因为没有webpack中支持运行时publicPath,也就是__webpack_public_path__,换句话说就是vite不支持运行时publicPath,其主要作用是用来解决微应用动态载入的脚本,样式,图片等地址不正确的问题。
# 改造子应用
- 安装vite-plugin-qiankun插件
npm install vite-plugin-qiankun
1
- 修改 vite.config.ts
import { defineConfig, loadEnv } from 'vite'
import vue from '@vitejs/plugin-vue'
import qiankun from 'vite-plugin-qiankun'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver,AntDesignVueResolver } from 'unplugin-vue-components/resolvers'
import path from 'path'
import {name} from './package.json'
// useDevMode 开启时与热更新插件冲突
const useDevMode = true // 如果是在主应用中加载子应用vite,必须打开这个,否则vite加载不成功, 单独运行没影响
export default defineConfig(({ mode }) => {
const root = process.cwd() // process.cwd()返回当前工作目录
const env = loadEnv(mode, root)
let config = {
base: env.VITE_BASE_API,
plugins: [
vue(),
//下面这俩插件是注册element-plus的
AutoImport({
resolvers: [ElementPlusResolver()],
}),
Components({
resolvers: [ElementPlusResolver()],
}),
// 微应用名字,与主应用注册的微应用名字保持一致
qiankun(name, { useDevMode })
],
resolve: {
alias: {
'@': path.resolve(__dirname,'./src')
}
},
output: {
// 把子应用打包成 umd 库格式
library: `${name}-[name]`,
libraryTarget: 'umd',
jsonpFunction: `webpackJsonp_${name}`
}
}
return config
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
- 修改main.ts
import { createApp,App } from 'vue'
import MyApp from './App.vue'
import {initRouter} from './router'
import { initStore } from './store'
import {initPromission} from "@/permission";
import {initComponent} from '@/components/publicComponents'
import {
renderWithQiankun,
qiankunWindow
} from 'vite-plugin-qiankun/dist/helper'
let instance:App<Element>|null = null
declare global {
interface Window {
__POWERED_BY_QIANKUN__: any
__INJECTED_PUBLIC_PATH_BY_QIANKUN__: any
}
}
function render(props = {}) {
instance = createApp(MyApp)
initRouter(instance)
initPromission(instance)
initComponent(instance)
// 初始化vuex
initStore(instance)
instance.mount('#app')
if (qiankunWindow.__POWERED_BY_QIANKUN__) {
console.log('我正在作为子应用运行')
}
}
renderWithQiankun({
mount(props) {
console.log('viteapp mount')
render(props)
},
bootstrap() {
console.log('bootstrap')
},
update(){
console.log('哎呀更新了')
},
unmount(props) {
console.log('vite被卸载了')
instance.unmount()
instance = null
}
})
if (!qiankunWindow.__POWERED_BY_QIANKUN__) {
render({})
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
需要注意的是,判断是否是作为子应用运行,使用的是qiankunWindow.__POWERED_BY_QIANKUN__
,生命周期mount
、bootstrap
、update
,unmount
等通过插件函数renderWithQiankun
在其中暴露完成。其他配置与基于webpack构建的子应用相同。
- 改造router.ts
import { App } from 'vue'
import { createRouter, createWebHashHistory, RouteRecordRaw } from 'vue-router'
import {qiankunWindow} from "vite-plugin-qiankun/dist/helper";
import {name} from '../../package.json'
let history = createWebHashHistory()
// 判断是 qiankun 环境则增加路由前缀
let prefix = ''
if(qiankunWindow.__POWERED_BY_QIANKUN__){
prefix = '/'+name
}
let routes:RouteRecordRaw[] = [
{
path:prefix + '/login',
name:'登录',
component: () => import('@/views/login/login.vue')
},
{
path:prefix + '/homepage',
name:'首页',
component: () => import('@/views/index/index.vue')
}
]
export const router = createRouter({
history,
routes
})
export const initRouter = (app: App<Element>)=>{
app.use(router)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
暂时就只踩到这些坑了,项目还没写完,到这里已经可以正常的在主系统里接入了,后面遇到新坑再来更新~