微前端如何使跨框架应用共享组件(single-spa 之 parcel 使用)

472 阅读2分钟

背景

微前端大部分的应用都是以路由划分一个应用,当路由匹配时去加载对应应用,但是有些组件,不是在路由改变时加载,比如打开一个模态对话框,加载内容来自其它应用。

微前端框架 single-spa

Parcelssingle-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的元素上

single-spa 提供了两种挂载 parcel 的方式

暂时还未实践 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 也可以共享组件,但是用户体验不佳。