translateHelp |
---|
true |
Umi plugin for qiankun.
-
yarn add @umijs/plugin-qiankun -D
-
配置
qiankun
开启。
Umi 应用一键开启 qiankun 微前端模式。
导航是主应用,App1/App2 是子应用,App1/App2 也支持单独打开。主应用可以嵌套 APP1 和 APP2,App1 也可以嵌套 App2。
$ yarn
$ yarn build
$ cd packages/plugin-qiankun && yarn start
- ✔︎ 基于 qiankun
- ✔︎ 支持主应用和子应用都用 umi
- ✔︎ 支持通过
<MicroApp />
组件引入子应用 - ✔︎ 父子应用通讯
- ✔︎ 子应用运行时配置自定义
bootstrap()
、mount()
和unmount()
- ✔︎ 主应用、子应用联调
- ✔︎ 嵌套子应用
子应用注册有两种方式,二选一即可
export default {
qiankun: {
master: {
// 注册子应用信息
apps: [
{
name: 'app1', // 唯一 id
entry: '//localhost:7001', // html entry
},
{
name: 'app2', // 唯一 id
entry: '//localhost:7002', // html entry
},
],
},
},
};
// 从接口中获取子应用配置,export 出的 qiankun 变量是一个 promise
export const qiankun = fetch('/config').then(({ apps }) => ({
// 注册子应用信息
apps,
// 完整生命周期钩子请看 https://qiankun.umijs.org/zh/api/#registermicroapps-apps-lifecycles
lifeCycles: {
afterMount: props => {
console.log(props);
},
},
// 支持更多的其他配置,详细看这里 https://qiankun.umijs.org/zh/api/#start-opts
}));
完整的主应用配置项看这里 masterOptions 配置列表
子应用的装载有两种方式,二选一即可:
建议使用这种方式来引入自带路由的子应用。假设我们的系统之前有这样的一些路由:
export default {
routes: [
{
path: '/',
component: '../layouts/index.js',
routes: [
{
path: '/app1',
component: './app1/index.js',
routes: [
{
path: '/app1/user',
component: './app1/user/index.js',
},
],
},
{
path: '/',
component: './index.js',
},
],
},
],
}
我们现在想在 /app1/project
和 /app2
这两个路径时分别加载微应用 app1 和 app2,只需要增加这样一些配置即可:
export default {
routes: [
{
path: '/',
component: '../layouts/index.js',
routes: [
{
path: '/app1',
component: './app1/index.js',
routes: [
{
path: '/app1/user',
component: './app1/user/index.js',
},
+ // 配置微应用 app1 关联的路由
+ {
+ path: '/app1/project',
+ microApp: 'app1',
+ },
],
},
+ // 配置 app2 关联的路由
+ {
+ path: '/app2',
+ microApp: 'app2'
+ },
{
path: '/',
component: './index.js',
},
],
},
],
}
微应用路由也可以配置在运行时,通过 src/app.ts 添加:
export const qiankun = fetch('/config').then(({ apps }) => {
return {
apps,
routes: [
{
path: '/app1',
microApp: 'app1',
}
]
}
});
运行时注册的路由会自动关联到你配置的根路由下面,比如你的路由是这样的:
export default {
routes: [
{
path: '/',
component: '../layouts/index.js',
routes: [
{
path: '/test',
component: './test.js',
},
],
},
]
}
完成了上面的运行时微应用路由配置后,你的路由结构会合自动并成这样的:
export default {
routes: [
{
path: '/',
component: '../layouts/index.js',
routes: [
+ {
+ path: '/app1',
+ microApp: 'app1',
+ },
{
path: '/test',
component: './test.js',
},
],
},
]
}
我们可以直接使用 React 标签的方式加载我们已注册过的子应用:
import { MicroApp } from 'umi';
export function MyPage() {
return (
<div>
<div>
+ <MicroApp name="app1" />
</div>
</div>
)
}
你可以通过配置 autoSetLoading
的方式,开启微应用的 loading 动画。
import { MicroApp } from 'umi';
export function MyPage() {
return (
<div>
<div>
<MicroApp name="app1" autoSetLoading />
</div>
</div>
)
}
默认情况下,当我们检测到你使用的是 antd 组件库时,loading 动画使用的是 antd Spin 组件。
如果你需要定制自己的 loading 动画,或者修改组件的样式,你可以这样处理:
import { MicroApp } from 'umi';
export function MyPage() {
return (
<div>
<MicroApp
name="app1"
autoSetLoading
// 设置自定义 loading 动画
loader={loading => <div>loading: {loading}</div>}
// 微应用容器 class
className="myContainer"
// wrapper class,仅开启 loading 动画时生效
wrapperClassName="myWrapper"
/>
</div>
)
}
路由模式下,你可以这样设置一些静态配置开启 loading 动画:
{
path: '/user',
microApp: 'user',
microAppProps: {
autoSetLoading: true,
className: 'myContainer',
wrapperClassName: 'myWrapper',
}
}
或者,你可以通过设置 autoSetLoading false 来关闭自动的 loading 动画:
import { MicroApp } from 'umi';
export function MyPage() {
return (
<div>
<div>
<MicroApp
name="app1"
// 关闭 loading 动画
autoSetLoading={false}
/>
</div>
</div>
)
}
export default {
qiankun: {
slave: {}
}
}
插件会自动为你创建好 qiankun 子应用需要的生命周期钩子,但是如果你想在生命周期期间加一些自定义逻辑,可以在子应用的 src/app.ts
里导出 qiankun
对象,并实现每一个生命周期钩子,其中钩子函数的入参 props
由主应用自动注入。
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);
},
};
为了获得更好地本地开发及调试体验,我们建议您提前在子应用中指定应用启动的具体端口号,如通过.env
指定
PORT=8081
详细配置参考:https://umijs.org/zh/guide/env-variables.html#port
有两种方式可以实现
配合 useModel 使用(推荐)
需确保已安装
@umijs/plugin-model
或@umijs/preset-react
-
主应用使用下面任一方式透传数据:
-
如果你用的 MicroApp 组件模式消费微应用,那么数据传递的方式就跟普通的 react 组件通信是一样的,直接通过 props 传递即可:
function MyPage() { const [name, setName] = useState(null); return <MicroApp name={name} onNameChange={newName => setName(newName)} /> }
-
如果你用的 路由绑定式 消费微应用,那么你需要在
src/app.ts
里导出一个useQiankunStateForSlave
函数,函数的返回值将作为 props 传递给微应用,如:// src/app.ts export function useQiankunStateForSlave() { const [masterState, setMasterState] = useState({}); return { masterState, setMasterState, } }
-
微应用中会自动生成一个全局 model,可以在任意组件中获取主应用透传的 props 的值。
import { useModel } from 'umi'; function MyPage() { const masterProps = useModel('@@qiankunStateFromMaster'); return <div>{ JSON.strigify(masterProps) }</div>; }
或者可以通过高阶组件 connectMaster 来获取主应用透传的 props
import { connectMaster } from 'umi'; function MyPage(props) { return <div>{ JSON.strigify(props) }</div>; } export default connectMaster(MyPage);
-
和
<MicroApp />
的方式一同使用时,会额外向子应用传递一个 setLoading 的属性,在子应用中合适的时机执行masterProps.setLoading(false)
,可以标记微模块的整体 loading 为完成状态。
类似 react 中组件间通信的方案
-
主应用中配置 apps 时以 props 将数据传递下去(参考主应用运行时配置一节)
// src/app.js export const qiankun = fetch('/config').then(config => { return { apps: [ { name: 'app1', entry: '//localhost:2222', props: { onClick: event => console.log(event), name: 'xx', age: 1, }, }, ], }; });
-
子应用在生命周期钩子中获取 props 消费数据(参考子应用运行时配置一节)
除了导航应用之外,App1 与 App2 均依赖浏览器 url,为了让 App1 嵌套 App2,两个应用同时存在,我们需要在运行时将 App2 的路由改为 memory 类型。
- 在 App1 中加入 master 配置
export default {
qiankun: {
master: {
// 注册子应用信息
apps: [
{
name: 'app2', // 唯一 id
entry: '//localhost:7002', // html entry
},
],
},
},
};
- 通过
<MicroAppWithMemoHistory />
引入 App2
import { MicroAppWithMemoHistory } from 'umi';
export function MyPage() {
return (
<div>
<div>
+ <MicroAppWithMemoHistory name="app2" url="/user" />
</div>
</div>
)
}
配置 | 说明 | 类型 | 是否必填 | 默认值 |
---|---|---|---|---|
apps | 子应用配置 | App[] | 是 | |
routes | 子应用运行时需要注册的微应用路由 | Route[] | 否 | N/A |
sandbox | 是否启用沙箱,详细说明 | boolean | 否 | false |
prefetch | 是否启用 prefetch 特性,详细说明 | boolean | 'all' | 否 | true |
配置 | 说明 | 类型 | 是否必填 | 默认值 |
---|---|---|---|---|
name | 子应用唯一 id | string | 是 | |
entry | 子应用 html 地址 | string | { script: string[], styles: [] } | 是 | |
props | 主应用传递给子应用的数据 | object | 否 | {} |
配置 | 说明 | 类型 | 是否必填 | 默认值 |
---|---|---|---|---|
path | 路由 path | string | 是 | |
microApp | 关联的微应用名称 | string | 是 | |
microAppProps | 微应用配置 | {autoSetLoading: boolean, className: string, wrapperClassName: string} | 否 | {} |
v2.3.0 完全兼容 v2 之前的版本,但我们还是建议您能升级到最新版本已获得更好的开发体验。
-
移除无必要的应用配置
export default { qiankun: { master: { apps: [ { name: 'microApp', entry: '//umi.dev.cnd/entry.html', - base: '/microApp', - mountElementId: 'root-subapp', - history: 'browser', } ] } } }
-
移除无必要的全局配置
export default { qiankun: { master: { apps: [], - defer: true, } } }
-
移除不必要的挂载容器
-export default MyContainer() { - return ( - <div> - <div id="root-subapp"></div> - </div> - ) -}
-
关联微应用
比如我们之前配置了一个微应用名为
microApp
,base 为/microApp
,mountElementId 为subapp-container
, 那么我们只需要(二选一):a. 增加
/microApp
的路由(推荐)export default { routes: [ ..., { path: '/microApp', microApp: 'microApp' } ] }
使用路由关联模式时,不再需要微应用的 base 配置必须跟主应用中的保持一致了。
b. 在
/microApp
路由对应的组件里使用MicroApp
export default { routes: [ ..., { path: '/microApp', component: 'MyPage' } ] }
import { MicroApp } from 'umi'; export default MyPage() { return ( <div> <MicroApp name="microApp" base="/microApp" /> </div> ) }
-
移除一些无效配置,如 手动添加子应用路由配置
-
主应用注册子应用时不再需要手动配置 base 和 mountElementId。
这类方式会导致很多关联问题,最典型的是如果我们需要将子应用挂载到某一个具体的子路由下时,常出现由于挂载点还未初始化或已被销毁导致的问题。
现在只需要在注册完子应用后,在期望的路由下指定需要挂载的子应用的 name 即可。
-
可以直接通过
<MicroApp />
组件的方式在任意位置挂载自己的子应用。详见 API 说明 -
不再支持主应用是 browser 路由模式,子应用是 hash 路由的混合模式。如果有场景需要可以通过自己使用
<MicroApp />
组件加载子应用。 -
移除了 base、mountElementId、defer 等配置,现在有更好的方式来解决这类问题,参见第一条。
-
rename
jsSandbox
->sandbox
,来自 qiankun2.0 的升级。 -
完全兼容 1.x 插件。
-
动态 history type 支持(即将到来 🎉),依赖 umi: ^3.2.7, @umijs/plugin-qiankun: ^2.4.0
通过运行时设置微应用 props 的方式,修改微应用 history 相关配置,从而解耦微应用配置,如:
// HistoryOptions 配置见 https://github.com/ReactTraining/history/blob/master/docs/api-reference.md type HistoryProp = { type: 'browser' | 'memory' | 'hash' } & HistoryOptions; <MicroApp history={{ type: 'browser', basename: '/microApp' }} />
-
运行时统一,针对多层嵌套微应用场景
-
微应用自动 mountElementId,避免多个 umi 子应用 mountElementId 冲突
-
自动 loading
-
本地集成开发支持