In Chinese traditional culture
qian
means heaven andkun
stands for earth, soqiankun
is the universe.
An implementation of Micro Frontends, based on single-spa, but made it production-ready.
As we know what micro-frontends aims for:
Techniques, strategies and recipes for building a modern web app with multiple teams using different JavaScript frameworks. — Micro Frontends
An independent development experience is very important for a large system, especially with an enterprise application. But if you've tried to implement a micro-frontends architecture in such a system, you'll usually hurt your brain with such problems:
- How to compose your independent sub apps into your main system?
- How to guarantee your sub apps to be isolated by each other?
- and so on...
We built an library to help you solve these glitch problems automatically without any mental burden of yours, then named it qiankun
.
Probably the most complete micro-frontends solution you ever met🧐.
npm i qiankun -S
-
Create master framework with qiankun
import { registerMicroApps, start } from 'qiankun'; function render({ appContent, loading }) { const container = document.getElementById('container'); ReactDOM.render(<Framework loading={loading} content={appContent}/>, container); } function genActiveRule(routerPrefix) { return (location) => location.pathname.startsWith(routerPrefix); } registerMicroApps( [ { name: 'react app', // app name registered entry: '//localhost:7100', render, activeRule: genActiveRule('/react') }, { name: 'vue app', entry: { scripts: [ '//localhost:7100/main.js' ] }, render, activeRule: genActiveRule('/vue') }, ], ); start();
-
Export the lifecycles from your sub app entry
export async function bootstrap() { console.log('react app bootstraped'); } export async function mount(props) { console.log(props); ReactDOM.render(<App/>, document.getElementById('react15Root')); } export async function unmount() { ReactDOM.unmountComponentAtNode(document.getElementById('react15Root')); }
For more lifecycle information, see single-spa lifecycles
-
Config your sub app bundler
While you wanna build a sub app to integrate to qiankun, pls make sure your bundler have the required configuration below:
output: {
library: packageName,
libraryTarget: 'umd',
jsonpFunction: `webpackJsonp_${packageName}`,
}
see https://webpack.js.org/configuration/output/#outputlibrary
parcel serve entry.js --global myvariable
see https://en.parceljs.org/cli.html#expose-modules-as-umd
npm i
npm run install:examples
npm start
Visit http://localhost:7099
- Based on single-spa
- HTML Entry
- Config Entry
- Isolated styles
- JS Sandbox
- Assets Prefetch
- @umijs/plugin-qiankun integration
type RegistrableApp = {
// name to identify your app
name: string;
// where your sub app served from, supported html entry and config entry
entry: string | { scripts?: string[]; styles?: string[]; html?: string };
// render function called around sub app lifecycle
render: (props?: { appContent: string, loading: boolean }) => any;
// when sub app active
activeRule: (location: Location) => boolean;
// props pass through to sub app
props?: object;
};
type Lifecycle<T extends object> = (app: RegistrableApp<T>) => Promise<any>;
type LifeCycles<T extends object> = {
beforeLoad?: Lifecycle<T> | Array<Lifecycle<T>>;
beforeMount?: Lifecycle<T> | Array<Lifecycle<T>>;
afterMount?: Lifecycle<T> | Array<Lifecycle<T>>;
beforeUnmount?: Lifecycle<T> | Array<Lifecycle<T>>;
afterUnmount?: Lifecycle<T> | Array<Lifecycle<T>>;
};
function registerMicroApps<T extends object = {}>(apps: Array<RegistrableApp<T>>, lifeCycles?: LifeCycles<T>): void;
function start({ prefetch: boolean, jsSandbox: boolean, singular: boolean }): void;
- Parcel apps integration (multiple sub apps displayed at the same time, but only one uses router at most)
- Communication development kits between master and sub apps
- Custom side effects hijacker
- Nested Microfrontends
https://github.com/umijs/qiankun/wiki/FAQ
https://github.com/umijs/umi#community
- single-spa What an awesome meta-framework for micro-fronteds!