整合qiankun微前端框架心得笔记
本文主要讲整合思路和一些心得小结,而不仅仅是简单地讲操作步骤。然后列出一些要点,帮大家避坑。
建议最好先看qiankun官网对qiankun有一点了解再看本文,或者官网文档结合本文一起看。
接入qiankun框架前需要准备的工作
使用qiankun框架一般是用来整合PC端后台管理系统。在整合这些后台系统之前,你需要考虑和准备以下事情:
- 新开一个简单的项目作为主应用:主应用是用来放统一登录的页面,和各子应用入口的一个页面。首先是需要一个新项目做为qiankun框架的主应用,在其次是考虑到权限问题,不能拿任一子应用作为主应用入口,然后也方便开发和维护。
- 整合后系统登录方式:使用单点登录还是什么方式,这个需要根据自己的项目情况和项目需求决定。不做统一登录的话,整合起来后各个子系统还需要各自登录。
- 整合后服务器端部署方案:整合前可能几个项目部署在不同服务器,整合后需要考虑是不是放在同一台服务器。
- 路由的history模式最好统一:本文几个子系统的history模式统一使用的
history
。
整合前主要是考虑和准备好这几点,可以在整合过程中少走弯路。这每一点又涉及到很多细节,需要在整合开发的过程去解决,比如子应用跟主应用的通信、构建打包等问题,需要看官方文档,然后根据自己项目现状去修改调整。
整合前后的变化
事项 | 整合前 | 整合后 |
---|---|---|
用户信息 | 各子系统各自获取 | 主应用统一获取 |
登录退出 | 各子系统单独登录退出 | 主应用统一登录退出 |
服务器部署 | 部署在不同服务器,简单配置nginx | 考虑是否部署在一台服务器,统一配置nginx |
| history模式 | 有的hash,有的history | 统一使用history(建议) |
整合过程需要处理的疑难问题
把网上qiankun配置好的demo下载下来运行起来,感觉比较简单比较好配置,但是在现有项目上修改配置会发现完全不一样。以下是一些需要注意的事项:
- vite配置修改:应该是这些配置工作里最麻烦最需要仔细的,vite的qiankun全局变量名跟webpack的是不一样的。
- 路由配置修改:现有项目的路由守卫里面涉及到重定向页面的,在调通qiankun前可以暂时注释掉,不然会造成主应用页面白屏,子系统页面加载不出来。
- 生命周期:按照qiankun官网的文档,给每个子应用添加生命周期,记得要销毁。
- 应用通信:主应用登录完下发token给子应用,子应用超时需要通知主应用,以及子应用加载完成通知主应用等等,都需要主应用和子应用通信,按照官网文档使用。
- 碰到问题可以多看看官网的 常见问题 ,部署相关多看入门教程,不少问题最终都是根据官网文档解决的。
Vite2+Vue3主应用配置要点
main.js
里的配置基本上按照官网文档来就好:
import { initGlobalState } from 'qiankun'
import storage from 'store'
import { ACCESS_TOKEN } from '@/store/mutation-types'
import { registerMicroApps, start } from 'qiankun'
const initialState = {
// 这里可以写初始化数据
project_id: '项目5',
token: storage.get(ACCESS_TOKEN)||'',
spinning: false
}
const actions = initGlobalState(initialState) //初始化state
// 监听actions全局公共状态数据的变化
actions.onGlobalStateChange((state, prevState) => {
console.log("主应用变更前:", prevState);
console.log("主应用变更后:", state);
})
function loader(loading) {
console.log('loading',loading)
if(loading){
actions.setGlobalState({ spinning: loading });
}
}
registerMicroApps([
{
name: 'app-aaa', // 与子应用打包配置里的一致
entry: import.meta.env.DEV ? '//localhost:7100' : '/subapp/aaa/', //本地开发是localhost,部署到测试和生产环境是用后面的
container: '#appContainer',
activeRule: '/app-aaa',
props: { actions }, //向子应用传递创建的全局状态
loader
},
{
name: 'app-bbb', // 与子应用打包配置里的一致
entry: import.meta.env.DEV ? '//localhost:7200' : '/subapp/bbb/', //本地开发是localhost,部署到测试和生产环境是用后面的
container: '#appContainer',
activeRule: '/app-bbb',
props: { actions }, //向子应用传递创建的全局状态
loader
}
])
start()
主应用配置要点:
- 在主应用里初始化应用和初始化通信;
- 测试环境
entry
名字,不能和activeRule
一样,否则主应用页面刷新就变成微应用,官网有强调; - 测试环境
entry
名字,是跟子应用构建里面的publicPath
或者assetsPublicPath
一致的,这里划重点; activeRule
就是浏览器地址栏里的后半截路径;- 如果主应用是
vite2+vue3
应用,vite配置文件不需要
额外加output那些打包成umd的配置,不需要
,加了打包会报错; - 要把所有子应用里的
proxy
接口代理,拷到主应用里面,这样才能在主应用里访问到子应用里的接口。
Vite2+Vue3子应用配置要点
vite.config.ts
文件需要增加的内容:
import qiankun from "vite-plugin-qiankun";
export default defineConfig({
base: "/subapp/aaa/", // 与主应用里面测试环境的entry一致
headers: {
// 允许跨域访问
"Access-Control-Allow-Origin": "*"
},
port: 7100, // 与主应用里注册的开发环境entry一致
output: {
// 把子应用打包成 umd 库格式
library: `${name}-[name]`, // 我这里library名字跟package.json里的name不一样,也是可以的
libraryTarget: "umd", // 重点,子应用要打包成umd格式
jsonpFunction: `webpackJsonp_${name}`
},
plugins: [
// 增加qiankun插件
qiankun("app-aaa", { // app-aaa是与主应用main.ts里注册子应用的name一致
useDevMode: true
}),
]
})
src
目录增加public-path.ts
文件:
import { renderWithQiankun, qiankunWindow } from 'vite-plugin-qiankun/dist/helper';
if (qiankunWindow.__POWERED_BY_QIANKUN__) {
// eslint-disable-next-line no-undef
__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}
路由文件需要修改的内容:
import { qiankunWindow } from 'vite-plugin-qiankun/dist/helper';
export default createRouter({
history: createWebHistory(
qiankunWindow.__POWERED_BY_QIANKUN__ ? '/app-aaa/' : '/subapp/aaa/'
),
});
src
目录增加action.ts
文件:
function emptyAction() {
// 警告:提示当前使用的是空 Action
console.warn("Current execute action is empty!");
}
// 我们首先设置一个用于通信的Actions类
class Actions {
actions = {
onGlobalStateChange: emptyAction,
setGlobalState: emptyAction
}
// 默认值为空Action
constructor() {
}
// 设置actions
setActions(actions) {
console.log(actions)
this.actions = actions
}
// 映射
onGlobalStateChange(...args) {
return this.actions.onGlobalStateChange(...args)
}
// 映射
setGlobalState(...args) {
return this.actions.setGlobalState(...args)
}
}
const actions = new Actions()
export default actions
main.ts
文件需要增加的内容:
import { renderWithQiankun, qiankunWindow } from 'vite-plugin-qiankun/dist/helper';
import actions from './action';
let instance: any;
let history: any;
declare global {
interface Window {
__POWERED_BY_QIANKUN__?: string;
}
}
if (!qiankunWindow.__POWERED_BY_QIANKUN__) {
// 独立访问时的代码
instance = createApp(App)
instance
.use(router)
.use(store)
instance.mount('#subApp')
// ... ...
} else {
// 在qiankun内访问
renderWithQiankun({
mount(props) {
history = createWebHistory(
qiankunWindow.__POWERED_BY_QIANKUN__ ? '/app-aaa' : '/subapp/aaa'
);
instance = createApp(App)
instance
.use(router)
.use(store)
instance.mount(
(props.container
? props.container.querySelector('#subApp')
: document.getElementById('subApp')) as Element
)
if (props) {//子应用接收主应用值
actions.setActions(props)
actions.onGlobalStateChange((state) => {
console.log("我是子应用,我检测到数据了:", state);
if(!state.token){
console.log('document.location.hostname', window.location.origin)
}
}, true);
}
},
bootstrap() {
console.log('--bootstrap')
},
update() {
console.log('--update')
},
unmount() {
instance.unmount()
console.log('--unmount')
console.log('instance',instance)
console.log('history',history)
instance._container.innerHTML = '';
history.destroy();// 不卸载 router 会导致其他应用路由失败
instance = null;
},
})
}
vite2+vue3子应用配置要点:
- 安装
qiankun
; - 安装
vite-plugin-qiankun
; vite.config.ts
文件里面增加base
、port
、headers
跨域、output
和qiankun插件
配置;- 注意
qiankunWindow.__POWERED_BY_QIANKUN__
里的变量名是qiankunWindow
,qiankunWindow
相当于一个假的window对象,是作为子应用js代码执行时的全局变量,几个文件都用到这个,划重点; main.ts
文件里增加判断是否是qiankunWindow.__POWERED_BY_QIANKUN__
来分别写独立访问时和qiankun里访问时的代码;main.ts
文件里的qiankun访问的代码是放在renderWithQiankun
里的mount
生命周期里面;- 有两处路由相关的修改,在
main.ts
和路由文件里。 - 路由文件和
vite.config.ts
里面的/subapp/aaa/
,和主应用main.ts
里注册子应用的entry
是一致的。
Vue2子应用配置要点
vue.config.js
增加的配置:
devServer: {
port: 7200, // 与主应用里注册的开发环境entry一致
headers: {
'Access-Control-Allow-Origin': '*'
}
}
publicPath: process.env.NODE_ENV === 'development' ? '/' : '/subapp/bbb/', // 增加了判断,生产环境的路径跟主应用里一致
output: {
library: `${name}-[name]`,
libraryTarget: 'umd', // 把微应用打包成 umd 库格式
jsonpFunction: `webpackJsonp_${name}`
}
src
目录增加public-path.js
文件:
if (window.__POWERED_BY_QIANKUN__) {
// eslint-disable-next-line no-undef
__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__
}
路由文件需要修改的内容:
export default new Router({
mode: 'history',
base: window.__POWERED_BY_QIANKUN__ ? '/app-bbb' : '/',
})
src
目录增加action.js
文件,与上面子应用的一样:
function emptyAction() {
// 警告:提示当前使用的是空 Action
console.warn("Current execute action is empty!");
}
// 我们首先设置一个用于通信的Actions类
class Actions {
actions = {
onGlobalStateChange: emptyAction,
setGlobalState: emptyAction
}
// 默认值为空Action
constructor() {
}
// 设置actions
setActions(actions) {
console.log(actions)
this.actions = actions
}
// 映射
onGlobalStateChange(...args) {
return this.actions.onGlobalStateChange(...args)
}
// 映射
setGlobalState(...args) {
return this.actions.setGlobalState(...args)
}
}
const actions = new Actions()
export default actions
main.js
文件需要增加的内容:
import router from './router'
import store from './store'
import actions from './action'
let instance = null
function render(props = {}) {
const { container } = props
instance = new Vue({
router,
store,
render: h => h(App)
}).$mount(container ? container.querySelector('#subApp') : '#subApp')
}
if (!window.__POWERED_BY_QIANKUN__) {
render()
}
export async function bootstrap () {
console.log('[vue] vue app bootstraped')
}
export async function mount(props) {
console.log('receive props', props)
// Vue.prototype.$qiankun=props
if (props) { // 子应用接收主应用值
actions.setActions(props)
actions.onGlobalStateChange((state) => {
console.log('我是子应用bbb,我检测到数据了:', state)
}, true)
}
render(props)
}
export async function unmount() {
instance.$destroy()
instance.$el.innerHTML = ''
instance = null
}
vue2子应用配置要点:
- 不需要安装什么,整体配置相对比较简单;
vue.config.js
文件里面修改publicPath
配置,如上面代码加上开发环境判断;vue.config.js
文件里面在devServer
下增加port
和headers
跨域配置;vue.config.js
文件里面在configureWebpack
下增加output
配置;- 注意
window.__POWERED_BY_QIANKUN__
里的变量名是window
。 main.js
文件里基本按照官网来修改就可以,router
可以使用你现有的,然后在路由文件里修改就好。vue.config.js
里面的/subapp/bbb/
,和主应用main.ts
里注册子应用的entry
是一致的。- 路由文件里面的
app-bbb
,和主应用main.ts
里注册子应用的name
是一致的。
部署的nginx配置:
基本上按照官网的配置来的,官网写的很详细了,按官网配置没错。这个配置是主应用跟子应用部署在同一台服务器的配置,适用于测试和生产环境。
server{
listen 80;
server_name yourdomain.com;
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
#lijian
location / {
root /www/html/app;
index index.html;
try_files $uri $uri/ /index.html;
}
location /admin111 {
proxy_pass http://111.111.111.111:8888;
}
location /admin222 {
proxy_pass http://222.222.222.222:8888;
}
}
...
└── app/ # 主应用的目录(/www/html/app)
├── css/ # 主应用的css文件夹
├── js/ # 主应用的js文件夹
├── index.html # 主应用的index.html
├── subapp/ # 存放所有子应用的目录
| ├── aaa/ # 存放子应用 aaa 的目录
| ├── bbb/ # 存放子应用 bbb 的目录
...
nginx配置说明:
- 这是主应用和子应用都部署在同一台服务器的基本配置,划重点;
- 注意上面配置,这里只需要配置主应用的目录就好,服务器
/www/html/app
目录下放主应用的页面文件。 - 需要在服务器
/www/html/app
目录下建立subapp
目录,subapp
目录是与本文上面的保持一致的。 - 子应用
aaa
在服务器/www/html/app/subapp
下面建立aaa
目录,把构建好的页面放进去。 - 子应用
bbb
同理,在服务器/www/html/app/subapp
下面建立bbb
目录,把构建好的页面放进去。 - 这里的
subapp
目录,以及subapp
下面建立的aaa
和bbb
两个目录,是跟本文上面主应用和子应用配置里的/subapp/aaa/
和/subapp/bbb/
一致的,重点重点重点。 - 之前本地开发要把各个子应用里面配置的代理拷贝到主应用里面去,上到测试或者生产环境则需要nginx里面做转发,如上面配置,ip可以换成域名。
心得和总结
- 基于
vite
的vue3应用在本地开发和测试生产都是可以搞定的,不用把vite替换换成webpack(网上见有替换的)。 - 基于
vite
的应用需要安装qiankun插件,变量名不一样。 - 基于
vue2
的应用接入qiankun相对简单得多。 - 本地开发和测试生产的
entry
和publicPath
等配置不一样,需要像本文一样做是不是本地开发环境的判断。 Vue2项目
有的资源路径名是publicPath
,有的是assetsPublicPath
,根据实际项目来。- 整合qiankun最花时间的不是qiankun本身,是各个系统的登录改造,以及不断试错尝试,本文是这样。
- 碰到问题多看官网的 常见问题 ,部署相关的问题多看入门教程,特别是部署相关的,根据官网文档来没错。
- 一定要仔细再仔细,耐心再耐心,不断地试错。
以上就是整合qiankun
的心得总结,如果有错误和不完善的地方,欢迎指正。
转载说明
原文标题:整合qiankun微前端框架的心得笔记
原文地址:hanhan.pro/using-qiankun-micro-frontends-solution/
原文作者:xiaohan
转载请注明出处