本教程适合于qiankun新手,手把手教你搭建一个简单的本地前端微服务,附完整代码
一、什么是微前端
微前端是一种多个团队通过独立发布功能的方式来共同构建现代化 web 应用的技术手段及方法策略。
微前端架构核心价值:
- 技术栈无关:主框架不限制接入应用的技术栈,微应用具备完全自主权
- 独立开发、独立部署:微应用仓库独立,前后端可独立开发,部署完成后主框架自动完成同步更新
- 增量升级:在面对各种复杂场景时,我们通常很难对一个已经存在的系统做全量的技术栈升级或重构,而微前端是一种非常好的实施渐进式重构的手段和策略
- 独立运行时:每个微应用之间状态隔离,运行时状态不共享
二、qiankun 的核心设计理念
- 简单
由于主应用微应用都能做到技术栈无关,qiankun 对于用户而言只是一个类似 jQuery 的库,你需要调用几个 qiankun 的 API 即可完成应用的微前端改造。同时由于 qiankun 的 HTML entry 及沙箱的设计,使得微应用的接入像使用 iframe 一样简单。 - 解耦/技术栈无关
微前端的核心目标是将巨石应用拆解成若干可以自治的松耦合微应用,而 qiankun 的诸多设计均是秉持这一原则,如 HTML entry、沙箱、应用间通信等。这样才能确保微应用真正具备 独立开发、独立运行 的能力。
特性
- 基于 single-spa 封装,提供了更加开箱即用的 API。
- 技术栈无关,任意技术栈的应用均可 使用/接入,不论是 React/Vue/Angular/JQuery 还是其他等框架。
- HTML Entry 接入方式,让你接入微应用像使用 iframe 一样简单。
- 样式隔离,确保微应用之间样式互相不干扰。
- JS 沙箱,确保微应用之间 全局变量/事件 不冲突。
- 资源预加载,在浏览器空闲时间预加载未打开的微应用资源,加速微应用打开速度。
- umi 插件,提供了 @umijs/plugin-qiankun 供 umi 应用一键切换成微前端架构系统。
三、代码演示
1、创建并配置主应用
- 通过
pnpm create vue@latest
创建一个Vue3项目为主应用。 - 安装qiankun:
pnpm i qiankun -S
- 注册微应用并启动
打开src下的main.ts文件,注册微应用,代码如下,这里注册了两个子应用sub-vue、sub-react
javascript
import { registerMicroApps, start } from 'qiankun'
// 注册微应用
registerMicroApps([
{
name: 'sub-vue', //子应用的名称
entry: '//localhost:3001', //子项目启动后的地址
container: '#container', //加载的容器
activeRule: '/sub-vue' //匹配的路由
},
{
name: 'sub-react',
entry: '//localhost:3002',
container: '#container',
activeRule: '/sub-react'
}
])
// 启动 qiankun
start()
2、创建并配置Vue子项目
- 通过
pnpm create vue@latest
创建一个Vue3子应用。 - 通过
pnpm i vite-plugin-qiankun
安装vite-plugin-qiankun
依赖包。 - 在vite.config.js文件中配置qiankun插件,
javascript
import { fileURLToPath, URL } from 'node:url'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import qiankun from 'vite-plugin-qiankun'
export default defineConfig({
base: '/sub-vue',
server: {
port: 3001,
cors: true,
origin: 'http://localhost:3001'
},
plugins: [
vue(),
qiankun('sub-vue', { //配置qiankun插件
useDevMode: true
})
],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
}
}
})
- 修改main.ts
javascript
import './assets/main.css'
import { createApp } from 'vue'
import { renderWithQiankun, qiankunWindow } from 'vite-plugin-qiankun/dist/helper'
import App from './App.vue'
import router from './router'
let app: any
if (!qiankunWindow.__POWERED_BY_QIANKUN__) {
app = createApp(App)
app.use(router)
app.mount('#app')
} else {
renderWithQiankun({
mount(props) {
app = createApp(App)
app.use(createPinia())
app.use(router)
app.use(ElementPlus)
app.mount(props.container?.querySelector('#app'))
},
bootstrap() {},
update() {},
unmount() {
app?.unmount()
}
})
}
3、创建并配置React子项目
- 在 src 目录新增 public-path.js文件
javascript
if (window.__POWERED_BY_QIANKUN__) {
__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__
}
- 修改入口文件src/index.js
javascript
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import './public-path';
let root
function render(props) {
const { container } = props
const dom = container ? container.querySelector("#root") : document.getElementById('root')
root = ReactDOM.createRoot(dom)
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
reportWebVitals();
}
// 判断能否在qiankun环境下运行
if (!window.__POWERED_BY_QIANKUN__) {
render({});
}
// 各个声明周期
// bootstrap 只会在微应用初始化的时候调用一次,下次微应用重新进入时会直接调用mount钩子
export async function bootstrap() {
console.log('[react16] react app bootstraped');
}
// 应用每次进入都会调用mount方法,通常在这里出发渲染方法
export async function mount(props) {
console.log('[react16] props from main framework', props);
render(props);
}
// 应用每次切出、卸载会调用unmount方法,通过在这里卸载微应用实例
export async function unmount(props) {
root.unmount()
}
- 修改webpack配置
1)为了不暴露所有的webpack配置,我们使用react-app-rewired工具包来进行修改。
javascript
pnpm i react-app-rewired
2)修改package.json
javascript
"scripts": {
"start": "set PORT=3002 && react-app-rewired start",
"build": "react-app-rewired build",
"test": "react-app-rewired test",
"eject": "react-scripts eject"
},
3)根目录新增 .rescriptsrc.js
javascript
const { name } = require('./package');
module.exports = {
webpack: (config) => {
config.output.library = `${name}-[name]`;
config.output.libraryTarget = 'umd';
config.output.chunkLoadingGlobal = `webpackJsonp_${name}`;
config.output.globalObject = 'window';
return config;
},
};
至此,所有的配置都已经完成,分别在本地启动主应用和子应用就可以实现一个简单的前端微服务了。
完整的代码可去GitHub上进行下载:源码下载