@melt-js/tpl-vue3-admin-ele-pure
v2026.11.8
Published
由 pure-admin-thin 提取的 Vue 3 + Element Plus 后台模板,公共组件改为从 comps-pure 远程加载
Maintainers
Readme
tpl-vue3-admin-ele-pure
由 pure-admin-thin 提取的 Vue 3 + Element Plus 后台模板(Vite 8 + Tailwind 4 + pinia + vue-router)。
与其他 tpl 包不同,本包不做成远程组件对外暴露:它就是一个普通的后台应用模板,只是把原仓库 src/components 里的公共组件、src/layout 里的布局抽到了远程包 comps-pure,运行时用 preFetchLib('comps-pure') 加载。构建产物会打包发布到 npm,用 unpkg 托管线上 demo(见发布到 unpkg)。
本包只是把上游 pure-admin-thin 的源码整理进 monorepo,请遵守上游的使用约定。
快速开始
# 终端 1:公共组件远程包(端口 20070)
pnpm comps-pure:dev
# 终端 2:后台模板(端口 50130)
pnpm tpl3-pure:dev打开 http://localhost:50130/,用户名 admin 或 common、密码任意(mock 登录见 mock/login.js:admin 拥有 *:*:* 权限,common 只有 permission:btn:add / permission:btn:edit)。
pnpm build # 产物在 dist/,远程组件地址切到 unpkg 上的 hel-meta.json
pnpm preview # 预演 dist(50140)发布到 unpkg
# 发布前先按仓库 calver 规则把 package.json 的 version 改成今天(如 2026.11.7)
pnpm --filter @melt-js/tpl-vue3-admin-ele-pure run publish:stage线上入口:https://unpkg.com/@melt-js/tpl-vue3-admin-ele-pure/dist/index.html(unpkg 字段已指向它,直接访问包名也会跳转)。
publish:stage=pnpm run build && npx -y npm@11 stage publish,只把版本暂存到 npm;执行npm stage list --registry=https://registry.npmjs.org拿到 stage id 后,还要npm stage approve <stage-id>才真正上线;files白名单只发布dist/、README.md、LICENSE,不含源码与mock/源码;mock 会随产物打进dist,所以打开线上页面即可用admin/ 任意密码登录;publishConfig.registry指向https://registry.npmjs.org,仓库根.npmrc的 npmmirror 只读镜像不参与发布。
公共组件为什么在远端
原仓库的 src/components 是一个「宿主强耦合」的组件目录:ReAuth 依赖 @/router/utils 的 hasAuth、RePerms 依赖 @/utils/auth 的 hasPerms、PureTableBar 依赖 @/store/modules/epTheme 的主题色。抽到 comps-pure 后:
- 这些宿主能力改成运行时注入:
lib.setupPureRuntime({ hasAuth, hasPerms, getEpThemeColor })(src/remote/setup.js); - 组件包不 import 宿主的任何模块,因此可以独立调试(未注入时权限默认放行);
- 模板不再把
ReIcon/ReDialog/ReText/ReSegmented/PureTableBar/Auth/Perms打进自己的产物。
模板里的用法保持不变:
| 位置 | 用法 |
| --- | --- |
| src/main.js | 固定启动骨架:bindVueRuntime → loadRemoteComps → 平台配置 → setupStore → setupRemoteComps → app.use(router) → storage / 插件 → router.isReady → mount(远程包必须在路由首次导航前就绪) |
| src/remote/setup.js | 预加载远程包、注入 hasAuth / hasPerms / getEpThemeColor / 布局能力 / 工具用户 store、注册远程指令、全局注册 10 个组件 |
| src/remote/index.js | 函数式 API 的本地代理:useRenderIcon / addDialog / closeDialog / closeAllDialog / addOfflineIcons(远程包就绪前会缓存离线图标注册);路由级布局 / 异常页用 defineRemoteRoute 等同一个 preFetchLib Promise |
| src/plugins/offlineIcons.js | 把路由 / mock 用到的图标(ep:home-filled、ep:lollipop、ri:search-line 等)交给远程包的 addOfflineIcons 预注册,断网时图标也能显示 |
| src/App.vue | <ReDialog /> 直接用全局组件;closeAllDialog 走本地代理 |
| src/layout/** | 只剩 types.js(routerArrays 常量);路由组件直接在 src/router/modules/*.js 里 defineRemoteRoute("ReLayout") / defineRemoteRoute("LayFrame") / defineRemoteRoute("LayRedirect"),布局 hooks 直接用 lib.useNav() / lib.useLayout() 等 |
| src/utils/** | 只剩 auth.js 的常量(userKey / TokenKey / multipleTabsKey);message / http / progress / mitt / responsive 等转发文件已删除,调用处直接使用 lib.xxx |
| src/directives/** | 已删除;v-auth / v-perms 等由 setupRemoteComps 从 lib.directives 统一注册 |
| src/plugins/elementPlus.js | 已删除;lib.setupElementPlus(app) 按 window.ElementPlus 命名空间自动注册,2.14 新增组件无需改模板 |
| src/config/index.js | 只保留 getPlatformConfig(依赖 VITE_PUBLIC_PATH + axios);getConfig / setConfig 转发到远程 config |
| src/views/error/*.vue | 已删除;/error/403|404|500 等路由直接 defineRemoteRoute("Error403/404/500"),页面与插画在远程包 |
| src/style/** | transition.scss / element-plus.scss / dark.scss 已移到远程包;reset.scss / sidebar.scss / theme.scss / tailwind.css 属于本模板主题体系,保留 |
远程组件只有一个入口:src/remote/
所有「知道组件来自远程」的代码都收在这里,以后同步公共组件只需要动这个目录:
src/remote/
config.js 远端地址推导(dev 用 http://localhost:20070,build 用 unpkg 上的 hel-meta.json)+ preFetchLib
setup.js 启动期注入:bindVueRuntime / element-plus / setupPureRuntime / setupLayoutRuntime / setupUtilsRuntime / 全局组件 / 指令
index.js 业务侧访问器(getRemoteComps / defineRemoteRoute / addOfflineIcons ...)业务代码不需要感知远程。comps-pure 的包入口就是 hel 的 exposeLib 代理,
preFetchLib 完成后可以像普通 npm 包一样使用:
import lib from "@melt-js/comps-pure";
lib.useRenderIcon("ri:search-line"); // 函数
lib.addDialog({ title: "..." }); // 弹窗
lib.getStaticUrl("static/bg.png"); // 远程包托管的静态资源组件本身在 setupRemoteComps 里已全局注册,模板里直接写 <ReText /> / <Auth /> / <ReDialog />,
既不需要 import、也不需要 defineRemoteRoute(后者只用于路由级懒加载的布局与异常页,
作用是等同一个 preFetchLib Promise,避免首屏直接刷新布局路由时抢跑)。
布局也在远端
src/layout 的实现已经搬进 comps-pure/src/layout,本模板不再保留适配层:
- 路由组件:在
src/router/modules/*.js里直接defineRemoteRoute("ReLayout")/defineRemoteRoute("LayFrame")/defineRemoteRoute("LayRedirect"); - 布局 hooks:在使用的页面直接
lib.useNav()/lib.useLayout()/lib.useTags()/lib.useDataThemeChange(),不再经过src/layout/hooks/*; src/layout/types.js保留routerArrays常量(依赖VITE_HIDE_HOME),由setupLayoutRuntime回传。
布局需要的 pinia store / router / i18n / 主题 / 头像等能力,在 src/remote/setup.js 的 setupRemoteLayout(lib) 里通过 lib.setupLayoutRuntime({...}) 注入。精简版的能力开关是 features: { i18n: false, watermark: true },与完整版共用同一份布局实现。原来 src/layout/index.vue 里全局引入的 animate.css、@/plugins/offlineIcons 已移到 src/main.js。
公共工具 / 指令也在远端
除布局外,两个模板重复的工具与指令也合并进了远程包:
src/utils/**只保留auth.js的常量;message/http/progress/print/localforage/preventDefault/responsive的转发文件已删除,调用处直接使用lib.message/lib.http/lib.NProgress/lib.injectResponsiveStorage等;src/utils/tree.js直接删除,改用@pureadmin/utils的同名树工具;src/directives/**删除,auth/perms/copy/longpress/optimize/ripple从lib.directives注册;src/plugins/elementPlus.js删除,改由远程lib.setupElementPlus(app)自动注册(不再维护 2.14 的组件长列表);src/plugins/echarts.js未被任何页面引用,已删除;src/views/error/**只保留适配层,异常页与插画在远程包;src/assets/status删除;src/config/index.js只保留getPlatformConfig,配置读写走远程config;完整版 i18n 初始语言在配置加载后调用initI18nLocale();src/style/中两个模板一致的transition.scss/element-plus.scss/dark.scss移到远程包,reset.scss/sidebar.scss/theme.scss/tailwind.css留在模板;- 登录态 / HTTP 需要读写用户 store,由
lib.setupUtilsRuntime({ useUserStoreHook })注入。
固定启动骨架
src/main.js 两个模板保持同一顺序,业务开发只需要改 views/ / api/ / 路由与 store:
bindVueRuntime({ Vue }); // 1 共享 vue 运行时
setRemoteComps(await loadRemoteComps()); // 2 预加载远程组件
const config = await getPlatformConfig(app); // 3 平台配置
setupStore(app); // 4 pinia
await setupRemoteComps(app); // 5 注入纯/布局/工具运行时 + 注册指令/组件
app.use(router); // 6 首次导航(守卫已可用远程 auth/http)
injectResponsiveStorage(app, config); // 7 storage / UI 插件
app.use(MotionPlugin).use(Table).use(VueTippy);
await router.isReady();
app.mount("#app");关键点:远程包必须在 app.use(router) 之前就绪,因为首次导航的守卫会调用远程的 removeToken / NProgress / http。
远端地址按环境选择(src/configs/remote.js):开发 http://localhost:20070,构建 https://unpkg.com/@melt-js/comps-pure/hel_dist/hel-meta.json,可用 VITE_REMOTE_HOST 覆盖(例如指向自己部署的 hel-meta.json)。远程包加载失败时,main.js 会渲染一个带远端地址与错误原因的兜底页,不会白屏。
与上游仓库的差异
- 删除
src/components/**(已抽到comps-pure)与src/assets/table-bar/**(随PureTableBar一起搬走); - 删除
src/layout/components/**与布局 hooks 的具体实现(已抽到comps-pure/src/layout),本地只保留index.vue/frame.vue/redirect.vue适配层、hooks/*转发和types.js; - 布局的宿主依赖改成运行时注入(
lib.setupLayoutRuntime):store / router / 平台配置 / 头像 / emitter 等从src/remote/setup.js传入;布局图标已内联到远程包,不再依赖vite-svg-loader/unplugin-icons; - 原
src/layout/index.vue里的animate.css、@/plugins/offlineIcons移到src/main.js,避免异步布局加载时主题动画和图标注册滞后; src/plugins/offlineIcons.js预注册路由 / mock 用到的 4 个图标,断网时菜单图标也能显示;src/utils/**与src/directives/**的公共实现已抽到comps-pure:utils 只保留auth.js常量,其余转发文件删除、调用处直接用lib.xxx;directives 目录删除、改由lib.directives注册;src/utils/tree.js删除(改用@pureadmin/utils);- axios 实例、拦截器、mock
{ success, data }兼容、NProgress 都在远程包,API 模块直接lib.http.request/get/post,不再保留本地http转发文件; src/plugins/elementPlus.js/src/plugins/echarts.js删除:element-plus 由远程包自动注册,echarts 插件模板中无引用;src/views/error/*.vue改为远程组件适配层,src/assets/status删除;src/style/transition.scss、element-plus.scss、dark.scss移到远程包;- 随代码迁到远程包的依赖(
pinyin-pro/path-browserify/echarts/localforage/mitt/nprogress/qs/responsive-storage,以及本模板未使用的dayjs)已从package.json移除; - 删除 husky / commitlint / lint-staged / Dockerfile /
.dockerignore/ 上游.npmrc(monorepo 用根目录统一管理),保留 eslint / prettier / stylelint 配置与脚本; - 端口写死为 50130(dev)/ 50140(preview),并在根目录
ports.json登记; build/info.js打包信息插件改用writeBundle:Vite 8(rolldown)在closeBundle时产物可能还没落盘,统计dist会抛 ENOENT 把构建带崩;- 删除
.browserslistrc,只保留package.json的browserslist(两者同时存在会让cssnano报 "contains both .browserslistrc and package.json with browsers"); vite.config.js增加watch.ignored: [/\.tmpdir([\\/]|$)/]:Windows 上 chokidar 命中原子写入的临时目录会抛 EBUSY 把 dev server 带崩;.env.production的VITE_PUBLIC_PATH为./:配合 hash 路由,dist/index.html从任意层级的路径(如 unpkg)打开都能加载同目录资源;部署到服务器根目录时改回/也可以。
目录结构(只列关键项)
build/ 打包插件(tailwind / jsx / icons / fake-server / 压缩 / 构建信息)
mock/ 登录与动态路由 mock
public/ favicon、logo、platform-config.json
src/
api/ 接口
layout/ types.js(routerArrays 常量);布局组件由 defineRemoteRoute 直接加载
plugins/ element-plus 按需注册、远程组件接入、离线图标
remote/ config.js / setup.js / index.js(远程包唯一入口)
router/ 静态 / 动态路由(ReLayout / LayFrame / LayRedirect 用 defineRemoteRoute)
store/ pinia
style/ 重置 / element-plus / tailwind / 暗色
utils/ 仅 auth.js 常量;其余工具直接调用 lib.*
views/ login / welcome / permission / error端口
| 用途 | 端口 |
| --- | --- |
| dev(pnpm dev) | 50130 |
| preview(pnpm preview) | 50140 |
| 依赖的远程组件 comps-pure | 20070 |
