Engage 背景与定位 里,我们举了几个有关插件机制的现实需求及其例子。所谓插件,就是对标准功能的一种定制、扩展。插件必须运行在某个位置上(或者叫宿主环境),且其须满足一定的接口(如参数、结构等)。在 Engage 中,宿主环境的某个位置就叫做插槽,注入进来的就叫做插件。插槽由目标应用 Id、插槽标识构成唯一性,并定义了其需要的参数列表(类似函数里的形参)。插件则表明自己属于哪一个插槽,具体参数值是什么(类似函数里的实参),以及自己绑定的角色(权限)。参看下图:

在 Engage 中,插件分为如下几类:

  1. 前端插件
  2. 后端插件
  3. 混合插件

前端插件就是说目标应用的前端界面某个位置上支持插入组件,这样通过注入不同的插件,就能实现界面的定制化、扩展化。后端插件是指在某个流程逻辑中,注入一个新的接口,一般用以通知或提供数据。混合插件则表示既有前端的部分,又有后端的部分。

# 插槽、插件开发示例

假设现在我们自己有一个应用,名叫员工应用。在员工详情页面,我们可以支持一个插槽,显示该员工的各类关联信息。此时,有一个 BPM 应用,可以提供员工的各种流程审批信息。那么该怎么做呢?

首先,员工应用先设计一个插槽:

  • 插槽标识:employee-detail-v1
  • 参数列表:
    • component:表示插件的组件地址,通常是由微前端 + 组件名构成

在员工详情页面的渲染代码里,我们需要先查询所有注册到该插槽的插件列表,然后加载这些插件的微前端,并注册这些插件,最后进行渲染:

<template>
    <div v-if="employee">
        {{employee.name}}
        <div v-for="widget in widgets">
            <!-- 使用动态组件来加载插件的组件 -->
            <component :is="widget" :employeeId="id"/>
        </div>
    </div>
</template>
<script>
import 'promise-addition';
import {queryAppAddons} from '@engage/frontend';

export default {
    name: 'xxx',
    data(){ return { /* ... */ } },
    async created(){
        const addons = await queryAppAddons({applicationId: 'employee', type: 'employee-detail-v1'});
        this.widgets = await Promise.map(addons, addon=>{
            let component = addon.params.component; // component 就是参数列表里定义的参数
            let [mfeAppId, compName] = component.split('.');
            await loadMfeApp(mfeAppId); // 加载插件组件所在的微前端工程
            
            let compDef = window[mfeAppId][compName];
            Vue.component(compName, compDef); // 全局注册该组件。也可以局部注册,通过 this.constructor.options.components[compName] = compDef;

            return compName;
        })

        this.employee = await requestApi({ url: '/v1/employee/detail', body: {id: this.id} });
    }
}
</script>

在 BPM 应用,我们则需要开发一个组件,比如叫 EmployeeTask。然后在 BPM 应用发布时,注册一个到员工应用的插件即可。