@breaknine/elpis
v1.0.5
Published
Elpis 是一个基于 Node.js + Koa2 + Vue3 的全栈低代码开发平台,旨在通过配置化的方式快速构建企业级管理系统。项目采用模块化架构设计,支持多项目管理。
Downloads
28
Readme
Elpis
一、一个企业级应用
项目概况
Elpis 是一个基于 Node.js + Koa2 + Vue3 的全栈低代码开发平台,旨在通过配置化的方式快速构建企业级管理系统。项目采用模块化架构设计,支持多项目管理。
01.基于 nodejs 实现服务端内核引擎
/*
运行前(磁盘文件) -> 解析器 ElpisKoa -> 运行时(内存)
----------------------------------------------------------------------------
[app/router/**] -> [router-loader]
[app/router-schema/**] -> [router-schema-loader]
[app/middleware/**] -> [middleware-loader] -> API 请求┐
[app/controller/**] -> [controller-loader] -> ├--> router /
[app/service/**] -> [service-loader] -> 页面请求┘ router-schema
[app/extend/**] -> [extend-loader] |
[app/schedule/**] -> [schedule-loader] |
[config/**] -> [config-loader] v
----------------------------------------------------------------------------
middleware (洋葱圈外层):
- 错误捕获
- 参数校验
- 其他中间件...
----------------------------------------------------------------------------
[业务逻辑处理](洋葱圈内部)
----------------------------------------------------------------------------
| |
v |
Controller -> service |
| ├─ 读写 mysql |
| ├─ 日志 |
| ├─ 外部服务 |
| └─ 其他能力 |
└─ SSR/config/extend/页面模板 V
┌───────────────┐
│ API响应 / │
│ 页面响应 │
└───────────────┘
*/- 请求处理洋葱模型(Koa 中间件栈)
/*
┌─────────────────────────────────┐
Inbound │ 全局错误捕获 │
Req │ 日志 / Trace │
---> │ CORS / 安全头 │
│ 参数校验 (router-schema) │
│ 业务自定义中间件链 │
├─────────────────────────────────┤
│ 路由匹配 (app.router) │
│ -> controller.method │
│ -> service.* │
│ -> DB / 外部API │
│ <- 组装结果 (success封装) │
├─────────────────────────────────┤
Outbound│ 统一响应格式 / 压缩 / 缓存头 │
Res │ 错误格式化 │
<--- │ 最终写回 HTTP Response │
└─────────────────────────────────┘
*/- 路由与控制器、Schema 关联
/*
[router-loader]
解析定义: METHOD + PATH + handlerRef
│
│ handlerRef 解析到 controller.loader 挂载的实例方法
v
[router-schema-loader]
为 (METHOD, PATH) 匹配校验规则
│
v
(请求进入)
-> 中间件参数校验 (使用 schema)
-> 通过则调用 controller.method
*/- 依赖方向概览(箭头指向“被依赖”)
/*
请求 → middleware链 → router → controller → service → (DB/外部API)
│
├→ app.extend.*
├→ app.config.*
└→ 工具库 (lodash/moment 等)
Loader 初始化顺序 (大致):config → extend → service → controller → middleware → router-schema → router → schedule
*/- 层级抽象(越下越接近基础设施)
/*
[ 接口层 / 路由暴露 ]
[ 控制器 (协调/组装) ]
[ 服务 (业务逻辑 / 领域) ]
[ 数据访问 / 外部集成 ]
[ 基础设施: DB | Cache | 外部API | 文件 | 日志 ]
*/02.基于 webpack5 完成工程化建设
/*
app/
├─ pages/
│ ├─ foo/
│ │ └─ entry.foo.js
│ ├─ bar/
│ │ └─ entry.bar.js
│ └─ ... (更多内置或业务页面)
├─ public/
│ └─ dist/
│ ├─ entry.foo.tpl
│ ├─ entry.bar.tpl
│ └─ ... (每个入口对应一个模板)
└─ webpack/
├─ config/
│ └─ webpack.base.js (自动收集入口 + 构造 HtmlWebpackPlugin 列表 + 合并业务配置)
├─ dev.js (在 base 上附加 HMR / devtool / middleware)
├─ prod.js (在 base 上附加优化 / 压缩 / 分析)
├─ view/
│ └─ entry.tpl (所有页面共享的基础模板)
└─ ... 其他辅助文件
流程:
[扫描入口 - 内置] app/webpack/config/webpack.base.js
│ glob ../../pages/**/entry.*.js
▼
elpisPageEntries (entryName -> 文件路径)
│
├────────────────────────────────┐
▼ │
[扫描入口 - 业务同路径] │
businessPageEntries (entryName -> 文件路径)
│ │
└───────────────┬────────────────┘
▼
合并 entries
│
▼
为每个 entry 生成 HtmlWebpackPlugin
(输出 *.tpl 到 app/public/dist/)
│
▼
尝试加载业务 webpack.config.js (存在则 merge)
│
▼
得到 baseConfig
│
┌───────────────┴────────────────┐
▼ ▼
dev.js (追加 HMR / sourcemap) prod.js (压缩 / hash / 分析)
│ │
▼ ▼
webpack 构建 (分别输出环境产物)
│
▼
产出: js/css + *.tpl 模板文件
*/- Webpack 前端工程侧(与服务端内核的衔接)
/*
pages/**/entry.*.js (多入口)
│
v
[webpack.base] 发现 -> entries + HtmlWebpackPlugin(tpl)
│
dev.js / prod.js (环境差异: HMR / 压缩 / 分析)
│
v
public/dist/*.tpl + 静态资源(bundle.js / css / assets)
│
v
后端 (koa 中间件 / controller 渲染或直返模板)
*/03.基于 vue3 完成领域模型架构建设 04.基于 vue3 完成动态组件库建设
目录树分析(聚焦角色、依赖、可优化点):
核心分层映射
单入口: dashboard/entry.dashboard.js
全局引导: boot.js (可挂载全局样式、store、路由、全局组件)
页面聚合: dashboard.vue (装配 header / sider / iframe / schema 四大子区域)
复合区域: complex-view/* 下按功能拆子视图 (header-view / sider-view / iframe-view / schema-view)
Schema 子域: 配置驱动 + 视图面板 (search-panel / table-panel / create/edit/detail 表单)
配置文件: component-config.js / form-item-config.js / search-item-config.js / hook/schema.js
可复用部件: widgets/*(搜索表单、表单、表格、头部、侧栏容器)
状态: store/index.js 聚合 menu.js / project.js
通用工具: common/curl.js (HTTP) / utils.js
资产: asserts/custom.css + 各局部组件内 asserts/**
目录角色归类 (mermaid 目录视图):
graph TD
P[app/pages] --> E[entry.dashboard.js]
P --> B[boot.js]
P --> D[dashboard/]
P --> W[widgets/]
P --> S[store/]
P --> C[common/]
P --> A[asserts/]
D --> Dv[dashboard.vue]
D --> CV[complex-view/]
CV --> HV[header-view.vue]
CV --> SV[sider-view.vue]
CV --> IF[iframe-view.vue]
CV --> SCH[schema-view/]
SCH --> SCHV[schema-view.vue]
SCH --> Hook[hook/schema.js]
SCH --> Cfg[components/ + config.js]
Cfg --> CF[create-form.vue]
Cfg --> EF[edit-form.vue]
Cfg --> DF[detail-panel.vue]
SCH --> SP[search-panel.vue]
SCH --> TP[table-panel.vue]
W --> WSSB[schema-search-bar/]
WSSB --> SSBC[schema-search-bar.vue]
WSSB --> SSBI[search-item-config.js]
W --> WSF[schema-form/]
WSF --> SFV[schema-form.vue]
WSF --> SFC[form-item-config.js]
W --> WST[schema-table.vue]
W --> SID[sider-container.vue]
W --> HDR[header-container.vue]
S --> StIdx[index.js]
S --> StPrj[project.js]
S --> StMenu[menu.js]
C --> Curl[curl.js]
C --> Utils[utils.js]- 运行/依赖流 (从入口到组件)
flowchart LR
Entry[entry.dashboard.js] --> Boot[boot.js]
Boot --> Store[store/index.js]
Boot --> App[dashboard.vue]
App --> Complex[complex-view/*]
Complex --> Header[header-view.vue]
Complex --> Sider[sider-view.vue]
Complex --> Iframe[iframe-view.vue]
Complex --> Schema[schema-view.vue]
Schema --> SearchP[search-panel.vue]
Schema --> TableP[table-panel.vue]
Schema --> Forms[create/edit/detail]
SearchP --> WidgetSearch[schema-search-bar.vue]
Forms --> WidgetForm[schema-form.vue]
TableP --> WidgetTable[schema-table.vue]
WidgetSearch --> SearchCfg[search-item-config.js]
WidgetForm --> FormCfg[form-item-config.js]
Schema --> HookSchema[hook/schema.js]
Widgets --> Common[common/utils.js & curl.js]
Store --> API[(后端 API 调用 via curl)]- Schema 视图内部结构 (配置驱动)
graph TD
SCH[schema-view.vue] --> Hook[hook/schema.js]
SCH --> Panels[complex-view 子面板]
Panels --> Search[search-panel.vue]
Panels --> Table[table-panel.vue]
Panels --> Detail[detail-panel.vue]
Panels --> Create[create-form.vue]
Panels --> Edit[edit-form.vue]
Search --> WidgetSearchBar[schema-search-bar.vue]
WidgetSearchBar --> SearchConfig[search-item-config.js]
Create --> WidgetForm[schema-form.vue]
Edit --> WidgetForm
WidgetForm --> FormConfig[form-item-config.js]
Table --> WidgetTable[schema-table.vue]- 可复用 widgets 依赖
graph LR
subgraph Widgets
widgetSearchBar[SchemaSearchBar]
widgetForm[SchemaForm]
widgetTable[SchemaTable]
siderContainer[SiderContainer]
headerContainer[HeaderContainer]
end
widgetSearchBar --> commonUtils
widgetForm --> commonUtils
widgetTable --> commonUtils
siderContainer --> commonUtils
headerContainer --> commonUtils
headerContainer --> assets[(header-container / asserts / *.png)]
commonUtils[common curl & utils] --> storeLayer[Store]- 状态与页面交互
sequenceDiagram
participant Entry as entry.dashboard.js
participant Store as store/*
participant View as dashboard.vue / 子视图
participant Widget as widgets/*
participant Curl as common/curl.js
participant API as 后端
Entry->>Store: 注册 modules (project/menu)
Entry->>View: mount
View->>Widget: 传递配置 / props
Widget->>Store: dispatch/commit
Store->>Curl: 发起请求
Curl->>API: HTTP
API-->>Curl: JSON
Curl-->>Store: resolve
Store-->>Widget: state 更新 (响应式)
Widget-->>View: emit 事件 (如 search / submit)05.完成 框架npm包 抽象封装并发布, elpis-demo 应用
二、辅助 mermaid 视图 总览
整体 Loader 流程
graph TD
A[磁盘文件] --> B[config-loader]
A --> C[extend-loader]
A --> D[service-loader]
A --> E[controller-loader]
A --> F[middleware-loader]
A --> G[router-schema-loader]
A --> H[router-loader]
A --> I[schedule-loader]
B --> R[(app.config)]
C --> S[(app.extend)]
D --> T[(app.service)]
E --> U[(app.controller)]
F --> V[(app.middleware)]
G --> W[(校验规则)]
H --> X[(路由树)]
I --> Y[(计划任务)]graph TD
subgraph Loader阶段
CF[config] --> EX[extend]
EX --> SV[service]
SV --> CT[controller]
CT --> MW[middleware]
MW --> RS[router-schema]
RS --> RT[router]
RT --> SC[schedule]
end
subgraph Runtime
RT --> Handle[请求调度]
MW2[中间件栈] --> RT
Handle --> CTRL[Controller方法]
CTRL --> SERV[Service]
SERV --> DB[(DB/外部API)]
SERV --> EXT[extend工具]
CTRL --> RESP[统一响应]
end
subgraph Frontend
Scan[扫描 entry.*.js] --> Merge[合并 entries]
Merge --> HTML[HtmlWebpackPlugin 生成 *.tpl]
HTML --> Dist[dist 输出]
Dist --> RESP
end
Client[浏览器请求] --> MW2
RESP --> Client依赖方向概览 + Loader 初始化顺序
flowchart LR
Req[请求] --> MW链[middleware链] --> RT[router] --> CT[controller] --> SV[service] --> EXT[extend] --> 外部[DB/外部API]
CT --> CFG[app.config]graph TD
subgraph 目录
PAGES[app/pages/**/entry.*.js]
BPAGES[business/app/pages/**/entry.*.js]
TPL[app/webpack/view/entry.tpl]
DIST[app/public/dist/*.tpl]
end
PAGES -->|glob| EN1[elpisPageEntries]
BPAGES -->|glob| EN2[businessPageEntries]
EN1 --> M[合并 entries]
EN2 --> M
M --> H[生成 HtmlWebpackPlugin 列表 -> *.tpl]
TPL --> H
H --> BASE[webpack.base 配置]
BASE --> DEV[dev.js: HMR / sourcemap]
BASE --> PROD[prod.js: 压缩 / 分析 / hash]
DEV --> OUT[js/css + tpl]
PROD --> OUT
OUT --> DISTWebpack 前端工程侧(与服务端内核衔接)
sequenceDiagram
participant Scan as 扫描 entry.*.js
participant Base as webpack.base
participant Env as dev/prod 配置
participant Build as webpack 构建
participant Dist as dist 产物
participant Koa as 后端(Koa)
participant Browser as 浏览器
Scan->>Base: entries + 模板列表
Base->>Env: 合并基础配置
Env->>Build: 运行
Build->>Dist: 输出 *.tpl + 资源
Dist->>Koa: 模板/静态资源提供
Browser->>Koa: 请求页面
Koa-->>Browser: 注入后的 HTML三、技术栈
后端技术栈
框架: Koa2 模板引擎: Nunjucks 测试框架: Mocha + Supertest 工具库: Lodash, MD5, Glob
前端技术栈
框架: Vue 3 (Composition API) UI 组件库: Element Plus 状态管理: Vuex 4 路由: Vue Router 4 构建工具: Webpack 5 样式预处理: Less
四、项目架构以及使用说明
核心架构设计
项目采用分层架构模式,主要包含以下几个层次:
Elpis 架构
├── 表现层 (Presentation Layer)
│ ├── Vue3 组件
│ ├── Element Plus UI
│ └── 路由管理
├── 业务逻辑层 (Business Logic Layer)
│ ├── Controller 控制器
│ ├── Service 服务层
│ └── 中间件系统
├── 数据访问层 (Data Access Layer)
│ ├── Model 数据模型
│ └── Schema 配置
└── 基础设施层 (Infrastructure Layer)
├── Elpis-Core 核心框架
├── 自动加载器
└── 配置管理目录结构
Elpis/
├── app/ # 应用主目录
│ ├── controller/ # 控制器层
│ ├── service/ # 服务层
│ ├── middleware/ # 中间件
│ ├── router/ # 路由配置
│ ├── router-schema/ # 路由参数校验
│ ├── pages/ # 前端页面
│ ├── public/ # 静态资源
│ ├── view/ # 模板文件
├── config/ # 配置文件
├── model/ # 数据模型
├── elpis-core/ # 核心框架
└── doc/ # 配置文档model 配置
通过一份 schema 生成 一个完整的站点
{
model: 'dashboard',// 模版类型,不同模版对应不一样的数据结构
name: '',//mingcheng
desc: '',// 描述
icon: '',// icon
homePage: '',// 首页路径
// 头部菜单
menu: [{
key: '',// 菜单唯一描述
name: '',// 菜单名称
menuType: '', // 枚举值,group / module
// 当menuType == group 时,可填
subMenu: [{
// 可递归 menuItem
}, ...],
// 当 menuType == module 时,可填
moduleType: '',// 枚举值:sider/iframe/custom/schema
// 当 moduleType == sider
siderConfig: {
menu: [{
// 可递归 menuItem(除 moduleType === sider)
}, ...]
},
// 当 moduleType == iframe 时
iframeConfig: {
path: '',// iframe 路径
},
// 当 moduleType == custom 时
customConfig: {}, // 自定义路由路径
// 当moduleType == schema 时
schemaConfig: {
api: '',// 数据源API (遵循 RESTFUL 规范)
schema: {// 板块数据结构
type: 'object',
properties: {
key: {
...schema, // 标准 schema 配置
type: '', // 字段类型
label: '', // 字段的中文名
// 字段在 table 中的相关配置
tableOption: {
...elTableColumnConfig,// 标准 el-table-column 配置
toFixed: 0,// 保留小数点后几位数字
visible: true, // 默认为 true (false 表示不在表单中显示)
},
//字段在 search-bar 中的相关配置
searchOption: {
...eleComponentConfig, //标准 el-component-column 配置
comType: '',// 配置组件类型 input/select/...
default: '',//默认值
// comType='select'
enumList:[],// 下拉框可选项
// comType === 'dynamicSelect'
api:''
},
// 字段在不同动态 component 中的相关配置,前缀对应 componentComfig 中的键值
// 如:componnetconfig.createForm,这里对应 createFormOption
// 字段在 createForm 中相关配置
createFormOption:{
...elTableColumnConfig,// 标准 el-table-column 配置
comType:'',// 控件类型 input/select/input-number
visible:true,// 是否展示 (true/false) 默认为 true
disabled:false,// 是否禁用 (true/false) 默认为 false
// comType === 'select' 时生效
enumList:[] // 枚举列表
},
// 字段在 editForm 表单中的相关配置
editFormOption:{
...elTableColumnConfig,// 标准 el-table-column 配置
comType:'',// 控件类型 input/select/input-number
visible:true,// 是否展示 (true/false) 默认为 true
disabled:false,// 是否禁用 (true/false) 默认为 false
// comType === 'select' 时生效
enumList:[] // 枚举列表
},
detailPanelOption:{
...eleComponnetConfig // 标准 elcomponent 配置
}
},
...
},
required:[]// 标记 properties 中的哪些字段是必填项
},
// table 相关配置
tableConfig: {
headerButtons: [{
label: '',//按钮中文名
eventKey: '', //按钮事件名
//按钮事件具体配置
eventOption: {
// 当 eventKey === 'showComponent'
comName:'' // 组件名称
},
...elButtonConfig //标准 el-button 配置
}, ...],
rowButtons: [{
label: '',//按钮中文名
eventKey: '', //按钮事件名
eventOption: {//按钮事件具体配置
// 当 eventKey === 'showComponent'
comName:'', // 组件名称
//当 eventKey=== 'remove'
params: {
// paramKey =参数的键值
// rowValueKey =参数值(当格式为 schema::tableKey 的时候,到table 中找响应的字段)
paramKey: rowValueKey // 比如 当 eventKey=== 'remove' 时,user_id: schema::user_id
}
},
...elButtonConfig //标准 el-button 配置
}, ...]
},
// search-bar 相关配置
searchConfig: {},
// 动态组件 相关配置
componentConfig: {
// create-form 表单相关配置
createForm:{
title:'',// 表单标题
saveBtnText:'',// 保存按钮文案
},
// edit-form 相关配置
editForm:{
mainKey:'', // 表单主键,用于唯一标识要修改的数据对象
title:'',// 表单标题
saveBtnTitle:'',//保存按钮文案
},
// detail-panel 相关配置
detailPanel: {
mainKey:'', // 表单主键,用于唯一标识要修改的数据对象
title:'',// 表单标题
},
// ...支持用户动态扩展
}
}
}, ...]
};服务端启动
const {
serverStart
} = require('@breaknine/elpis');
// 启动elpis
const app = serverStart();自定义服务端
- router-schema
- router
- controller
- service
- extend
- config
前端构建
const { frontendBuild } = require('@breaknine/elpis');
// 编译构建前端工程
frontendBuild(process.env._ENV);自定义页面拓展
- 在
app/pages目录下写入口 entry.${页面name}.js
dashboard/custom-view 自定义页面拓展
- 在
app/pages/dashboard/xxx下写页面
dashboard/schema-view/components 动态组件拓展
- 在
app/pages/dashboard/complex-view/schema-view/components下写组件 - 配置到
app/pages/dashboard/complex-view/schema-view/components/component-config.js
schema-form 控件拓展
- 在
app/pages/widgets/schema-form/complex-view下写控件 - 配置到
app/pages/widgets/schema-form/form-item-config.js
schema-search-bar 控件拓展
- 在
app/pages/widgets/schema-search-bar/complex-view下写控件 - 配置到
app/pages/widgets/schema-search-bar/schema-item-config.js
