vite2 接入 qiankun 微前端
关注公众号: 微信搜索 前端工具人
; 收货更多的干货
原文链接: 自己掘金文章 https://juejin.cn/editor/drafts/7078238272064847903
vite
已经大火了, 自从用上了就停不下来` ;
但碍于 vite
初来乍到, 生态不够成熟, 有些功能还是比较尴尬的,比如微前端;
qiankun
微前端搭建详细步骤及常见问题,可参考之前文章 https://juejin.cn/post/6943763969576271879
以下源码也已上传至 github
开篇
去年初项目接入微前端的时候,就准备使用 vite
, 一顿构操作下来,发现 vite
应用一直无法获取生命周期, 才知道那时 qiankun
暂时不支持 vite
应用
大致原因如下:
vite
构建的js
内容必须在type=module
的script
脚本里;- 当时
qiankun
的源码依赖之一import-html-entry
则不支持type=module
这个属性 (目前已支持); qiankun
是通过eval
来执行这些js
的内容,而vite
里面import/export
没有被转码, 所以直接接入会报错:不允许在非type=module
的script
里面使用import
;
在去年年尾的时候,在qiankun
的 issues
中找到了2
种方法;
还是这些大佬牛逼;下面介绍下这2种方法
方法一 (不推荐)
- 结合
rollup/plugin-html
插件; - 修改
Vite.config.js
中的build
配置默认Vite
的输出目标target
是module
,改为esnext
- 详细步骤可参考
https://github.com/umijs/qiankun/issues/1268
缺点:
- 可以实现生产环境接入,开发环境不行;
vite
没有动态publicPath
的支持;所以Vite.config
中base
配置需要写死;vite
code-splitting(
代码分割)功能并不支持iife
和umd
两种格式,导致路由无法懒加载;- 图片资源只会被打包成
base64
,无论图片大小
方法二 (推荐)
vite-plugin-qiankun
插件; github文档
优点
- 保留
vite
构建es
模块的优势 - 一键配置,不影响已有的
vite
配置 - 支持
vite
开发环境
- 安装插件
pnpm add vite-plugin-qiankun
vite.config.ts
配置
// vue3
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import qiankun from 'vite-plugin-qiankun';
import { resolve } from 'path';
export default ({ mode }) => {
const __DEV__ = mode === 'development'
return defineConfig({
alias: {
'@': resolve('src'),
},
server: {
port: 7711,
origin: '//localhost:7711'
},
base: __DEV__ ? '/' : '//localhost:7711',
plugins: [ vue(),
qiankun('sub-vite2-vue3', {
useDevMode: true
})],
})
}
// react
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import qiankun from 'vite-plugin-qiankun';
import reactRefresh from '@vitejs/plugin-react-refresh'
// useDevMode 开启时与热更新插件冲突
const useDevMode = true
export default ({ mode }) => {
const __DEV__ = mode === 'development'
return defineConfig({
server: {
port: 7722,
origin: '//localhost:7722'
},
base: __DEV__ ? '/' : '//localhost:7722',
plugins: [
...(
useDevMode ? [] : [
reactRefresh()
]
),
qiankun('sub-vite2-react', {
useDevMode: true
})
],
})
}
- 导出相应的生命周期
// vue3 main.ts 无关代码自行省略
// @ts-nocheck
import { createApp } from "vue";
import { createRouter, createWebHistory } from "vue-router";
import App from "./App.vue";
import routes from "./router";
import { renderWithQiankun, qiankunWindow } from 'vite-plugin-qiankun/dist/helper';
let router = null;
let instance = null;
renderWithQiankun({
mount(props) {
storeTest(props);
render(props);
instance.config.globalProperties.$onGlobalStateChange =
props.onGlobalStateChange;
instance.config.globalProperties.$setGlobalState = props.setGlobalState;
},
bootstrap() {
console.log("%c ", "color: green;", "sub-vite2-vue3 app bootstraped");
},
unmount(props: any) {
instance.unmount();
instance._container.innerHTML = "";
instance = null;
router = null;
},
});
function render(props = {}) {
const { container } = props;
router = createRouter({
history: createWebHistory(!qiankunWindow.__POWERED_BY_QIANKUN__ ? "/sub-vite2-vue3" : "/"),
routes
});
instance = createApp(App);
instance.use(router);
instance.mount(container ? container.querySelector("#app") : "#app");
}
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
}
});
}
if (!qiankunWindow.__POWERED_BY_QIANKUN__) {
render({});
}
// react main.ts 无关代码自行省略
import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
// vite-plugin-qiankun helper
import { renderWithQiankun, qiankunWindow } from 'vite-plugin-qiankun/dist/helper';
function render(props: any) {
const { container } = props;
ReactDOM.render(
,
container
? container.querySelector("#root")
: document.getElementById("root")
);
}
renderWithQiankun({
mount(props) {
console.log("sub-vite2-react mount");
render(props);
},
bootstrap() {
console.log("bootstrap");
},
unmount(props: any) {
console.log("sub-vite2-react unmount");
const { container } = props;
const mountRoot = container?.querySelector("#root");
ReactDOM.unmountComponentAtNode(
mountRoot || document.querySelector("#root")
);
},
});
if (!qiankunWindow.__POWERED_BY_QIANKUN__) {
render({});
}
如发现子应用图片资源 404
, 控制台报错显示该资源在主应用路劲下;则 vite.config.ts
增加 origin
...
server: {
...
origin: '//localhost:7722'
},
参考资源:
- https://github.com/umijs/qiankun/issues/1257
- https://github.com/tengmaoqing/vite-plugin-qiankun