# 扩展点的设计原则

重要提醒

  • 扩展点的设计很重要,在插件化开发过程中需要严格按照规范进行设计。
  • 扩展点一旦定义,项目中禁止删除或修改,仅可新增功能点。
  • ⭐️⭐️⭐️⭐️⭐️ 扩展点的层级只能有一层,不可以嵌套的形式进行使用;一旦存在嵌套,其维护和变更成本将呈几何形式上升。
# 插件的意义是旨在解决后续项目升级问题,所以须保证插件的独立性。本篇主要介绍在实际插件化项目中插件独立性的checklist

扩展点的设计原则

# 扩展点的颗粒度

简介:扩展点的颗粒度的大小依据于业务的定制化差异大小。在确定扩展点的颗粒度大小时,推荐以下两种方式:

# 1. 布局型扩展点【根据页面布局挖取扩展点】

布局型扩展点

  • 优势
    • 上手简单,覆盖面广:单一页面仅需维护极少的扩展点即可覆盖所有的定制化需求。
    • 高内聚:扩展点通常将相关的功能、状态和样式集中在一起管理;使代码更加内聚,易于理解和维护。
    • 变更成本低:可在当前扩展点内定制各种大小需求,无需担心扩展点的变更问题。
  • 劣势
    • 开发/维护成本高:大型扩展点可能会存在与主应用相同的大量的重复代码。例如:若顶部扩展点某个按钮的功能是定制化功能时,整个顶部扩展点都需要定制一份;当主应用的顶部扩展点(除按钮的功能)功能进行优化升级时,定制的扩展点也需要进行优化升级。
    • 依赖关系深入:大型扩展点可能与其他扩展点或宿主有深层次的依赖关系(如:数据、指令集等),引入时的复杂度增加。
    • 体积过大:大型扩展点通常包含大量的代码和资源,会导致前端包的体积过大,影响页面的加载性能。
  • 适用场景:适用于定制化功能比较集中、比较复杂,定制化区域比较大的场景

# 2. 功能型扩展点(根据定制功能点挖取扩展点 例如:签署页)

功能型扩展点

  • 优势
    • 开发/维护成本低:小型扩展点通常只关心某一特定功能,代码简洁,易于理解和维护。
    • 依赖关系清晰:小型扩展点通常不涉及过多的外部依赖,减少模块之间的复杂关系,便于定制和维护。
    • 轻量化:小型扩展点的体积较小,减少网络传输和页面加载时间,提升用户体验。
  • 劣势
    • 组合复杂性增加:当宿主需要组合使用多个扩展点时,可能需要编写更多的代码和逻辑来实现复合功能。
    • 变更成本大:当扩展点无法满足定制化需求,需要进行变更时(即扩展点小变大),会增加更多的开发、测试成本。
  • 适用场景:定制化功能比较分散、比较简单;定制化区域比较小的场景

# 扩展点的变更流程

功能型扩展点

# 数据store

  1. store设计需要语义化,参数字段需要平铺细化,后期影响范围可追溯(包括给插件提供路由中的传递参数);
  2. 不能直接包一个无语义化的对象。
  3. 插件中禁止直接通过storage(local/session/cookie)的方式获取或设置主应用中缓存的数据,必须通过指令集的方式由主应用提供。插件中的临时存储除外

# 指令集

提示

指令集命名需要语义化,类似open-api,一旦暴露需要固化

# 1. 指令集按通用性分类

工具类(util)  
流程类(process)  
event类(event)  
上行数据方法(uplink)  

# 2. 命名规范: 扩展点名称-指令类型-业务特性

例:login-page-epu-event-login

# 3. 扩展点与指令集设计原则

一对一(即 一个扩展点对应一个指令集),例如 扩展点home-page-body-epu对应的指令集如下:

/**
 * 指令集命名规范:扩展点名称-指令类型-业务特性(例如:登录页扩展点-流程类-登录)
 */
const global: any = window

/**
 * 工具类指令集
 */
const utilsApi = {}

/**
 * 流程类指令集
 */
const processApi = {}

/**
 * event指令集
 */
const eventApi = {
  toSealList: () => {
    // 点击前往印章列表
    global.esignbridge.$eventEmitter.emit('home-page-body-epu-event-sealClick')
  },
}

/**
 * 上行数据
 */
const uplinkApi = {}

export default { ...eventApi, ...utilsApi, ...processApi, ...uplinkApi }

# 4. npm的独立性,插件&主应用独自依赖,可升级

i. 基线指令通过import引入指令集监听处理
ii. 插件通过window.esignbridge.xxx调用指令集

# 5. 路由触发

插件中不能直接调用主应用的路由跳转,需要通过指令集通知主应用,由主应用进行跳转(因为主应用的router name或path是可变的,插件不能直接触及,即防止后续升级插件不可用

# 依赖独立性

# 多语言

# 组件

# 工具类

# 接口API

i. 调用基线能力,使用指令集
ii. 调用插件能力,使用基线http封装对象

# 扩展点属性

# 1. 空逻辑

基线扩展点支持空逻辑,即基线实现逻辑扩展点而不实现插件,也不阻塞业务流程

# 2. 宽度、高度等

UI类扩展点需要有对应的宽度高度等样式属性

# 插件包体积

影响性能

# 1. 图片资源--base64

# 2. 剔除包含多余的三方依赖

# window挂载对象覆盖(待开发)

# js沙箱隔离

# css样式覆盖

问题:主应用中引入elementUI样式后并重写覆盖某些样式,插件中也单独引入了elementUI及其样式,因css权重问题导致插件中引入的样式覆盖主应用中的样式。

解决方案:通过修改编译后的插件所使用的基础组件的前缀,解决样式覆盖问题。@esign/css-prefix-webpack-plugin

警告事项

插件中基础组件的局部注册,建议以 双驼峰 命名发进行注册。 例如:

import { Button } from 'element-ui'

...... /* 省略代码 */
components: {
  ElButton: Button
}
...... /* 省略代码 */
上次更新: 8/28/2023, 9:52:35 AM