中后台越做越乱后,我用插件化把它救回来了

背景

公司里前端项目不少,我也试过几种组织方式,最后留下来的是这套插件化方案。原因不复杂: 商城、系统设置、报表这类模块边界已经很清楚了,继续全塞在宿主里,后面只会越来越乱。所以我把宿主收回到启动、布局和全局守卫,把业务域拆成 packages/plugin-*,再让插件通过统一协议交出自己的路由、菜单、多语言和初始化逻辑

文档地址、 演示地址

插件协议怎么定

ts 复制代码
export interface AdminPlugin {
  id: string // 插件唯一标识
  name: string // 插件名称
  version: string // 插件版本
  enabled?: boolean // 默认是否启用
  order?: number // 注册顺序
  dependsOn?: string[] // 依赖的插件 id
  routes?: AdminRouteRecordRaw[] // 插件提供的路由
  menus?: MenuConfig[] // 插件提供的菜单
  locales?: {
    'zh-CN'?: Record<string, any>
    en?: Record<string, any>
  } // 插件自己的语言包
  install?: (app: App, context: PluginContext) => void | Promise<void> // 初始化钩子
}

我比较在意的一点是,插件要把自己的边界说清楚,而不是嘴上说自己是"独立模块",代码里还在不停伸手改宿主,所以后面的插件架构要设计好,大概做了以下功能点

项目预览

插件功能点

  • 📦 定了一套统一的插件协议,把 id、name、version、enabled、order、dependsOn、routes、menus、locales、install 这些字段先收口
  • 🔢 插件注册排序,用 order 控制接入顺序
  • 🟢 默认启用控制,通过 enabled 配置插件初始状态
  • 🔗 依赖声明和依赖校验,避免插件在缺少前置模块时硬挂进来
  • 🛡️ 冲突检测,主要拦重复插件 id、路由 path / name 和菜单 path
  • 🧭 插件路由注册,把页面入口统一挂到宿主路由系统
  • 🗂️ 插件菜单收集,把各业务插件的导航配置汇总到宿主
  • 🌐 语言包合并,让插件自己的 locales 能注入到宿主
  • 🪝 install 钩子,方便插件做自己的初始化
  • 📋 运行时插件清单,宿主能拿到当前注册过的插件信息
  • 🔌 插件启停能力,支持在运行时打开或关闭某个插件
  • 💾 启停状态持久化到 localStorage
  • 🔄 刷新后恢复插件状态,宿主重新引导时继续使用本地启停结果

一个插件长什么样

ts 复制代码
const reportPlugin: AdminPlugin = {
  id: 'plugin-report',
  name: '报表插件',
  version: '1.0.0',
  order: 20,
  dependsOn: ['plugin-shop'],
  routes: [
    {
      path: '/report/list',
      name: 'ReportList',
      component: () => import('./views/ReportList.vue'),
      meta: {
        title: 'report.list',
        layout: 'default',
        permissions: ['report.read']
      }
    },
    {
      path: '/report/detail/:id',
      name: 'ReportDetail',
      component: () => import('./views/ReportDetail.vue'),
      meta: {
        title: 'report.detail',
        layout: 'default',
        permissions: ['report.read'],
        activeMenu: '/report/list',
        noCache: true,
        hidden: true
      }
    }
  ],
  menus: [
    {
      path: '/report',
      title: 'report.title',
      icon: 'chart',
      children: [
        {
          path: '/report/list',
          title: 'report.list'
        }
      ]
    }
  ]
}

这段代码最关键的地方,不是"能跑起来",而是它把自己该交给宿主的信息一次性带齐了。宿主看到这个插件,基本就知道要把什么东西接进去。

最后

做到这里之后,我最直接的感受就是,新增一个业务模块时,接入方式终于稳定下来了。对我来说,这就够了。至少这个中后台后面继续长的时候,不会再回到什么都往宿主里塞的状态。

相关推荐
wangxiaoxuan2171 小时前
SLAM 的基本结构:前端、后端、回环与地图优化
前端·机器人·科沃斯八界
Agent世界4 小时前
用 CDP 做发布自动化:四道机器闸门与产物验收
前端·javascript
FungLeo4 小时前
成为全栈·Vue 管理后台篇·编辑器图片上传:从文件选择到文章附件关联
前端·vue.js·编辑器·markdown·文件上传·formdata·附件管理
某哈压力大5 小时前
SSH 突然 Connection reset?不是密钥坏了,是 OpenSSL 把 sshd 干趴了
前端·node.js·命令行
程序员大阳5 小时前
副队长ES6+教程(3)--解构赋值
前端·javascript·es6·赋值·解构
神膘护体小月半5 小时前
css - 元素背景图由 hover 触发,初次加载时闪动的解决办法
前端·javascript·css
程序员大阳5 小时前
副队长ES6+教程(2)--let 与 const
前端·javascript·es6·const·let·var
deli0075 小时前
写满 200GB 后 SSD 为什么掉到 95MB/s?SLC 缓存模型实测
前端
曦樂~6 小时前
【Web Development】03JavaScript 基础和事件
开发语言·前端·javascript
deli0077 小时前
HTTPS 的锁是怎么挂上的?TLS 1.3 握手 6 步实测
前端