因業務須要,如下文字純我的qiankun實戰學習筆記,不談原理只記操做過程,內容不免有紕漏部分,敬請不吝賜教批評指正。css
"qiankun": "^2.4.0"
;"react-app-rewired": "^2.1.8"
、"react-router-dom": "^5.2.0"
;"vue": "^3.0.0"
;"vue-router": "^4.0.0-beta.11"
;npm init react-app react-app-qiankun-main
複製代碼
qiankun
yarn add qiankun # 或者 npm i qiankun -S
複製代碼
react-app-qiankun-main
├── .env.local // 本地環境
├── .env.development.local // 測試環境
├── .env.production.local // 生產環境
├── README.md
├── node_modules
├── package.json
├── .gitignore
├── public
│ ├── favicon.ico
│ ├── index.html
│ └── manifest.json
└── src
├── components
│ └── Loading.jsx
├── store
│ └── store.js // 主應用的全局狀態
├── apps.js // 子應用配置
├── App.css
├── App.js // 基座佈局,掛載子應用
├── App.test.js
├── index.css
├── index.js // 主應用中註冊微應用
├── logo.svg
├── reportWebVitals.js
└── setupTests.js
複製代碼
新增3個.env文件,主要配置不一樣環境的對應的域名html
REACT_APP_SUB_REACT=//localhost:2233/react
REACT_APP_SUB_VUE=//localhost:3344/vue
PORT=1122
複製代碼
REACT_APP_SUB_REACT = https://react.xiaoqiang.tech
REACT_APP_SUB_VUE = https://vue.xiaoqiang.tech
複製代碼
修改 index.html
掛載dom的默認id,防止與子應用id衝突前端
// 默認root => main-root
<div id="main-root"></div>
複製代碼
新增store/store.js,配置主應用的全局狀態vue
import { initGlobalState } from 'qiankun';
const initialState = {
user: {
name: 'qiankun'
}
};
const actions = initGlobalState(initialState);
actions.onGlobalStateChange((state, prev) => {
for(const key in state) {
initialState[key] = state[key];
}
})
// 非官方api,https://github.com/umijs/qiankun/pull/729
actions.getGlobalState = (key) => {
return key ? initialState[key] : initialState;
}
export default actions;
複製代碼
修改src/App.js,主要完成基座頁面佈局及增長掛載子應用的dom(id="subapp-viewport")node
function App(props) {
// ...省略,詳細可見源碼
return (
<> <div className="mainapp"> {/* 標題欄 */} <header className="mainapp-header"> <ul className="mainapp-header-sidemenu"> {/* 側邊欄 省略,詳細可見源碼 */} </ul> </header> <div className="mainapp-main"> {/* 子應用 */} <main id="subapp-viewport"></main> </div> </div> </>
);
}
複製代碼
增長apps.js,子應用的配置react
import store from './store/store'
const microApps = [
{
name: 'react',
entry: process.env.REACT_APP_SUB_REACT,
activeRule: '/react',
container: '#subapp-viewport',
},
{
name: 'vue',
entry: process.env.REACT_APP_SUB_VUE,
activeRule: '/vue',
container: '#subapp-viewport',
},
]
const apps = microApps.map(item => {
return {
...item,
props: {
routerBase: item.activeRule,
getGlobalState: store.getGlobalState,
}
}
})
export default apps
複製代碼
修改src/index.js,主應用中註冊微(子)應用webpack
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import { registerMicroApps, start, setDefaultMountApp } from 'qiankun';
import apps from './apps'
function render({ appContent, loading }) {
const container = document.getElementById('main-root');
ReactDOM.render(
<React.StrictMode> <App loading={loading} content={appContent} /> </React.StrictMode>,
container,
)
}
const loader = loading => render({ loading });
render({ loading: true });
const microApps = apps.map((app => ({
...app,
loader,
})))
registerMicroApps(microApps, {
beforeLoad: app => {
console.log('before load app.name=====>>>>>', app.name)
},
beforeMount: [
app => {
console.log('[LifeCycle] before mount %c%s', 'color: green;', app.name)
}
],
afterMount: [
app => {
console.log('[LifeCycle] after mount %c%s', 'color: green;', app.name)
}
],
afterUnmount: [
app => {
console.log('[LifeCycle] after unmount %c%s', 'color: green;', app.name)
}
]
})
setDefaultMountApp('/react')
start();
複製代碼
本地啓動nginx
npm start
複製代碼
npm init react-app react-app-qiankun-sub
複製代碼
react-app-rewired
、react-router-dom
npm i react-app-rewired --save-dev
npm i react-router-dom --save
複製代碼
react-app-qiankun-sub
├── .env // 本地環境
├── config-overrides.js // 覆蓋create-react-app的webpack配置
├── README.md
├── node_modules
├── package.json
├── .gitignore
├── public
│ ├── favicon.ico
│ ├── index.html
│ └── manifest.json
└── src
├── components
│ └── LibVersion.jsx
├── pages
│ └── Home.jsx
├── public-path.js // __webpack_public_path__
├── App.css
├── App.js // 子應用佈局
├── App.test.js
├── index.css
├── index.js // 子應用入口,掛載dom導出相應的生命週期鉤子
├── logo.svg
├── reportWebVitals.js
└── setupTests.js
複製代碼
新增1個.env文件,主要配置本地環境git
此處PORT須要和基座REACT_APP_SUB_REACT
端口保持一致github
PORT=2233
複製代碼
修改 index.html
掛載dom的默認id,防止與基座及其餘子應用id衝突
// 默認root => sub-react-root
<div id="sub-react-root"></div>
複製代碼
新增src/public-path.js,webpack_public_path
if (window.__POWERED_BY_QIANKUN__) {
// eslint-disable-next-line no-undef
__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}
複製代碼
修改src/App.js,主要完成子應用頁面佈局(略,見源碼)
修改src/index.js,微(子)應用導出相應的生命週期鉤子
import './public-path';
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
function getSubRootContainer(container) {
return container ? container.querySelector('#sub-react-root') : document.querySelector('#sub-react-root');
}
function render(props) {
const { container } = props;
ReactDOM.render(
<React.StrictMode> <App store={{...props}} /> </React.StrictMode>,
getSubRootContainer(container),
);
}
function storeTest(props) {
props.onGlobalStateChange((value, prev) => console.log(`[onGlobalStateChange - ${props.name}]:`, value, prev), true);
props.setGlobalState({
ignore: props.name,
user: {
name: props.name,
},
});
}
if (!window.__POWERED_BY_QIANKUN__) {
render({});
}
export async function bootstrap() {
console.log('react app bootstraped');
}
export async function mount(props) {
console.log('props from main framework', props);
storeTest(props);
render(props);
}
export async function unmount(props) {
const { container } = props;
ReactDOM.unmountComponentAtNode(getSubRootContainer(container));
}
複製代碼
增長config-overrides.js,覆蓋create-react-app的webpack配置
const { name } = require('./package');
module.exports = {
webpack: config => {
config.output.library = `${name}-[name]`;
config.output.libraryTarget = 'umd';
config.output.jsonpFunction = `webpackJsonp_${name}`;
return config;
},
devServer: (configFunction) => {
return (proxy, allowedHost) => {
const config = configFunction(proxy, allowedHost);
config.historyApiFallback = true;
config.open = false;
config.hot = false;
config.watchContentBase = false;
config.liveReload = false;
config.headers = {
'Access-Control-Allow-Origin': '*',
};
return config;
}
}
}
複製代碼
修改 package.json
"scripts": {
- "start": "react-scripts start",
+ "start": "react-app-rewired start",
- "build": "react-scripts build",
+ "build": "react-app-rewired build",
- "test": "react-scripts test",
+ "test": "react-app-rewired test",
"eject": "react-scripts eject"
},
複製代碼
本地啓動
npm start
複製代碼
npm install -g @vue/cli-service-global
vue create vue-cli-qiankun-sub
複製代碼
vue-router
npm i vue-router --save
複製代碼
vue-cli-qiankun-sub
├── .env // 本地環境
├── vue.config.js // vue可選的配置文件
├── babel.config.js
├── README.md
├── node_modules
├── package.json
├── .gitignore
├── public
│ ├── favicon.ico
│ ├── index.html
│ └── manifest.json
└── src
├── components
│ └── HelloWorld.vue
├── router
│ └── index.js
├── views
│ └── Home.vue
├── public-path.js // __webpack_public_path__
├── App.vue // 子應用佈局
└── main.js // 子應用入口,掛載dom導出相應的生命週期鉤子
複製代碼
新增1個.env文件,主要配置本地環境
此處PORT須要和基座REACT_APP_SUB_VUE
端口保持一致
PORT=3344
複製代碼
修改 index.html
掛載dom的默認id,防止與基座及其餘子應用id衝突
// 默認root => sub-vue-root
<div id="sub-vue-root"></div>
複製代碼
新增src/public-path.js,webpack_public_path
if (window.__POWERED_BY_QIANKUN__) {
// eslint-disable-next-line no-undef
__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}
複製代碼
修改src/App.vue,主要完成子應用頁面佈局(略,見源碼)
修改src/mian.js,微(子)應用導出相應的生命週期鉤子
import './public-path';
import { createApp } from 'vue';
import { createRouter, createWebHistory } from 'vue-router';
import App from './App.vue';
import routes from './router';
import store from './store';
let router = null;
let instance = null;
let history = null;
function render(props = {}) {
const { container } = props;
history = createWebHistory(window.__POWERED_BY_QIANKUN__ ? '/vue' : '/');
router = createRouter({
history,
routes,
});
instance = createApp(App);
instance.use(router);
instance.use(store);
instance.mount(container ? container.querySelector('#sub-vue-root') : '#sub-vue-root');
}
if (!window.__POWERED_BY_QIANKUN__) {
render();
}
export async function bootstrap() {
console.log('%c ', 'color: green;', 'vue3.0 app bootstraped');
}
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,
},
});
}
export async function mount(props) {
storeTest(props);
render(props);
instance.config.globalProperties.$onGlobalStateChange = props.onGlobalStateChange;
instance.config.globalProperties.$setGlobalState = props.setGlobalState;
}
export async function unmount() {
instance.unmount();
instance._container.innerHTML = '';
instance = null;
router = null;
history.destroy();
}
複製代碼
增長vue.config.js配置文件
const path = require('path');
const { name } = require('./package');
function resolve(dir) {
return path.join(__dirname, dir);
}
const port = process.env.PORT;
module.exports = {
outputDir: 'dist',
assetsDir: 'static',
filenameHashing: true,
devServer: {
hot: true,
disableHostCheck: true,
port,
overlay: {
warnings: false,
errors: true,
},
headers: {
'Access-Control-Allow-Origin': '*',
},
},
// 自定義webpack配置
configureWebpack: {
resolve: {
alias: {
'@': resolve('src'),
},
},
output: {
// 把子應用打包成 umd 庫格式
library: `${name}-[name]`,
libraryTarget: 'umd',
jsonpFunction: `webpackJsonp_${name}`,
},
},
};
複製代碼
修改 package.json
"scripts": {
+ "start": "vue-cli-service serve",
},
複製代碼
本地啓動
npm start
複製代碼
以上操做完後,能夠直接經過基座預覽,子應用也可獨立預覽
http://localhost:1122/
複製代碼
http://localhost:2233/
複製代碼
http://localhost:3344/
複製代碼
// 基座:https://qiankun.xiaoqiang.tech
// react子應用:https://qiankun.xiaoqiang.tech/react
// vue子應用:https://qiankun.xiaoqiang.tech/vue
// 編譯後服務器存儲目錄
react-app-qiankun
├── main
│ └── index.html
├── react
│ └── index.html
└── vue
└── index.html
複製代碼
// 基座:https://qiankun.xiaoqiang.tech
// 編譯後服務器項目獨立存儲目錄
react-app-qiankun-main
└── index.html
複製代碼
// react子應用:https://react.xiaoqiang.tech
// 編譯後服務器項目獨立存儲目錄
react-app-qiankun-sub
└── index.html
複製代碼
// vue子應用:https://vue.xiaoqiang.tech
// 編譯後服務器項目獨立存儲目錄
vue-cli-qiankun-sub
└── index.html
複製代碼
// 基座:react-app-qiankun-main 存儲到 https://github.com/niexq/react-app-qiankun-main
// react子應用:react-app-qiankun-sub 存儲到 https://github.com/niexq/react-app-qiankun-sub
// vue子應用:vue-cli-qiankun-sub 存儲到 https://github.com/niexq/vue-cli-qiankun-sub
複製代碼
// 詳細配置步驟略
// github webHooks設置
// jenkins構建部分執行shell
BUILD_ID=dontKillMe
cd /var/jenkins_home/workspace/react-app-qiankun-main
npm install
npm run build
rm -rf /srv/www/react-app-qiankun-main
cp -rf /var/jenkins_home/workspace/react-app-qiankun-main/build /srv/www/react-app-qiankun-main/
複製代碼
nginx.conf
user root;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
#include /etc/nginx/conf.d/*.conf;
server {
listen 443;
server_name qiankun.xiaoqiang.tech; # 你的域名
ssl on;
root www/react-app-qiankun-main; # 前臺文件存放文件夾,可改爲別的
index index.html index.htm; # 上面配置的文件夾裏面的index.html
ssl_certificate cert/5543142_qiankun.xiaoqiang.tech.pem; #將domain name.pem替換成您證書的文件名。
ssl_certificate_key cert/5543142_qiankun.xiaoqiang.tech.key; #將domain name.key替換成您證書的密鑰文件名。
ssl_session_timeout 5m;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
location / {
# 用於配合 browserHistory使用
try_files $uri $uri/ /index.html;
# root /srv/www/react-app-qiankun-main;
# index index.html index.htm;
}
}
server {
listen 443;
server_name react.xiaoqiang.tech; # 你的域名
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';
if ($request_method = 'OPTIONS') {
return 204;
}
ssl on;
root www/react-app-qiankun-sub; # 前臺文件存放文件夾,可改爲別的
index index.html index.htm; # 上面配置的文件夾裏面的index.html
ssl_certificate cert/4325684_react.xiaoqiang.tech.pem; #將domain name.pem替換成您證書的文件名。
ssl_certificate_key cert/4325684_react.xiaoqiang.tech.key; #將domain name.key替換成您證書的密鑰文件名。
ssl_session_timeout 5m;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
location / {
# 用於配合 browserHistory使用
try_files $uri $uri/ /index.html;
# root /srv/www/react-app-qiankun-sub;
# index index.html index.htm;
}
}
server {
listen 443;
server_name vue.xiaoqiang.tech; # 你的域名
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';
if ($request_method = 'OPTIONS') {
return 204;
}
ssl on;
root www/vue-cli-qiankun-sub; # 前臺文件存放文件夾,可改爲別的
index index.html index.htm; # 上面配置的文件夾裏面的index.html
ssl_certificate cert/5556275_vue.xiaoqiang.tech.pem; #將domain name.pem替換成您證書的文件名。
ssl_certificate_key cert/5556275_vue.xiaoqiang.tech.key; #將domain name.key替換成您證書的密鑰文件名。
ssl_session_timeout 5m;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
location / {
# 用於配合 browserHistory使用
try_files $uri $uri/ /index.html;
# root /srv/www/vue-cli-qiankun-sub;
# index index.html index.htm;
}
}
}
複製代碼
docker運行nginx命令,重點關注-v 掛載目錄
docker run --name nginx -p 80:80 -p 443:443 -v /root/nginx/config/nginx.conf:/etc/nginx/nginx.conf -v /root/nginx/cert:/etc/nginx/cert -v /root/nginx/logs:/var/log/nginx -v /srv/www/react-app-qiankun-main:/etc/nginx/www/react-app-qiankun-main -v /srv/www/react-app-qiankun-sub:/etc/nginx/www/react-app-qiankun-sub -v /srv/www/vue-cli-qiankun-sub:/etc/nginx/www/vue-cli-qiankun-sub --restart=always -d nginx:stable
複製代碼
沒有總結,遇到的問題太多,筆記總結的太雜,後期再整理分享
react子應用預覽:react.xiaoqiang.tech
vue子應用預覽:vue.xiaoqiang.tech
能堅持到最後的都是勇士,感謝閱讀
,歡迎star
鼓勵