后端有微服务框架,当然前端也有微前端框架。
“微前端架构”就是构建基于微服务的前端应用架构。
其思想是将前端应用切分为一系列可以单独部署的松耦合的应用,然后将这些应用组装起来创建单个面向用户的应用程序。
iframe
天然具备微前端的基因。我们只需将单体的前端应用,按照业务模块进行拆分,分别部署。最后通过 iframe
进行动态加载即可。
Demo:
<html>
<head>
<title>微前端-ifametitle>
head>
<body>
<h1>我是容器h1>
<iframe id="mfeLoader">iframe>
<script type="text/javascript">
const routes = {
'/': 'https://app.com/index.html',
'/app1': 'https://app1.com/index.html',
'/app2': 'https://app2.com/index.html',
};
const iframe = document.querySelector('#mfeLoader');
iframe.src = routes[window.location.pathname];
script>
body>
html>
优点:
缺点:
常见的实现方式是,服务端根据路由动态渲染特定页面的模板文件。架构图如下:
优点:
缺点:
借助 single-spa
,开发者可以为不同的子应用使用不同的技术栈,比如子应用 A 使用 vue
开发,子应用 B 使用 react
开发,完全没有历史债务。
single-spa 的实现原理并不难,从架构上来讲可以分为两部分:子应用
和容器应用
。
子应用与传统的单页应用的区别在于:
容器应用主要负责注册应用,当 url 命中子应用的路由时激活并挂载子应用,或者当子应用不处于激活状态时,将子应用从页面中移除卸载。其核心方法有两个:
registerApplication
注册并下载子应用start
启动处于激活状态的子应用。容器应用代码
<html>
<body>
<script src="single-spa-config.js">script>
body>
html>
single-spa-config.js
代码如下:
import * as singleSpa from 'single-spa';
const appName = 'app1';
const app1Url = 'http://app1.com/app1.js'
// loadJS 方法是伪代码,表示加载 app1.js。开发者需要自己实现,或者借助 systemJS 来实现。
singleSpa.registerApplication('app1',() => loadJS(app1Url), location => location.pathname.startsWith('/app1'))
singleSpa.start();
子应用代码:
//app1.js
let domEl;
export function bootstrap(props) {
return Promise
.resolve()
.then(() => {
domEl = document.createElement('div');
domEl.id = 'app1';
document.body.appendChild(domEl);
});
}
export function mount(props) {
return Promise
.resolve()
.then(() => {
domEl.textContent = 'App 1 is mounted!'
});
}
export function unmount(props) {
return Promise
.resolve()
.then(() => {
domEl.textContent = '';
})
}
优点:
缺点:
qiankun
是一个基于 single-spa
的微前端实现库,旨在帮助大家能更简单、无痛的构建一个生产可用微前端架构系统。
在主应用中注册微应用
import { registerMicroApps, start } from 'qiankun';
registerMicroApps([
{
name: 'react app', // app name registered
entry: '//localhost:7100',
container: '#yourContainer',
activeRule: '/yourActiveRule',
},
{
name: 'vue app',
entry: { scripts: ['//localhost:7100/main.js'] },
container: '#yourContainer2',
activeRule: '/yourActiveRule2',
},
]);
start();
当微应用信息注册完之后,一旦浏览器的 url 发生变化,便会自动触发 qiankun 的匹配逻辑,所有 activeRule 规则匹配上的微应用就会被插入到指定的 container 中,同时依次调用微应用暴露出的生命周期钩子。
微应用需要在自己的入口 js (通常就是你配置的 webpack 的 entry js) 导出 bootstrap
、mount
、unmount
三个生命周期钩子,以供主应用在适当的时机调用。
/**
* bootstrap 只会在微应用初始化的时候调用一次,下次微应用重新进入时会直接调用 mount 钩子,不会再重复触发 bootstrap。
* 通常我们可以在这里做一些全局变量的初始化,比如不会在 unmount 阶段被销毁的应用级别的缓存等。
*/
export async function bootstrap() {
console.log('react app bootstraped');
}
/**
* 应用每次进入都会调用 mount 方法,通常我们在这里触发应用的渲染方法
*/
export async function mount(props) {
ReactDOM.render(<App />, props.container ? props.container.querySelector('#root') : document.getElementById('root'));
}
/**
* 应用每次 切出/卸载 会调用的方法,通常在这里我们会卸载微应用的应用实例
*/
export async function unmount(props) {
ReactDOM.unmountComponentAtNode(
props.container ? props.container.querySelector('#root') : document.getElementById('root'),
);
}
/**
* 可选生命周期钩子,仅使用 loadMicroApp 方式加载微应用时生效
*/
export async function update(props) {
console.log('update props', props);
}
优点:
缺点: