Preface
Qiankun microservices aggregate multiple systems with different technology stacks (React, Vue, Angular, jQuery) into one system, and each system can be deployed and run independently, which is suitable for large teams and large front-end projects.
Realize function:
- Introduce a multi-technology stack (React + Vue)
- Practice of Cache of Multi-tab Page of Backstage Management System (Ant Design Pro) in Qiankun Environment
- Dependency sharing --- sharing of packages react, react-dom, moment, antd, etc. common to the main and sub-applications
- Common resources --- common tools util, components, configuration in multiple projects synchronization
Online preview based on qiankun microservice:
Project structure
project | Technology stack | port | address |
---|---|---|---|
Main project (main-react) | Ant Design Pro | 5000 | http://qiankun.fancystore.cn |
Subproject 1 (app1-react) | Ant Design Pro | 5001 | http://app1.fancystore.cn |
Subproject 2 (app2-react) | Ant Design Pro | 5002 | http://app2.fancystore.cn |
Subproject 3 (app3-vue) | Vue Element Template | 5003 | http://app3.fancystore.cn |
Public Resource Library (qiankun-common) | TypeScript | https://github.com/czero1995/qiankun-common |
Project transformation
1. Main application (base)
1.1 Install qiankun
npm install @umi/qiankun --save
or
yarn add @umi/qiankun --save
1.2 Registering sub-applications
// 在config/config.ts加入
qiankun: {
master: {
apps: [
{
name:'app1',
entry: process.env.NODE_ENV === 'production' ? '//app1.fancystore.cn' : '//localhost:5001',
},
{
name:'app2',
entry: process.env.NODE_ENV === 'production' ? '//app2.fancystore.cn:' : '//localhost:5002',
},
{
name:'app3',
entry: process.env.NODE_ENV === 'production' ? '//app3.fancystore.cn:' : '//localhost:5003',
},
],
sandbox: true, //是否启用沙箱
prefetch: true, //是否启用prefetch特性
}
}
1.3 Modify the root node
// src/pages/document.ejs
id=root-master
1.4 New sub-application loading layout MicroAppLayout
// src/layouts/MicroAppLayout
import BasicLayout from '@ant-design/pro-layout';
import { KeepAlive, Provider } from 'react-keep-alive';
import { MicroAppWithMemoHistory } from 'umi';
import allRoutes from '../../config/routes';
function MicroAppLayout(props) {
let targetMicro = ''
const transRoutes = (routes, pathname) => {
routes.map(item => {
if (item.routes) {
return transRoutes(item.routes, pathname)
}
if (item.path === pathname) {
targetMicro = item.microName
}
})
return targetMicro
}
return <Provider>
<KeepAlive name={props.location.pathname}>
{
targetMicro ? <MicroAppWithMemoHistory name={transRoutes(allRoutes[0].routes, props.location.pathname)} url={props.location.pathname} /> :
<BasicLayout></BasicLayout>
}
</KeepAlive>
</Provider>
}
export default MicroAppLayout;
1.5 Create a new app.ts in the src directory, and determine if it is a sub-application, it needs to be loaded with MicroAppLayout
// src/app.ts
import LoadingComponent from '@/components/PageLoading';
import { dynamic } from 'umi';
const transRoutes = (routes) => {
routes.forEach(item => {
if(item.routes){
return transRoutes(item.routes)
}
if(item.microName){
item.component = dynamic({
loader: (a) => import(/* webpackChunkName: 'layouts__MicroAppLayout' */ '@/layouts/MicroAppLayout'),
loading: LoadingComponent,
})
}
})
}
export function patchRoutes({ routes }) {
transRoutes(routes[0].routes)
}
### 2. Sub-application React (Ant Desin Pro)
#### 2.1 Install qiankun
npm install @umi/qiankun --save
or
yarn add @umi/qiankun --save
#### 2.2 Sub-project registration qiankun, add in config/config.ts
qiankun: {
slave: {}
}
#### 2.3 Modify the root node src/pages/document.ejs
id=root-slave
#### 2.4 Create a new app.ts in the src directory and export the corresponding lifecycle hooks. The subproject needs to distinguish between the qiankun environment and the current environment. If it is the qiankun environment, use a blank template (src/layouts/BlankLayout) , If it is the current environment, use the default template (src/layouts/BasicLayout), so that it can be embedded in the qiankun environment to run and can be independently developed and deployed
const isQiankun = window.__POWERED_BY_QIANKUN__
export const qiankun = {
// 应用加载之前
async bootstrap(props) {
console.log('app1 bootstrap', props);
},
// 应用 render 之前触发
async mount(props) {
console.log('app1 mount', props);
},
// 应用卸载之后触发
async unmount(props) {
console.log('app1 unmount', props);
},
};
export async function patchRoutes({routes}) {
if(isQiankun){
routes[0]['component'] = require('@/layouts/BlankLayout').default
}
}
3. Sub-application Vue (Vue-Element-Template)
3.1 Add in configureWebpack under vue.config.js
output: {
// 把子应用打包成 umd 库格式(必须)
library: `${name}-[name]`,
libraryTarget: 'umd',
jsonpFunction: `webpackJsonp_${name}`,
}
3.2 Add in devServer under vue.config.js:
headers: {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "*",
"Access-Control-Allow-Headers": "*"
}
3.3 Expose the life cycle of qiankun in main.js:
let install = null;
function render(props) {
install = new Vue({
router,
store,
render: h => h(App)
}).$mount('#app3')
}
if (window.__POWERED_BY_QIANKUN__) {
__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
} else {
render();
}
export async function bootstrap(props) {
}
export async function mount(props) {
render(props);
}
export async function unmount(props) {
install.$destroy();
install = null
}
Project summary
- There are two ways to load sub-applications in the main application using routing binding and <MicroApp'/> component. If you want to support Ant Design Pro multi-tab page , you need to use <MicroApp'/> This kind of form, because of the dynamic display and insertion of the Tab, binding a dead route will cause qiankun to fail to load the corresponding page.
Ant Design Pro multi-tab page , clicking on the tabs to display different application pages will cause them to be destroyed, and the content data will be initialized and lost. Under src/layouts/MicroAppLayout:
引入 react-keep-alive 包 主应用须使用 MicroAppWithMemoHistory, 若使用 MicroApp 无效果。
Page jump 404 in qiankun environment
在qiankun环境下,所有的路由改动都会涉会触发qiankun的路由监听,需要对环境做出判断: export const qiankunJump = (url:string,name='页面名称',params = null) =>{ window.__POWERED_BY_QIANKUN__ ? history.pushState(params,name,url): umiHistory.push(url) } qiankunJump('/xxx')
qiankun external will report Cannot read property'createContext' of undefind
子项目是umi项目,只要配置了externals就会出错,需要更改exteranls的写法,去掉window externals: { 'react': 'window.React', 'react-dom': 'window.ReactDOM', } => externals: { react: 'React', 'react-dom': 'ReactDOM', }
Project optimization
1. Rely on sharing
如果主子应用使用的是相同的库或者包(react,react-dom,moment等),可以用externals的方式来引入,减少加载重复包导致资源浪费.
qiankun将子项目的外链script标签内容请求完后,会记录到一个全局变量中,下次再次使用,他会先从这个全局变量中取。这样就会实现内容的复用,只要保证两个链接的Url一致即可
const fetchScript = scriptUrl => scriptCache[scriptUrl] || (scriptCache[scriptUrl] = fetch(scriptUrl).then(response => response.text()));
所以只要子项目配置了webpack的externals,这些公共依赖在同一台服务器上,就可以实现子项目的公共依赖的按需引入,一个项目使用了之后,另一个项目不再重复加载,可以直接复用这个文件。
2. Resource sharing
解决资源共用的问题,可以提高项目的维护性,不然多个系统共用的组件或者工具维护起来很费力。
1. 常用的就是发布成npm包,各个项目去安装更新包。本地调试可以用npm link。但反复的更新包也是比较繁琐。
2. 还有一种方式是用git库引入, 在package.json的依赖中加入
"qiankun-common": "git+https://git@github.com:czero1995/qiankun-common.git"
使用
import { commonUtil } from 'qiankun-common';
util.qiankunJump('/xxx')
### Project begining
1. 进入main-react
npm install
npm run start
2. 进入app1-react
npm install
npm run start
3. 进入app2-react
npm install
npm run start
4. 进入app3-react
npm install
npm run dev
### Project deployment
The sub-application Nginx needs to be equipped with a cross-domain request header:
add_header Access-Control-Allow-Origin *; add_header Access-Control-Allow-Credentials true; add_header Cache-Control no-cache;
Nginx turns on gzip compression:
gzip on; gzip_min_length 200; gzip_buffers 4 16k; gzip_comp_level 9; gzip_vary on; gzip_disable "MSIE [1-6]\."; gzip_types text/plain application/x-javascript text/css application/xml text/javascript application/x-httpd-php application/javascript application/json;
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。