背景
微前端大部分的应用都是以路由划分一个应用,当路由匹配时去加载对应应用,但是有些组件,不是在路由改变时加载,比如打开一个模态对话框,加载内容来自其它应用。
微前端框架 single-spa
Parcels是single-spa的一个高级特性,是一个与框架无关的组件,由一系列功能构成,可以被应用手动挂载,无需担心由哪种框架实现。Parcels 和 注册应用的 api 一致,不同之处在于 parcel 组件需要手动挂载,而不是通过 activity 方法被激活(即路由匹配激活)。
parcel 如何使用
Parcels 包含三个必须的生命周期函数(bootstrap, mount 和 unmount) 和一个可选的生命周期函数(update),可以使用 single-spa-react / single-spa-vue 实现 parcel
创建一个 parcel
import singleSpaVue from 'single-spa-vue';
import MyParcel from './pages/my-parcel/index.vue'
export const myParcel = singleSpaVue({
Vue,
appOptions: {
render(h) {
return h(MyParcel, {
name: this.name,
params: this.params
})
}
},
});
在另一个应用使用上边创建的 parcel
systemjs 加载 remote 资源,
在 html 中加入以下代码
<meta name="importmap-type" content="systemjs-importmap" />
<script type="systemjs-importmap">
{
"imports": {
"my-parcel": "https://url"
}
}
</script>
加载 parcel
window.addEventListener('single-spa:first-mount', function listener() {
System.import('my-parcel').then((parcelConfig) => {
// 存储 parcelConfig
})
window.removeEventListener('single-spa:first-mount', listener);
});
singleSpa.mountRootParcel 挂载 parcel
import { mountRootParcel } from 'single-spa'
const parcel = mountRootParcel(parcelConfig.myParcel, {
domElement: document.getElementById('parcelID'),
});
parcel.mountPromise.then(() => {
console.log('finished mounting parcel!')
// 如果我们想重新渲染parcel,可以调用update生命周期方法,其返回值是一个 promise
parcelProps.customProp1 = 'bar'
return parcel.update(parcelProps)
})
.then(() => {
// 在此处调用unmount生命周期方法来卸载parcel. 返回promise
return parcel.unmount()
})
此时,myParcel 组件将会挂载到另一个应用 dom id 为 parcelID的元素上
暂时还未实践 mountParcel 的方式挂载 parcel。
使用理解,在一个微应用 application 中,组件透传 mountParcel 方法,在需要挂载 parcel 的组件中,调用
System.import('my-parcel').then((parcelConfig) => {
props.mountParcel(parcelConfig.myParcel, {
domElement: document.getElementById('parcelID'),
})
})
此时会把 myParcel 挂载到对应 dom,如果该应用卸载,则 parcel 会被卸载,也可以手动卸载。
官方建议使用 mountParcel API
结语
灵活使用 parcel ,使跨框架应用可以共享组件,如果应用组件需要通信,建议使用 CustomEvent 进行通信。共享组件可能会遇到样式冲突,可以用 postcss-selector-namespace 增加样式作用域来解决等。
通过 iframe 也可以共享组件,但是用户体验不佳。