官方:https://qiankun.umijs.org/zh
搭建一个简单的 qiankun demo (全程CV即可)
- 一、 创建webpack项目
- 1. 调整webpack的packjson:
- 2. 在项目目录中创建config文件夹,分别创建build.js、install.js、start.js
- 3. 在项目目录中创建主程序master
- 二、 在master中引入qiankun
- 1. 修改master中main.js
- 2. 修改public中index.html
- 3. 修改App.vue
- 4. 修改vue.config.js
- 三、 创建子程序
- 1. 修改App.vue
- 2. 修改main.js
- 3. 修改router.js
- 4. src下创建public-path.js
- 5. 修改vue.config.js
- 四、 最后
- demo目录
- 补依赖
- 启项目
- 打包
(全程CV即可))
一、 创建webpack项目
该项目不是vue、react等前端脚手架,就是很简单的webpack项目
> npm init
1. 调整webpack的packjson:
{
"name": "vue-qiankun",
"version": "1.0.0",
"private": true,
"scripts": {
"init": "node config/install.js",
"cinit": "node config/install.js cnpm",
"serve": "node config/start.js",
"build": "node config/build.js",
"lint": "vue-cli-service lint"
},
"author": "",
"license": "ISC"
}
2. 在项目目录中创建config文件夹,分别创建build.js、install.js、start.js
build.js
const fs = require('fs');
const path = require('path');
const util = require('util');
const sub_app_ath = path.resolve();
const sub_apps = fs.readdirSync(sub_app_ath).filter(i => /^subapp|master/.test(i));
console.log(`即将进入所有模块并打包项目:${JSON.stringify(sub_apps)} ing...`)
const exec = util.promisify(require('child_process').exec);
function build() {
sub_apps.forEach(async i => {
console.log(`${i} 开始打包,耗时较久请耐心等待...`)
const { stdout, stderr } = await exec('npm run build', { cwd: path.resolve(i) });
console.log(i, 'success', stdout)
console.error(i, 'error', stderr)
});
};
build();
process.on('unhandledRejection', (reason, p) => {
console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);
// application specific logging, throwing an error, or other logic here
});
install.js
const fs = require('fs');
const path = require('path');
const util = require('util');
const sub_app_ath = path.resolve();
const sub_apps = fs.readdirSync(sub_app_ath).filter(i => /^subapp|master/.test(i));
console.log(`即将进入所有模块并下载依赖:${JSON.stringify(sub_apps)} ing... 批量下载所有项目依赖推荐使用 npm run cinit`)
const exec = util.promisify(require('child_process').exec);
// npm 源
let registry = process.argv.length === 3 ? 'cnpm install' : 'npm install';
function install() {
sub_apps.forEach(async i => {
console.log(`${i} 开始下载,耗时较久请耐心等待...`)
const { stdout, stderr } = await exec(registry, { cwd: path.resolve(i) });
console.log(i, 'success', stdout)
console.error(i, 'error', stderr)
});
};
install()
process.on('unhandledRejection', (reason, p) => {
console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);
// application specific logging, throwing an error, or other logic here
});
start.js
const fs = require('fs');
const path = require('path');
const util = require('util');
const sub_app_ath = path.resolve();
const sub_apps = fs.readdirSync(sub_app_ath).filter(i => /^subapp|master/.test(i));
console.log(`即将进入所有模块并启动服务:${JSON.stringify(sub_apps)} ing...`)
const exec = util.promisify(require('child_process').exec);
function start() {
sub_apps.forEach(async i => {
console.log(`${i} 开始启动... 全部启动需要时间,请稍加等候,或刷新浏览器即可`)
const { stdout, stderr } = await exec('npm run serve --fix', { cwd: path.resolve(i) });
console.log(i, 'success', stdout)
console.error(i, 'error', stderr)
});
exec('start http://localhost:7770/');
};
start();
process.on('unhandledRejection', (reason, p) => {
console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);
// application specific logging, throwing an error, or other logic here
});
3. 在项目目录中创建主程序master
这里我使用的vue,也可替换成react、angular
我这里创建的是master,可以是其他
> vue create master
二、 在master中引入qiankun
yarn add qiankun 或者
npm i qiankun -S
1. 修改master中main.js
import Vue from "vue";
import App from "./App.vue";
import router from "./router";
Vue.config.productionTip = false;
// 导入qiankun内置函数
import {
registerMicroApps, // 注册子应用
runAfterFirstMounted, // 第一个子应用装载完毕
setDefaultMountApp, // 设置默认装载子应用
start, // 启动
} from "qiankun";
let app = null;
/**
* 渲染函数
* appContent 子应用html
* loading 如果主应用设置loading效果,可不要
*/
function render({ appContent, loading } = {}) {
if (!app) {
app = new Vue({
el: "#container",
router,
data() {
return {
content: appContent,
loading,
};
},
render(h) {
return h(App, {
props: {
content: this.content,
loading: this.loading,
},
});
},
});
} else {
app.content = appContent;
app.loading = loading;
}
}
// 调用渲染主应用
render();
/**
* 路由监听
* @param {*} routerPrefix 前缀
*/
function genActiveRule(routerPrefix) {
return (location) => location.pathname.startsWith(routerPrefix);
}
// 注册子应用
registerMicroApps(
[
{
name: "vue-aaa",
entry: "//localhost:7771",
render,
activeRule: genActiveRule("/aaa"),
},
{
name: "vue-bbb",
entry: "//localhost:7772",
render,
activeRule: genActiveRule("/bbb"),
},
],
{
beforeLoad: [
(app) => {
console.log("before load", app);
},
], // 挂载前回调
beforeMount: [
(app) => {
console.log("before mount", app);
},
], // 挂载后回调
afterUnmount: [
(app) => {
console.log("after unload", app);
},
], // 卸载后回调
}
);
// 设置默认子应用,参数与注册子应用时genActiveRule("/aaa")函数内的参数一致
setDefaultMountApp("/aaa");
// 第一个子应用加载完毕回调
runAfterFirstMounted(() => {});
// 启动微服务
start();
2. 修改public中index.html
将id为app的div,id改为container
否则会跟子应用冲突,例如vue通常都是针对id为app的div进行操作
3. 修改App.vue
<template>
<div id="root" class="main-container">
<div class="main-container-menu"></div>
<!-- 子应用盒子 -->
<div id="root-view" class="app-view-box" v-html="content"></div>
</div>
</template>
<script>
export default {
name: "root-view",
props: {
loading: Boolean,
content: String
},
};
</script>
4. 修改vue.config.js
const port = 7770; // dev port
module.exports = {
lintOnSave:false,// 关闭eslint
// publicPath: './',
devServer: {
// host: '0.0.0.0',
hot: true,
disableHostCheck: true,
port,
overlay: {
warnings: false,
errors: true
},
headers: {
'Access-Control-Allow-Origin': '*',
}
}
};
三、 创建子程序
在项目目录中创建子程序subapp-time、subapp-news
注:与主程序同级目录
> vue create subapp-time
> vue create subapp-news
1. 修改App.vue
<template>
<div id="app">
<router-link to="/">Home</router-link>
<router-link to="/about">About</router-link>
<router-view />
</div>
</template>
<script>
export default {
name: "root-view",
props: {
loading: Boolean,
content: String,
},
};
</script>
2. 修改main.js
重点:
1.mount 方法中 base的 /aaa 与主应用注册子应用函数genActiveRule("/aaa")内的参数一致
import Vue from "vue";
import VueRouter from "vue-router";
import App from "./App.vue";
import "./public-path";
import routes from "./router";
Vue.config.productionTip = false;
// 声明变量管理vue及路由实例
let router = null;
let instance = null;
// 导出子应用生命周期 挂载前
export async function bootstrap(props) {
console.log(props);
}
// 导出子应用生命周期 挂载前 挂载后
// **注意,实例化路由时,判断当运行在qiankun环境时,路由要添加前缀,前缀与主应用注册子应用函数genActiveRule("/aaa")内的参数一致**
export async function mount(props) {
console.log(props)
router = new VueRouter({
base: window.__POWERED_BY_QIANKUN__ ? "/aaa" : "/",
mode: "hash",
routes
});
instance = new Vue({
router,
render: h => h(App)
}).$mount("#app");
}
// 导出子应用生命周期 挂载前 卸载后
export async function unmount() {
instance.$destroy();
instance = null;
router = null;
}
// 单独开发环境
mount();
3. 修改router.js
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
const routes = [
{
path: "/",
name: "home",
component: () =>
import("../views/Home.vue")
},
{
path: "/about",
name: "a-about",
component: () =>
import("../views/About.vue")
}
];
export default routes;
4. src下创建public-path.js
if (window.__POWERED_BY_QIANKUN__) {
// eslint-disable-next-line no-undef
__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}
5. 修改vue.config.js
重点:
1.这里的port要与主程序 main.js 中 registerMicroApps 对应的 entry 一致
2.port为端口号,尽量不要与主程序及其他子程序端口号产生冲突
const path = require('path');
const { name } = require('./package');
function resolve(dir) {
return path.join(__dirname, dir);
}
const port = 7771; // dev port
module.exports = {
outputDir: 'dist',
assetsDir: 'static',
filenameHashing: true,
devServer: {
// host: '0.0.0.0',
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}`,
},
},
}
四、 最后
demo目录
补依赖
npm run cinit
启项目
npm run serve
需要注意的是,起完服务后需要等待一段时间后再进,起项目需要时间。
打包
npm run build
如果有更漂亮的写法欢迎来讨论,让我们一起有条不紊的持续进步。
喜欢的话不妨点个小小的赞与关注,您的赞与关注将是我源源不断的前进动力。