2022 年 12 月 08 日原创
0
阿里开源的微前端库真是太好用了!
近日,由于所接手开发的项目越来越多,很多业务组件重复使用,每建一个新项目就要从旧项目里面 Copy 一份业务组件到新项目上,还要对新项目进行UI库适配,这无疑是一件很烦人的事,为了减少自己的工作量,我想到了当初开发小程序时微信提供的分包模式。
经过一番搜索,找到了一个工具 lerna,由于它只能在一个 git 库里面,也不是很符合我的需求,因为项目都是比较复杂的,整体包比较大,放到一个 git 里面容易出问题。
后来又想到了微前端,前后试过 qiankun / micro-app / wujie / ice-stark,唯有这个 ice-stark 最合心意,因为使用太简单了,在不考虑布局影响下,安装库后,只需要做小小的修改就可以实现微前端服务。
以 Vue 3 + vite 的已有项目为例 (官方也有这个栗子)
npm i --save @ice/stark
主应用
<html lang="zh-CN">
<head>
...
</head>
<body>
<div id="app"></div>
<!-- 这里多加一个子应用容器,ID 随便命名,实际上这个放在哪里都可以,最重要的是可以获取到 -->
<div id="ice-micro-app"></div>
<script src="..." type="module" />
</body>
</html>
// App.vue
import { onMounted } from 'vue';
import { useRouter } from 'vue-router';
import start from '@ice/stark-app/lib/start';
import { registerMicroApps } from '@ice/stark-app/lib/apps';
/**
这里需要关注的是:
activePath 设置的路由在 src/router 中不需要设置,注册应用后 @ice/stark-app 会进行路由劫持和匹配
entry 可以设置正在运行的项目地址或编译后的 dist/index.html 地址,总之是能够正常访问的地址就行
*/
type RegisterAppConfig = {
name: string,
activePath: string,
title: string,
loadScriptMode: string,
entry: string,
container: HTMLElement
}
const router = useRouter();
const container = document.getElementById('ice-micro-app') as HTMLElement;
registerMicroApps<RegisterAppConfig[]>([
{
name: 'ExampleApp',
activePath: '/example',
title: 'Example Child App',
loadScriptMode: 'import',
entry: 'http://localhost:3000/',
container,
}
]);
onMounted(() => {
start({
onLoadingApp: () => {},
onFinishLoading: () => {},
onRouteChange: (_, pathname) => router.push(
onActiveApps: (moduleApps) => {}
});
});
接下来看看子应用
// main.ts
import { createApp, type App as Root } from 'vue';
import App from './App.vue';
// import ...
import isInIcestark from '@ice/stark-app/lib/isInIceStark';
let vue = Root<Element> | null = null;
const runApp = (container: Element | string) => {
vue = createApp(App);
// vue.use(...)
vue.mount(container);
}
if (!isInIcestark()) runApp('#app');
// 这里的 container 就是主应用传入的容器
export function mount({ container }: { container: Element }) {
runApp(container);
}
export function unmount() {
if (vue) vue.unmount();
}
至此,一个简单的微前端应用就搞定了,但是目前两者都是单独运行的,也就是说除了浏览器提供的存储方式外,我们还需要应用之间能够通信,举一个简单的栗子:主应用有用户通知,进入消息子应用查看后需要刷新主应用的消息数量。
为此,@ice 还提供了一个 @ice/stark-data 实现应用间的通信,拥有 store 和 event, 具体的使用方式可以前往官网 @ice/dark-data 查看