前言
背景
在前端开发场景中,我们常需搭建各类中后台系统,功能看似多样,核心却多为 CRUD 页面。这类重复性开发不仅效率低下,对个人技术能力的提升也毫无帮助。
更关键的是,多数中后台系统仅存在细微差异 —— 以电商系统为例,首次开发可能包含商品管理、订单管理、会员管理与优惠管理模块,而后续需要开发新的电商系统,它的需求或许仅新增一个分销管理模块,基础功能并无本质变化。
我们这时候,往往重新开发或对旧项目进行 “魔改”,既浪费大量时间,又缺乏技术突破的价值。尤其在 AI 技术飞速发展的当下,若长期局限于这类低技术含量的业务开发,个人竞争力必然会持续下降。
如何解决此问题呢?
elpis 全栈框架里 —— 领域模型 + BFF Serve+Dashboard 模板页 为核心,构建一套可复用、高灵活的解决方案,让中后台开发从 “重复CRUD” 转向 “配置化搭建”。
领域模型是整个方案的 “蓝图引擎”:基于 JSON Schema 定义系统核心结构,不仅能描述基础功能模块(如订单管理、商品管理),还支持通过 “基类 + 子类” 的层级设计拓展个性化需求。比如电商场景中,“订单管理 + 商品管理” 可作为通用基类,电商 A 需新增的 “优惠券管理”、电商 B 需补充的 “分销管理”,则可作为子类灵活挂载。
BFF Serve 扮演 “桥梁与驱动” 的角色:提供 SSR 服务,实例化项目,API接口服务
Dashboard 模板页是 “可视化呈现终端”:无需单独开发页面,只需接收 BFF 层传递的领域模型配置,就能自动渲染出符合业务需求的系统界面。
举个实际例子:搭建电商 A 系统时,我们只需在领域模型中配置 “基类(订单管理 + 商品管理)+ 子类(优惠券管理)”;启动系统后,BFF Serve 会读取这份配置并同步给 Dashboard 模板页,最终呈现的电商 A 系统,就自带 “订单管理 + 商品管理 + 优惠券管理” 全套功能。搭建电商 B 系统同理,仅需调整领域模型为 “基类 + 子类(分销管理)”,即可快速生成包含分销功能的电商系统 —— 全程无需重写代码,仅靠配置领域模型,就能实现中后台系统的快速搭建。
里程碑一 基于 nodejs 实现服务端内核引擎
elpis 全栈框架的第一步,便是以 Node.js 构建 BFF Serve 层 —— 对我们而言,Node.js 具备天然的技术适配性,上手门槛更低。
但传统 Node 开发中,团队常陷入 “目录结构不统一”“编码规范难落地”“中间件使用无规则” 的困境:路由该放在哪个目录?服务逻辑与配置管理如何拆分?这些问题往往消耗大量沟通成本。因此,elpis 框架基于 Koa 封装了 elpis-core 引擎,通过预设规范与自动化能力,把开发者从基础搭建中解放出来,只需专注业务开发。
一、规范目录与自动化加载
elpis-core 引擎以 “约定优于配置” 为原则,定义了清晰的项目目录结构,所有模块按功能归类,无需团队反复协商存放位置:
elpis
|-- app/ # 核心业务目录(按约定存放业务模块)
| |-- controller/ # 控制器层:处理请求、调用服务、返回响应
| |-- extend/ # 扩展层:全局能力扩展(如工具函数、API 增强)
| |-- middleware/ # 中间件层:局部中间件(如接口权限校验)
| |-- public/ # 静态资源层:存放静态文件
| |-- router/ # 路由层:定义“请求路径→控制器”映射关系
| |-- router-schema/ # 路由校验层:用 JSON-Schema 定义接口参数规则
| |-- service/ # 服务层:封装数据处理、第三方接口调用(供控制器复用)
| |-- middlewares.js # 全局中间件配置:注册全链路生效的中间件
|-- config/ # 配置目录:区分本地/测试/生产环境的差异化配置
|-- elpis-core/ # 引擎内核:提供自动加载、环境适配等核心能力
| |-- loader/ # 加载器集合:对应各模块的自动化加载逻辑
| | |-- config.js # 配置加载器:自动加载 config 目录下的环境配置
| | |-- controller.js # 控制器加载器:自动加载 controller 模块并挂载
| | |-- extend.js # 扩展加载器:自动加载 extend 层的全局能力
| | |-- middleware.js # 中间件加载器:自动加载 middleware 模块
| | |-- router-schema.js # 路由校验加载器:自动加载接口参数校验规则
| | |-- router.js # 路由加载器:自动加载路由映射关系
| | |-- service.js # 服务加载器:自动加载 service 层的业务逻辑
| |-- env.js # 环境判断工具:快速区分本地/测试/生产环境
| |-- index.js # 引擎入口:整合所有加载器、初始化 Koa 实例
|-- index.js # 项目入口:一键启动 elpis 引擎
其中,加载器(loader) 是自动化的核心:每个模块(如 controller、service、router)都对应专属加载器,加载器会主动遍历目标目录、解析文件内容,并将模块自动挂载到 Koa 实例上。以控制器加载为例,整个流程完全无需手动干预:
- 读取
elpis/app/controller/**/*.js下所有文件; - 提取文件名称与路径,如
app/controller/custom-module/custom-controller.js; - 截取路径核心部分,得到
custom-module/custom-controller; - 将路径中的 “-” 转为驼峰式命名,即
customModule.customController; - 自动挂载到内存
app对象中
从启动到请求的全链路优化
固定启动顺序,避免模块依赖混乱
elpis-core 引擎定义了严格的模块启动顺序,确保各模块按依赖关系加载,避免 “未定义” 错误:
配置环境 → 加载配置 → 扩展加载 → 中间件加载 → 服务加载 → 控制器加载 → 全局中间件注册 → 路由模式加载 → 路由注册
从环境判断到路由生效,每一步都由引擎自动执行,开发者无需手动管理加载顺序。
环境与路由的精细化管理
- 环境配置:通过
elpis-core/env.js实现环境变量统一管理,可快速区分本地开发、测试、生产环境,配置文件按环境拆分后,加载器会自动匹配当前环境并加载对应配置; - 路由管理:结合 JSON-Schema 定义路由参数规则,不仅能自动校验请求参数合法性,还能让接口文档与代码逻辑保持一致,减少 “文档与实际接口不匹配” 的问题;
- 请求响应链路:通过 “路由→控制器→服务→中间件” 的链路设计,实现请求处理的解耦:路由负责映射路径,控制器负责请求分发,服务负责业务逻辑,中间件负责通用能力(如权限校验、日志记录)。
可扩展的生态能力
elpis-core 引擎支持自定义插件与功能扩展:
- 插件机制:可接入多个自定义插件,满足个性化业务需求(如日志插件、监控插件);
- 功能扩展:通过
extend层可扩展全局能力,如新增工具函数、增强 API 响应格式等,扩展内容由加载器自动生效,无需修改引擎核心代码。
里程碑二 基于 webpack5 完成工程化建设
作为 elpis 全栈框架的第二步,本阶段核心是为前端 Dashboard 模板页搭建工程化基础,通过拆分 webpack 配置实现 “环境差异化构建”,同时适配服务端渲染与 Vue3 技术栈需求。
一、配置拆分:按环境解耦,兼顾开发与生产
将 webpack 配置拆分为三类,通过 dev.js 和 prod.js 分别调用,实现不同环境的自动化构建:
webpack.base.js:基础配置(基类),定义入口、loader、插件、分包策略等通用逻辑,避免重复编码;webpack.dev.js:开发环境配置,侧重热更新(HMR)、SourceMap 等提升开发效率的能力;webpack.prod.js:生产环境配置,聚焦打包优化(多线程、资源压缩、缓存清理),保障线上性能。
二、核心配置实现:从入口到优化的全链路适配
1. 基础配置(webpack.base.js):适配服务端渲染的核心逻辑
(1)入口处理:动态识别多页面入口
区别于普通前端项目的固定入口,框架通过 glob 匹配 app/pages/**/entry.*.js(如 entry.dashboard.js),自动生成入口配置与 HTML 模板,适配服务端渲染场景(用户访问 http://ip:port/view/xxxx 时,服务端返回主页面,其他页面由 Vue Router 渲染):
js
// 1. 匹配所有 entry.xx.js 入口文件
const elpisEntryList = path.resolve(__dirname, "../../pages/**/entry.*.js");
// 2. 构造入口与 HTML 模板
glob.sync(elpisEntryList).forEach(file => {
const entryName = path.basename(file, ".js");
// 入口配置:key 为入口名,value 为文件路径
elpisPageEntries[entryName] = file;
// HTML 模板:指定输出路径、模板文件与注入的代码块
elpisHtmlWebpackPluginList.push(new HtmlWebpackPlugin({
filename: path.resolve(process.cwd(), "./app/public/dist/", `.tpl`),
template: path.resolve(__dirname, "../../view/entry.tpl"),
chunks: [entryName]
}));
});
// 最终入口配置
entry: elpisPageEntries,
(2)loader 配置:适配 Vue3 + Less 技术栈
针对 Vue 单文件组件、ES6 语法、样式与静态资源,配置专属 loader,确保代码正常解析:
rules: [
{ test: /.vue$/, use: "vue-loader" }, // 解析 Vue 文件
{ test: /.js$/, include: [pages目录], use: "babel-loader" }, // 转译 ES6
{ test: /.(png|jpg|gif)$/, use: { loader: "url-loader", options: { limit: 300 } } }, // 小图转 base64
{ test: /.css$/, use: ["style-loader", "css-loader"] }, // 解析 CSS
{ test: /.less$/, use: ["style-loader", "css-loader", "less-loader"] }, // 解析 Less
{ test: /.(eot|woff|woff2|svg|ttf)$/, use: "file-loader" } // 解析字体
]
(3)插件与优化:保障基础功能与性能
-
插件:配置
VueLoaderPlugin(解析 Vue 组件)、DefinePlugin(定义 Vue 全局常量,如禁用生产环境调试工具),并注入动态生成的 HTML 模板; -
分包策略:通过
splitChunks将代码分为三类,利用浏览器缓存减少重复加载:vendor:第三方依赖(如 Vue、Vue Router),改动频率低;common:业务公共组件(如common/widgets目录),被引用 ≥2 次即抽取;entry.{page}:页面私有业务代码,改动频率高。
2. 开发环境配置(webpack.dev.js):聚焦开发效率
核心实现三项能力:
- HMR 热更新:在入口中注入 HMR 客户端,结合
HotModuleReplacementPlugin,实现代码改动后局部更新,无需刷新页面; - SourceMap:配置
eval-cheap-module-source-map,快速定位错误且保障构建速度; - 输出规范:指定开发环境输出目录(
./app/public/dist/dev/),统一资源路径格式。
3. 生产环境配置(webpack.prod.js):聚焦线上性能
通过多插件组合实现优化:
- 多线程打包:使用
HappyPack开启多线程(线程数 = CPU 核心数),并行处理 JS 与 CSS,提升打包速度; - 资源压缩:
TerserWebpackPlugin压缩 JS(删除console.log)、CSSMinimizerPlugin压缩 CSS,减少资源体积; - 缓存清理:
CleanWebpackPlugin打包前清空public/dist目录,避免旧资源残留; - CSS 提取:
MiniCssExtractPlugin将 CSS 从 JS 中提取为单独文件,支持缓存复用。
三、页面入口逻辑:衔接 Vue 应用初始化
框架约定 app/pages 目录下的核心文件,实现 Vue 应用的自动化挂载:
boot.js:类比普通 Vue 项目的main.js,负责初始化 Vue 实例;entry.dashboard.js(如app/pages/dashboard/下):聚合路由配置与待挂载组件,调用boot(dashboard, { routes })完成应用启动。
里程碑三 基于 vue3 完成领域模型架构建设
作为 elpis 全栈框架解决前端 CRUD 重复开发的核心环节,本阶段聚焦 “用配置驱动页面”—— 基于领域模型 DSL 与 JSON Schema 定义页面结构,让中后台系统从 “手动编码开发” 转向 “配置化渲染”,彻底摆脱重复编写 CRUD 页面的低效模式。
一、核心选择:为何用 JSON Schema 承载领域模型?
选择 JSON Schema 作为领域模型的配置格式,核心源于其三大优势:
- 领域适配性强:作为特定领域的标准 JSON 格式,可精准描述中后台页面的 “字段属性、交互逻辑、组件关联”,比如一个 “商品价格” 字段,能同时定义其数据类型(number)、校验规则(30≤价格≤1000)、表格展示格式(保留 2 位小数)、表单组件类型(数字输入框);
- 校验能力完善:可结合 AJV(Another JSON Schema Validator)工具,自动校验前端输入数据与后端返回数据的合法性,减少手动编写校验逻辑的工作量;
- 扩展性灵活:支持嵌套配置、条件渲染等复杂场景,既能覆盖基础 CRUD 页面,也能适配带个性化交互的定制页面,无需修改框架核心逻辑。
二、领域模型架构:页面的 “配置化蓝图”
elpis 框架通过 JSON Schema 将中后台系统拆解为 “导航菜单 + 动态页面” 两大核心板块,每个板块的功能与交互均由配置定义,无需编写重复代码:
1. 整体架构拆解
-
导航菜单:定义系统的模块结构,支持多级菜单(如 “商品管理”“订单管理”),并关联对应的页面类型(Schema 渲染页 /iframe 嵌入页 / 自定义页);
-
动态页面:分为三类核心页面,覆盖中后台 90% 以上的场景:
- schema-view:核心 CRUD 页面,由 “搜索栏(search-bar)+ 表格(table)” 组成,表格关联 “新增 / 编辑 / 详情 / 删除” 等弹窗交互;
- iframe:嵌入外部页面(如第三方数据报表、旧系统页面),仅需配置嵌入路径;
- custom:用户自定义页面,支持关联自定义 Vue 组件路径,满足特殊交互需求。
2. 核心配置示例(以电商系统 “商品管理” 为例)
通过一份 JSON 配置,可完整定义 “商品管理” 模块的菜单、表格字段、搜索组件、表单交互,示例如下:
js
module.exports = {
model: 'dashboard', // 模型标识,关联系统整体配置
name: '电商系统', // 系统名称,用于页面标题展示
menu: [ // 导航菜单配置
{
key: 'product', // 菜单唯一标识
name: '商品管理', // 菜单显示名称
menuType: 'module', // 菜单类型(模块级)
moduleType: 'schema', // 页面类型(Schema 渲染页)
schemaConfig: { // Schema 页面核心配置
api: '/api/proj/product', // CRUD 接口地址(增删改查统一关联)
schema: { // 字段属性定义(覆盖表格、表单、搜索栏)
type: 'object',
properties: {
// 商品ID:表格展示、编辑时禁用输入
product_id: {
type: 'string',
label: '商品ID',
tableOption: { width: 300, 'show-overflow-tooltip': true },
editFormOption: { comType: 'input', disabled: true }
},
// 商品名称:支持动态下拉搜索、表单输入校验(3-20字)
product_name: {
type: 'string',
label: '商品名称',
maxLength: 20,
minLength: 3,
searchOption: { comType: 'dynamicSelect', api: '/api/proj/product_enum/list' },
createFormOption: { comType: 'input', default: '哲玄新课程' }
},
// 价格:数值范围校验(30-1000)、表格保留2位小数、下拉搜索
price: {
type: 'number',
label: '价格',
maximum: 1000,
minimum: 30,
tableOption: { width: 200, toFixed: 2 },
searchOption: { comType: 'select', enumList: [{ label: '¥39.0', value: 39.0 }, ...] },
createFormOption: { comType: 'inputNumber' }
},
// 其他字段(库存、创建时间):略...
},
required: ['product_name'] // 表单必填字段
},
tableConfig: { // 表格交互配置(按钮、操作逻辑)
headerButtons: [{ // 表格顶部按钮(新增商品)
label: '添加商品',
eventKey: 'showComponent', // 触发事件(显示弹窗)
eventOption: { comName: 'createForm' } // 弹窗类型(新增表单)
}],
rowButtons: [ // 表格行操作按钮(详情、修改、删除)
{ label: '详情', eventKey: 'showComponent', eventOption: { comName: 'detailPanel' } },
{ label: '修改', eventKey: 'showComponent', eventOption: { comName: 'editForm' } },
{ label: '删除', eventKey: 'remove', eventOption: { params: { product_id: 'schema::product_id' } } }
]
},
componentConfig: { // 弹窗组件配置(标题、按钮文本)
createForm: { title: '添加商品', saveBtnText: '保存' },
editForm: { mainKey: 'product_id', title: '编辑商品' },
detailPanel: { mainKey: 'product_id', title: '商品详情' }
}
}
},
// 其他菜单(订单管理-自定义页、客户管理-自定义页):略...
]
}
三、配置渲染流程:从 “配置” 到 “页面” 的全链路实现
前端基于 Vue3 实现配置的自动化渲染,核心分为 “配置获取” 与 “页面渲染” 两步,全程无需手动编写页面代码:
1. 第一步:配置获取(衔接 BFF Serve 层)
领域模型配置由 BFF Serve 层统一管理,前端通过接口获取配置并缓存,确保多页面共享数据:
- 接口请求:在系统入口(如
dashboard.vue)调用 BFF 层的/api/project接口,传入项目标识(proj_key),获取包含 “菜单、页面、字段” 的完整配置; - 状态缓存:将配置存入 Vuex/Pinia 状态管理(如
menuStore存储菜单配置、projectStore存储项目信息),避免重复请求; - 配置分发:路由切换时,从状态管理中读取当前菜单对应的配置,传递给动态渲染组件。
2. 第二步:页面渲染(分场景适配)
根据配置中的 moduleType(页面类型),前端自动匹配渲染逻辑,实现 “一套代码适配多场景”:
(1)schema-view 渲染(核心 CRUD 页面)
通过自定义 Hook useSchema 解析配置,将 JSON Schema 拆分为 “表格配置、搜索配置、组件配置”,再结合 Vue 动态组件渲染页面:
-
配置解析:
useSchema钩子接收schemaConfig,提取api(接口地址)、tableSchema(表格字段)、searchSchema(搜索字段)、components(弹窗组件); -
组件渲染:
- 搜索栏:根据
searchSchema动态生成组件(输入框、下拉框、日期范围选择器),并绑定校验规则; - 表格:基于
tableSchema渲染列,结合tableConfig渲染顶部 / 行操作按钮,点击按钮时触发eventKey对应的逻辑(如显示弹窗、调用删除接口); - 弹窗:根据
componentConfig渲染 “新增 / 编辑 / 详情” 弹窗,自动关联表单字段与校验规则。
- 搜索栏:根据
(2)iframe 渲染(嵌入外部页面)
- 从菜单配置中读取
iframe类型对应的嵌入路径(如customConfig.path); - 在 Vue 模板中使用
<iframe>标签,动态绑定src属性为嵌入路径,实现外部页面的无缝嵌入。
(3)custom 渲染(自定义页面)
- 配置中指定自定义页面的 Vue 组件路径(如
customConfig.path); - 通过 Vue3 的异步加载组件,在路由对应的页面中渲染,满足个性化交互需求(如复杂表单、数据可视化)。
3. 核心渲染代码示例(dashboard.vue 入口)
<template>
<el-config-provider :locale="zhCn">
<!-- 头部导航(渲染菜单) -->
<header-view :proj-name="projName" @menu-select="onMenuSelect">
<!-- 动态路由出口(渲染对应页面) -->
<template #main-content>
<router-view></router-view>
</template>
</header-view>
</el-config-provider>
</template>
<script setup>
import { ref, onMounted } from "vue";
import { useRouter, useRoute } from "vue-router";
import { useMenuStore } from "$elpisStore/menu"; // 菜单状态管理
import { useProjectStore } from "$elpisStore/project"; // 项目状态管理
import $curl from "$elpisCommon/curl.js"; // 接口请求工具
const router = useRouter();
const route = useRoute();
const menuStore = useMenuStore();
const projectStore = useProjectStore();
const projName = ref("");
// 初始化:获取配置并缓存
onMounted(async () => {
await getProjectConfig();
});
// 调用 BFF 接口获取领域模型配置
async function getProjectConfig() {
const res = await $curl({
method: "get",
url: "/api/project",
query: { proj_key: route.query.proj_key } // 项目标识
});
if (res?.success && res.data) {
const { name, menu } = res.data;
projName.value = name;
menuStore.setMenuList(menu); // 缓存菜单配置
}
}
// 菜单点击:切换路由,匹配对应页面
const onMenuSelect = (menuItem) => {
const { key, moduleType, customConfig } = menuItem;
// 路由路径映射(根据页面类型匹配)
const pathMap = {
schema: "/schema", // Schema 渲染页路径
iframe: "/iframe", // iframe 嵌入页路径
custom: customConfig?.path // 自定义页路径
};
// 跳转路由(携带项目标识、菜单标识)
router.push({
path: `/view/dashboard`,
query: { key, proj_key: route.query.proj_key }
});
};
</script>
里程碑四 基于 vue3 完成动态组件库建设
上一阶段通过 DSL 配置实现了 schema-view 页面自动化渲染,本阶段核心是构建配置驱动的动态组件库,用 JsonSchema 统一描述组件结构与逻辑
一、解决三大关键问题
- 配置体系:用一份 jsonSchema 覆盖 “组件是什么、何时触发、包含什么、如何交互”;
- 渲染通信:实现三层组件(容器→中间件→控件)解耦与跨层级联动。
二、配置体系:四层结构定义组件全生命周期
基于 “单一数据源” 思想,在领域模型基础上扩展配置,确保框架可自动识别逻辑:
- 组件元信息(componentConfig):定义 “是什么”
描述组件基础属性,如标题、按钮文本、主键(用于数据回显):
schemaConfig: {
componentConfig: {
createForm: { title: '添加商品', saveBtnText: '保存' },
editForm: { mainKey: 'product_id', title: '编辑商品' },
detailPanel: { mainKey: 'product_id', title: '商品详情' }
}
}
- 触发规则(tableConfig):定义触发
在表格按钮中配置事件,通过 eventKey 关联组件,统一交互逻辑:
schemaConfig: {
tableConfig: {
headerButtons: [{ // 表头按钮→新增组件
label: '添加商品',
eventKey: 'showComponent',
eventOption: { comName: 'createForm' }
}],
rowButtons: [ // 行按钮→详情/编辑/删除
{ label: '详情', eventKey: 'showComponent', eventOption: { comName: 'detailPanel' } },
{ label: '删除', eventKey: 'remove', eventOption: { params: { product_id: 'schema::product_id' } } }
]
}
}
- 字段属性(properties):定义 “包含什么”
为字段配置不同组件中的表现(控件类型、校验规则),通过 xxxOption 区分场景:
schemaConfig: {
properties: {
product_name: {
type: 'string',
label: '商品名称',
maxLength: 20, // 全局校验
searchOption: { comType: 'dynamicSelect', api: '/api/proj/enum' }, // 搜索框
createFormOption: { comType: 'input', default: '哲玄新课程' } // 新增表单
},
price: {
type: 'number',
minimum: 30,
tableOption: { width: 200, toFixed: 2 }, // 表格显示
createFormOption: { comType: 'inputNumber' } // 表单控件
}
}
}
- API 交互:定义 “如何通信”
遵循 REST 规范,基础 API 统一配置,框架自动映射 HTTP 方法(新增→POST、删除→DELETE),动态参数用
schema::xxx取表格行数据。
三、分层渲染:三层结构解耦加载 按职责拆分组件,用 Vue 动态组件实现自动化渲染,便于扩展:
1. 目录结构
plaintext
src/
├── pages/schema-view/ # 顶层容器:管理状态与事件
│ ├── schema-view.vue
│ └── components/ # 中间层:预设组件(新增/编辑/详情)
│ ├── create-form/
│ └── component-config.js # 组件映射(comName→组件路径)
└── widgets/schema-form/ # 底层:字段控件(输入框/下拉框)
├── schema-form.vue # 控件容器
└── components/ # 具体控件
2. 核心渲染逻辑(schema-view.vue)
vue
<template>
<!-- 表格+搜索栏(复用前序实现) -->
<el-table>...</el-table>
<!-- 动态渲染中间层组件 -->
<component
v-for="(com, comName) in components"
:key="comName"
:is="ComponentMap[comName]"
:schema="com.schema"
:api="api"
@command="handleComCommand" <!-- 监听组件事件(如保存成功) -->
/>
</template>
<script setup>
import { useSchema } from "@/hooks/schema.js";
import ComponentMap from "./components/component-config.js";
const { api, components } = useSchema();
// 处理组件事件(如保存后刷新表格)
const handleComCommand = ({ event }) => {
if (event === "saveSuccess") emit("refreshTable");
};
</script>
四、通信机制:高效跨层级联动
- 数据向下:顶层用
provide提供 API、配置,中间层 / 底层用inject直接获取,避免 props 层层传递; - 事件向上:中间层通过
emit触发事件(如saveSuccess),顶层监听后执行逻辑(如刷新表格); - 组件调用:顶层用
ref获取中间层组件实例,主动调用方法(如编辑时回显数据)。
里程碑五 完成 elpis-npm 包分离并发布
本阶段核心目标是实现 “核心 - 业务” 彻底解耦:将框架核心能力(elpis-core、webpack 工程化、基础组件)封装为elpis npm 包,业务侧仅需安装该包,按约定目录开发即可,无需关注底层配置,真正实现 “聚焦业务、核心托管”。
elpis-core:自动扫描业务代码,实现 “业务模块零配置挂载”
为各加载器(controller、service 等)新增业务层扫描逻辑,自动识别业务目录下的模块并挂载到框架实例,无需手动注册。
以控制器加载器为例:
// elpis-core/loader/controllerLoader.js
const path = require('path');
const glob = require('glob');
function loadController(app) {
// 1. 加载框架核心控制器(原有逻辑)
const coreControllerPath = path.resolve(__dirname, '../app/controller');
glob.sync(`${coreControllerPath}/**/*.js`).forEach(file => handlerFile(file, app));
// 2. 新增:扫描业务层控制器(约定业务路径 app/controller)
const businessControllerPath = path.resolve(app.businessPath, './controller');
const businessFileList = glob.sync(`${businessControllerPath}/**/*.js`);
businessFileList.forEach(file => handlerFile(file, app));
console.log(`-- [elpis] loaded ${businessFileList.length} business controllers --`);
}
// 统一挂载逻辑:核心与业务模块共用
function handlerFile(file, app) {
const controller = require(file);
const moduleName = path.dirname(file).split(path.sep).pop();
if (!app.controller[moduleName]) app.controller[moduleName] = {};
app.controller[moduleName][path.basename(file, '.js')] = controller;
}
module.exports = loadController;
同时改造elpis-core/index.js,新增业务全局中间件注册:
// elpis-core/index.js
function start(options = {}) {
const app = new Koa();
app.businessPath = options.businessPath || process.cwd() + '/app'; // 约定业务路径
// 注册业务全局中间件(约定业务路径 middleware.js)
try {
require(`${app.businessPath}/middleware.js`)(app);
console.log(`-- [elpis] loaded business global middleware --`);
} catch (error) {
console.log(`[elpis] no business middleware, skip`);
}
// 加载核心+业务模块(controller、service等)
loadController(app);
loadService(app);
app.listen(options.port || 3000);
return app;
}
module.exports = { start };
2. webpack 配置:自动扫描业务页面,实现 “业务入口零配置打包”
对webpack.base.js/dev.js/prod.js改造,新增业务层入口扫描,自动将业务页面纳入打包流程:
// webpack/base.js
const path = require('path');
const glob = require('glob');
const HtmlWebpackPlugin = require('html-webpack-plugin');
// 1. 初始化业务入口与HTML插件容器
const businessEntries = {};
const businessHtmlPlugins = [];
// 2. 扫描业务层入口(约定 app/pages/**/entry.*.js)
const businessEntryList = path.resolve(process.cwd(), './app/pages/**/entry.*.js');
glob.sync(businessEntryList).forEach(file => {
const entryName = path.basename(file, '.js').replace('entry.', '');
// 配置入口
businessEntries[entryName] = file;
// 配置HTML模板
businessHtmlPlugins.push(new HtmlWebpackPlugin({
filename: `${entryName}.html`,
template: path.resolve(__dirname, '../template/entry.tpl'),
chunks: [entryName]
}));
});
// 3. 合并核心与业务配置(最终导出)
module.exports = {
entry: { ...coreEntries, ...businessEntries }, // 合并入口
plugins: [...corePlugins, ...businessHtmlPlugins], // 合并插件
// 其他基础配置(loader、resolve等不变)
};
3. 框架入口 index.js:封装核心 API,对外暴露标准化能力
将框架核心能力(服务启动、前端构建)封装为函数,对外暴露清晰 API,业务侧直接调用:
// index.js(elpis包入口)
const ElpisCore = require("./elpis-core");
const FEBuildDev = require('./webpack/dev.js');
const FEBuildProd = require('./webpack/prod.js');
module.exports = {
// 1. 暴露基础类(供业务继承,减少重复编码)
Controller: { Base: require('./app/controller/base.js') },
Service: { Base: require('./app/service/base.js') },
// 2. 前端构建:支持开发/生产环境
frontendBuild(paramsEnv) {
const env = paramsEnv.trim();
env === 'local' ? FEBuildDev() : FEBuildProd();
},
// 3. BFF服务启动:接收业务配置,返回实例
serverStart(options = {}) {
const app = ElpisCore.start(options);
console.log(`-- [elpis] server started at port ${options.port || 3000} --`);
return app;
}
};
4. entry.dashboard.js:支持业务路由拓展,零配置注入
新增业务路由拓展机制,业务侧按约定暴露配置函数即可自动注入路由:
// app/pages/dashboard/entry.dashboard.js
import { createRouter, createWebHistory } from 'vue-router';
// 1. 框架核心路由(原有逻辑)
const routes = [/* 核心页面路由 */];
const siderRoutes = [/* 核心菜单路由 */];
// 2. 新增:业务路由拓展(约定业务暴露 businessDashboardRouterConfig)
if (typeof businessDashboardRouterConfig === 'function') {
businessDashboardRouterConfig({ routes, siderRoutes });
console.log(`-- [elpis] extended business routes --`);
}
// 3. 创建路由实例并导出
const router = createRouter({ history: createWebHistory(), routes });
export { router, siderRoutes };
5. 组件配置文件:支持业务组件拓展,合并导出
改造schema-view/components/component-config.js与widgets/**/xx-item-config.js,新增业务组件导入,合并核心与业务组件:
// schema-view/components/component-config.js
// 1. 框架核心组件(原有逻辑)
import CreateForm from './create-form';
const ComponentConfig = { createForm };
// 2. 新增:导入业务组件(约定业务路径 $businessComponentConfig)
import businessComponentConfig from '$businessComponentConfig';
// 3. 合并导出(业务组件覆盖核心组件,支持定制)
export default { ...ComponentConfig, ...businessComponentConfig };
二、业务侧使用:elpis-demo 项目零配置开发
业务侧只需创建elpis-demo项目,按以下步骤即可快速开发:
-
安装 elpis 包:
npm install elpis --save(或npm link本地调试); -
按约定目录开发:业务代码放在
app目录下(如app/controller、app/pages),无需配置 webpack/elpis-core;
三、包发布:npm 流程
- 本地调试:通过
npm link将elpis包链接到elpis-demo,验证功能; - 登录 npm:
npm login(输入账号密码); - 发布包:
npm publish(确保package.json中name唯一,版本号正确)。
迭代发展方向
深度融合 AI
AI 需求转配置:基于框架开发指南构建专属 AI 提示词(Prompt),开发者只需输入自然语言需求(如 “新增电商分销管理模块,包含分销员列表、佣金统计、订单关联功能”),AI 即可自动生成符合 elpis 规范的领域模型配置(字段定义、组件交互、API 映射),无需手动编写 jsonSchema 配置;
AI Agent:打造 “开发助手”: 开发 elpis 专属 AI Agent,集成框架所有核心能力与规范,支持多维度交互:
- 配置生成:根据开发者需求描述,生成 schema-view 页面配置、业务路由配置、组件拓展配置等,直接适配 elpis 框架的动态渲染逻辑;
- 问题解答:开发者遇到配置疑问(如 “如何自定义表格行操作按钮”“业务组件如何挂载到框架”)时,AI Agent 可基于框架文档精准回复,并提供代码示例;
- 能力拓展:支持开发者提出组件拓展需求(如 “开发一个带时间范围选择的搜索控件”),AI Agent 自动生成符合 elpis 组件规范的代码,并说明挂载方式,确保不偏离框架生态。