1.多系统集成的一个门户
2.每个系统可以用不同的技术栈
3.根据路由 判断切换系统
乾坤网站地址: https://qiankun.umijs.org/zh
2018 年 Single-SPA 诞生了, single-spa 是一个用于前端微服务化的 JavaScript 前端解决方案 ( 本身没有处理样式隔离, js 执行隔离 ) 实现了路由劫持和应用加载。
2019 年 qiankun 基于 Single-SPA, 提供了更加开箱即用的 API ( single-spa + sandbox + import-html-entry ) 做到了,技术栈无关、并且接入简单(像 i frame 一样简单)
引入安装
yarn add qiankun
npm i qiankun
API ------------ 在min.js配置
主应用
// 有两种配置方式 1 根据路由配置(推荐) 2 手动加载微应用 , 两种方式属性一致
// 基于路由配置
// 适用于 route-based 场景。
// 通过将微应用关联到一些 url 规则的方式,实现当浏览器 url 发生变化时,自动加载相应的微应用的功能。
import { registerMicroApps, start } from 'qiankun';
//当微应用信息注册完之后,一旦浏览器的 url 发生变化,便会自动触发 qiankun 的匹配逻辑,所有 activeRule 规则匹配上的微应用就会被插入到指定的 container 中,同时依次调用微应用暴露出的生命周期钩子
registerMicroApps(
[
{
name: 'app1', // string - 必选,微应用的名称,微应用之间必须确保唯一。
entry: '//localhost:8080', // 必选,微应用的入口 ==> 子项目的域名和端口
container: '#container', // string | HTMLElement - 必选,微应用的容器节点 我们子应用挂载的节点,相当于Vue项目里面的app节点 如container: '#app' 或 container: document.querySelector('#app')
activeRule: '/react', // string | Array<string> | (location: Location) => boolean 必选,微应用的激活规则
props: {
name: 'kuitos',
},
},
],
{
beforeLoad: (app) => console.log('before load', app.name),
beforeMount: [(app) => console.log('before mount', app.name)],
},
);
start(); // 启动 qiankun。
registerMicroApps(apps, lifeCycles?)
/**
参数 : https://qiankun.umijs.org/zh/api#startopts
apps - Array - 必选,微应用的一些注册信息
name - string - 必选,微应用的名称,微应用之间必须确保唯一。
entry - string | { scripts?: string[]; styles?: string[]; html?: string } - 必选,微应用的入口 。==> 子项目的域名和端口
配置为字符串时,表示微应用的访问地址,例如 https://qiankun.umijs.org/guide/。
配置为对象时,html 的值是微应用的 html 内容字符串,而不是微应用的访问地址。微应用的 publicPath 将会被设置为 /。
container - string | HTMLElement - 必选,微应用的容器节点的选择器或者 Element 实例。如container: '#root' 或 container: document.querySelector('#root')。
activeRule - string | (location: Location) => boolean | Array<string | (location: Location) => boolean> - 必选,微应用的激活规则。
支持直接配置字符串或字符串数组,如 activeRule: '/app1' 或 activeRule: ['/app1', '/app2'],当配置为字符串时会直接跟 url 中的路径部分做前缀匹配,匹配成功表明当前应用会被激活。
支持配置一个 active function 函数或一组 active function。函数会传入当前 location 作为参数,函数返回 true 时表明当前微应用会被激活。如 location => location.pathname.startsWith('/app1')。
props - object - 可选,主应用需要传递给微应用的数据。
lifeCycles - 生命周期 - 可选,全局的微应用生命周期钩子 可以是数组 或 函数
beforeLoad - Lifecycle | Array<Lifecycle> - 可选
beforeMount - Lifecycle | Array<Lifecycle> - 可选
afterMount - Lifecycle | Array<Lifecycle> - 可选
beforeUnmount - Lifecycle | Array<Lifecycle> - 可选
afterUnmount - Lifecycle | Array<Lifecycle> - 可选
*/
子应用
子应用不需要额外安装任何其他依赖即可接入 qiankun 主应用。
if (window.__POWERED_BY_QIANKUN__) { // 动态添加publicPath
// eslint-disable-next-line no-undef
__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__
}
let instance = null
function render(props) {
instance = new Vue({
router,
render: h => h(App)
}).$mount('#app');
}
// 父应用加载子应用,子应用必须暴露三个接口:bootstrap、mount、unmount
// 子组件的协议就ok了
export async function bootstrap(props) {
};
export async function mount(props) {
render(props) // 应用每次进入都会调用 mount 方法,通常我们在这里触发应用的渲染方法
}
export async function unmount(props) {
instance.$destroy() // 卸载
instance = null
}
// 单独开发环境
window.__POWERED_BY_QIANKUN__ || mount()
子应用 webpack配置
module.exports = {
lintOnSave: false, // 关闭eslint检测
css: {
// 是否提取css 生产环境可以配置为 true
extract: true,
},
devServer: {
port: 8080,//这里的端口是必须和父应用配置的子应用端口一致
headers: {
//因为qiankun内部请求都是fetch来请求资源,所以子应用必须允许跨域
'Access-Control-Allow-Origin': '*'
}
},
configureWebpack: {
output: {
//资源打包路径
library: 'vueApp',
libraryTarget: 'umd'
},
optimization: {
runtimeChunk: 'single',
splitChunks: {
chunks: 'all',
maxInitialRequests: Infinity,
minSize: 20000, // 依赖包超过20000bit将被单独打包
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name (module) {
// get the name. E.g. node_modules/packageName/not/this/part.js
// or node_modules/packageName
const packageName = module.context.match(/[\\/]node_modules[\\/](.*?)([\\/]|$)/)[1]
// npm package names are URL-safe, but some servers don't like @ symbols
return `npm.${ packageName.replace('@', '') }`
}
},
default: {
minChunks: 2,
priority: -20,
reuseExistingChunk: true
}
}
}
},
// gzip压缩
plugins: [
new webpack.ContextReplacementPlugin(/moment[/\\]locale$/, /zh-cn|ja/),
new CompressionPlugin({
filename: '[path].gz[query]',
algorithm: 'gzip',
test: new RegExp('\\.(' + ['js', 'css', 'json', 'html', 'svg', 'woff', 'ttf'].join('|') + ')$'),
threshold: 10240,
minRatio: 0.8
})
],
}
}
注意点(不对请留言)
我们所有项目路由都是在主应用 配置的 , 有个子页面保存 路由 和 组件组件路径的, 根据权限动态在主应用 router中加载路由
webpack 可以参考这个文章 https://blog.csdn.net/qq_33396780/article/details/110694871?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522163521307916780264026886%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=163521307916780264026886&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allfirst_rank_ecpm_v1~rank_v31_ecpm-1-110694871.pc_search_result_cache&utm_term=%E4%B9%BE%E5%9D%A4%E6%A1%86%E6%9E%B6&spm=1018.2226.3001.4187