A Plugin Protocol That Stops Admin Panels from Turning into Monoliths
Background
The company has quite a few front-end projects, and I've tried several organizational approaches. In the end, this plugin-based solution is the one that stuck. The reason is straightforward: modules like the mall, system settings, and reports already have clear boundaries. If you keep stuffing everything into the host, it will only get messier. So, I pulled the host back to just startup, layout, and global guards, split the business domains into
packages/plugin-*, and then let the plugins hand over their routes, menus, multi-language, and initialization logic through a unified protocol.
Documentation Demo Source Code
How the Plugin Protocol is Defined
export interface AdminPlugin {
id: string // Unique plugin identifier
name: string // Plugin name
version: string // Plugin version
enabled?: boolean // Whether it is enabled by default
order?: number // Registration order
dependsOn?: string[] // IDs of plugins it depends on
routes?: AdminRouteRecordRaw[] // Routes provided by the plugin
menus?: MenuConfig[] // Menus provided by the plugin
locales?: {
'zh-CN'?: Record<string, any>
en?: Record<string, any>
} // The plugin's own language pack
install?: (app: App, context: PluginContext) => void | Promise<void> // Initialization hook
}
One thing I care about a lot is that a plugin must clearly state its own boundaries, rather than verbally claiming to be an "independent module" while its code keeps reaching out to modify the host. So, the subsequent plugin architecture needed to be well-designed, and I roughly implemented the following features.
Project Preview
Plugin Features
- 📦 A unified plugin protocol was defined, first consolidating fields like
id,name,version,enabled,order,dependsOn,routes,menus,locales, andinstall. - 🔢 Plugin registration ordering, using
orderto control the sequence of integration. - 🟢 Default enable/disable control, configuring the initial state of a plugin via
enabled. - 🔗 Dependency declaration and dependency validation, preventing a plugin from being forcibly mounted when its prerequisite modules are missing.
- 🛡️ Conflict detection, mainly blocking duplicate plugin
ids, routepath/names, and menupaths. - 🧭 Plugin route registration, uniformly mounting page entry points to the host routing system.
- 🗂️ Plugin menu collection, aggregating the navigation configurations from various business plugins into the host.
- 🌐 Language pack merging, allowing a plugin's own
localesto be injected into the host. - 🪝 The
installhook, making it convenient for a plugin to perform its own initialization. - 📋 A runtime plugin manifest, so the host can access information about currently registered plugins.
- 🔌 Plugin start/stop capability, supporting enabling or disabling a specific plugin at runtime.
- 💾 Persistence of the start/stop state to
localStorage. - 🔄 Restoration of the plugin state after a refresh, so the host continues using the local start/stop results upon re-bootstrapping.
What a Plugin Looks Like
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'
}
]
}
]
}
The most critical part of this code isn't that "it can run," but that it brings all the information the host needs in one go. When the host sees this plugin, it basically knows what to integrate.
Final Thoughts
After reaching this point, my most direct feeling is that the integration method for adding a new business module has finally stabilized. For me, that's enough. At least when this admin panel continues to grow, it won't fall back into the state of stuffing everything into the host.
Top 3 of 9 from juejin.cn, machine-translated. The original thread is authoritative.
I'd like to ask, will this project be open-sourced? I've been free lately and happened to come across your blog, and I'd like to learn from it [rose][rose][rose]
It's already open-sourced, wow
The pm-web-admin-next repository isn't open-sourced
Is it similar to an npm package?
Yeah, it can be made into a package
It's not easy to extend, and it tends to overcomplicate simple tasks.