@dmqweb/elpis 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/.eslintignore +3 -0
  2. package/.eslintrc +59 -0
  3. package/.vscode/settings.json +15 -0
  4. package/README.md +198 -0
  5. package/app/controller/base.js +41 -0
  6. package/app/controller/project.js +98 -0
  7. package/app/controller/view.js +24 -0
  8. package/app/extend/logger.js +43 -0
  9. package/app/middleware/api-params-verify.js +89 -0
  10. package/app/middleware/api-sign-verify.js +47 -0
  11. package/app/middleware/error-handler.js +41 -0
  12. package/app/middleware/project-handler.js +27 -0
  13. package/app/middleware.js +40 -0
  14. package/app/pages/asserts/custom.css +12 -0
  15. package/app/pages/boot.js +59 -0
  16. package/app/pages/common/curl.js +88 -0
  17. package/app/pages/common/util.js +3 -0
  18. package/app/pages/dashboard/complex-view/header-view/complex-view/sub-menu/sub-menu.vue +40 -0
  19. package/app/pages/dashboard/complex-view/header-view/header-view.vue +141 -0
  20. package/app/pages/dashboard/complex-view/iframe-view/iframe-view.vue +43 -0
  21. package/app/pages/dashboard/complex-view/schema-view/complex-view/search-panel/search-panel.vue +39 -0
  22. package/app/pages/dashboard/complex-view/schema-view/complex-view/table-panel/table-panel.vue +146 -0
  23. package/app/pages/dashboard/complex-view/schema-view/components/component-config.js +24 -0
  24. package/app/pages/dashboard/complex-view/schema-view/components/create-form/create-form.vue +118 -0
  25. package/app/pages/dashboard/complex-view/schema-view/components/detail-panel/detail-panel.vue +177 -0
  26. package/app/pages/dashboard/complex-view/schema-view/components/edit-form/edit-form.vue +157 -0
  27. package/app/pages/dashboard/complex-view/schema-view/hook/schema.js +150 -0
  28. package/app/pages/dashboard/complex-view/schema-view/schema-view.vue +113 -0
  29. package/app/pages/dashboard/complex-view/sider-view/complex-view/sub-menu/sub-menu.vue +35 -0
  30. package/app/pages/dashboard/complex-view/sider-view/sider-view.vue +134 -0
  31. package/app/pages/dashboard/dashboard.vue +127 -0
  32. package/app/pages/dashboard/entry.dashboard.js +46 -0
  33. package/app/pages/store/index.js +5 -0
  34. package/app/pages/store/menu.js +61 -0
  35. package/app/pages/store/project.js +13 -0
  36. package/app/pages/widgets/header-container/asserts/avatar.png +0 -0
  37. package/app/pages/widgets/header-container/asserts/logo.png +0 -0
  38. package/app/pages/widgets/header-container/header-container.vue +144 -0
  39. package/app/pages/widgets/schema-form/complex-view/input/input.vue +165 -0
  40. package/app/pages/widgets/schema-form/complex-view/input-number/input-number.vue +166 -0
  41. package/app/pages/widgets/schema-form/complex-view/select/select.vue +144 -0
  42. package/app/pages/widgets/schema-form/form-item.config.js +24 -0
  43. package/app/pages/widgets/schema-form/schema-form.vue +144 -0
  44. package/app/pages/widgets/schema-search-bar/complex-view/date-range/date-range.vue +57 -0
  45. package/app/pages/widgets/schema-search-bar/complex-view/dynamic-select/dynamic-select.vue +77 -0
  46. package/app/pages/widgets/schema-search-bar/complex-view/input/input.vue +51 -0
  47. package/app/pages/widgets/schema-search-bar/complex-view/select/select.vue +58 -0
  48. package/app/pages/widgets/schema-search-bar/schema-search-bar.vue +138 -0
  49. package/app/pages/widgets/schema-search-bar/search-item-config.js +27 -0
  50. package/app/pages/widgets/schema-table/schema-table.vue +254 -0
  51. package/app/pages/widgets/sider-container/sider-container.vue +32 -0
  52. package/app/router/business.js +15 -0
  53. package/app/router/project.js +10 -0
  54. package/app/router/view.js +11 -0
  55. package/app/router-schema/business.js +82 -0
  56. package/app/router-schema/project.js +40 -0
  57. package/app/service/base.js +13 -0
  58. package/app/service/project.js +55 -0
  59. package/app/view/entry.tpl +27 -0
  60. package/app/webpack/config/blank.js +3 -0
  61. package/app/webpack/config/webpack.base.js +269 -0
  62. package/app/webpack/config/webpack.dev.js +61 -0
  63. package/app/webpack/config/webpack.prod.js +149 -0
  64. package/app/webpack/dev.js +58 -0
  65. package/app/webpack/prod.js +21 -0
  66. package/config/config.default.js +3 -0
  67. package/elpis-core/env.js +22 -0
  68. package/elpis-core/index.js +99 -0
  69. package/elpis-core/loader/config.js +51 -0
  70. package/elpis-core/loader/controller.js +75 -0
  71. package/elpis-core/loader/extend.js +54 -0
  72. package/elpis-core/loader/middleware.js +69 -0
  73. package/elpis-core/loader/router-schema.js +50 -0
  74. package/elpis-core/loader/router.js +52 -0
  75. package/elpis-core/loader/service.js +74 -0
  76. package/index.js +29 -0
  77. package/jsconfig.json +16 -0
  78. package/logs/applocation.log +3 -0
  79. package/model/index.js +119 -0
  80. package/package.json +93 -0
  81. package/test/controller/project.test.js +216 -0
@@ -0,0 +1,149 @@
1
+ const merge = require('webpack-merge')
2
+ const path = require('path')
3
+ const os = require('os')
4
+ const HappyPack = require('happypack')
5
+
6
+ const MiniCssExtractPlugin = require('mini-css-extract-plugin')
7
+ const CleanWebpackPlugin = require('clean-webpack-plugin')
8
+ const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')
9
+ const HtmlWebpackInjectAttributesPlugin = require('html-webpack-inject-attributes-plugin')
10
+ const TerserWebpackPlugin = require('terser-webpack-plugin')
11
+
12
+ // 多线程 build 配置
13
+ const happypackCommonConfig = {
14
+ // 是否开启调试模式,设为false表示不输出调试信息
15
+ debug: false,
16
+ // 创建一个线程池,大小为CPU核心数,用于并行处理任务
17
+ threadPool: HappyPack.ThreadPool({ size: os.cpus().length }),
18
+ }
19
+
20
+
21
+ // 基类配置
22
+ const baseConfig = require('./webpack.base.js')
23
+
24
+ // 生产环境配置
25
+ const webpackProdConfig = merge(baseConfig, {
26
+ mode: 'production',
27
+
28
+ output: {
29
+ // 定义输出文件名格式:在 js 目录下生成 [入口名称]_[8位chunkhash].bundle.js
30
+ filename: 'js/[name]_[chunkhash:8].bundle.js',
31
+ // 定义输出文件的绝对路径:当前工作目录下的 ./app/public/dist/prod
32
+ path: path.join(process.cwd(), './app/public/dist/prod/'),
33
+ // 指定浏览器访问资源的公共路径前缀
34
+ publicPath: '/dist/prod/',
35
+ // 设置跨域加载脚本时的 credentials 标志为 anonymous(不发送 cookies 等)
36
+ crossOriginLoading: 'anonymous'
37
+ },
38
+
39
+ module: {
40
+ rules: [{
41
+ test: /\.css$/,
42
+ use: [
43
+ // 1. 提取 loader(负责提取 CSS)
44
+ MiniCssExtractPlugin.loader,
45
+ // 2. CSS loader(负责解析 CSS)
46
+ `${require.resolve('happypack/loader')}?id=css`
47
+ ]
48
+ }, {
49
+ test: /\.js$/,
50
+ include: [
51
+ // 处理elpis目录中的文件
52
+ path.resolve(__dirname, '../../pages'),
53
+ // 处理业务目录文件
54
+ path.resolve(process.cwd(), './app/pages'),
55
+ ],
56
+ use: [
57
+ `${require.resolve('happypack/loader')}?id=js`,
58
+ ]
59
+ }]
60
+ },
61
+ // webpack 不会有大量 hits 信息, 默认为 warning
62
+ performance: {
63
+ hints: false
64
+ },
65
+
66
+ plugins: [
67
+ // 每次build前 , 清空 public/dist 目录
68
+ new CleanWebpackPlugin(['public/dist'], {
69
+ // 设置清理操作的根目录为 ./app 目录
70
+ root: path.resolve(process.cwd(),'./app'),
71
+ // 指定不需要删除的文件或目录(空数组表示全部删除)
72
+ exclude: [],
73
+ // 启用详细日志输出,显示删除过程
74
+ verbose: true,
75
+ // 设置为 false 表示执行实际删除操作(true 为模拟删除)
76
+ dry: false
77
+ }),
78
+
79
+ // 提取 css 公共部分,有效利用缓存 (非公共部分使用 inline )
80
+ new MiniCssExtractPlugin({
81
+ // 异步加载的CSS文件
82
+ chunkFilename: 'css/[name].[contenthash:8].bundle.css',
83
+ }),
84
+
85
+ // 优化并压缩css资源
86
+ new CssMinimizerPlugin(),
87
+
88
+ // 多线程打包 js ,加快打包速度
89
+ new HappyPack({
90
+ // 展开通用配置,包含调试设置和线程池配置
91
+ ...happypackCommonConfig,
92
+
93
+ // 指定loader的ID,用于在rules中引用
94
+ id: 'js',
95
+
96
+ // 配置需要使用的loader
97
+ loaders: [`${require.resolve('babel-loader')}?${JSON.stringify({
98
+ // Babel预设配置,用于转换ES6+语法到兼容性更好的ES5
99
+ presets: [require.resolve('@babel/preset-env')],
100
+ // Babel插件配置
101
+ plugins: [
102
+ // 优化Babel生成的代码,减少重复的帮助函数代码
103
+ require.resolve('@babel/plugin-transform-runtime')
104
+ ]
105
+ })}`]
106
+ }),
107
+
108
+ // 多线程打包 css
109
+ new HappyPack({
110
+ ...happypackCommonConfig,
111
+ id: 'css',
112
+ loaders: [{
113
+ path: require.resolve('css-loader'),
114
+ options: {
115
+ importLoaders: 1
116
+ }
117
+ }]
118
+ }),
119
+
120
+ // 浏览器在请求资源时,不会发送用户的身份凭证
121
+ new HtmlWebpackInjectAttributesPlugin({
122
+ // 确保加载外部资源时不携带身份凭证
123
+ crossorigin: 'anonymous'
124
+ })
125
+ ],
126
+
127
+ optimization: {
128
+ // 使用 TerserPlugin 的并发和缓存,提升压缩阶段的性能
129
+
130
+ // 启用代码压缩功能
131
+ minimize: true,
132
+
133
+ // 定义用于执行代码压缩的插件
134
+ minimizer: [
135
+ new TerserWebpackPlugin({
136
+ parallel: true, // 启用缓存来加速构建过程
137
+ cache: true, // 利用多核 CPU 的优势来提升构建速度
138
+ terserOptions: {
139
+ compress: {
140
+ drop_console: true, // 删除所有 console.* 语句
141
+ drop_debugger: true // 删除所有 debugger 语句
142
+ }
143
+ }
144
+ })
145
+ ]
146
+ }
147
+ })
148
+
149
+ module.exports = webpackProdConfig
@@ -0,0 +1,58 @@
1
+ // 本地开发启动 deserver
2
+ const express = require('express');
3
+ const consoler = require('consoler');
4
+ const webpack = require('webpack');
5
+ const path = require('path');
6
+ const devMiddleware = require('webpack-dev-middleware');
7
+ const hotMiddleware = require('webpack-hot-middleware');
8
+
9
+ module.exports = ()=>{
10
+ const {
11
+ webpackDevConfig,
12
+ DEV_SERVER_CONFIG
13
+ } = require('./config/webpack.dev.js');
14
+
15
+ const app = express();
16
+
17
+ const compiler = webpack(webpackDevConfig);
18
+
19
+ // 构建静态文件目录
20
+ app.use(express.static(path.join(__dirname, '../public/dist')))
21
+
22
+ // 引用 devMiddleware 中间件 监控文件改动
23
+ app.use(devMiddleware(compiler, {
24
+ // 落地文件
25
+ writeToDisk: (filePath) => {
26
+ // 只有以.tpl结尾的文件才写入磁盘,其余文件存储在内存中
27
+ return filePath.endsWith('.tpl')
28
+ },
29
+ // 资源路径
30
+ publicPath: webpackDevConfig.output.publicPath,
31
+
32
+ // headers 配置
33
+ headers: {
34
+ 'Access-Control-Allow-Origin': '*',
35
+ 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, PATCH, OPTIONS',
36
+ 'Access-Control-Allow-Headers': 'X-Requested-With, content-type, Authorization'
37
+ },
38
+ stats:{
39
+ colors: true
40
+ }
41
+ }))
42
+
43
+ // 引用 hotMiddleware 中间件 实现热更新通讯
44
+ app.use(hotMiddleware(compiler, {
45
+ path: `${DEV_SERVER_CONFIG.HMR_PATH}`,
46
+ log: () => {
47
+ }
48
+ }))
49
+
50
+ consoler.info('请等待webpack初次构建完成提示......')
51
+
52
+ // 启动devserver服务
53
+ const post = DEV_SERVER_CONFIG.PORT;
54
+ app.listen(post, () => {
55
+ consoler.info(`webpack-dev-server is listening on port ${post}`)
56
+ });
57
+
58
+ }
@@ -0,0 +1,21 @@
1
+ const webpack = require('webpack');
2
+ const webpackProdConfig = require('./config/webpack.prod.js')
3
+
4
+ console.log('\n 开始构建... \n')
5
+
6
+ module.exports = ()=>{
7
+ webpack(webpackProdConfig, (err, stats) => {
8
+ if (err) {
9
+ console.log(err)
10
+ return
11
+ }
12
+
13
+ process.stdout.write(`${stats.toString({
14
+ colors: true, // 在控制台输出色彩信息
15
+ modules: false, // 不显示模块信息
16
+ children: false, // 不显示子模块信息
17
+ chunks: false, // 不显示 chunk 信息
18
+ chunkModules: true // 显示代码块中模块信息
19
+ })}\n`)
20
+ })
21
+ }
@@ -0,0 +1,3 @@
1
+ module.exports = {
2
+ name:"elpis"
3
+ }
@@ -0,0 +1,22 @@
1
+ module.exports = (app) => {
2
+ return {
3
+ // 判断是否本地环境
4
+ isLocal() {
5
+ return process.env._ENV === 'local'
6
+ },
7
+
8
+ // 判断是否测试环境
9
+ isBeta() {
10
+ return process.env._ENV === 'beta'
11
+ },
12
+
13
+ // 判断是否生产环境
14
+ isProduction() {
15
+ return process.env._ENV === 'production'
16
+ },
17
+ // 获取当前环境
18
+ get() {
19
+ return process.env._ENV ?? 'local'
20
+ },
21
+ }
22
+ }
@@ -0,0 +1,99 @@
1
+ // 引入koa框架
2
+ const Koa = require('koa');
3
+ // 引入路径处理模块
4
+ const path = require('path');
5
+ const { sep } = path; // 处理不同操作系统的斜杠
6
+
7
+ // 引入环境配置
8
+ const env = require('./env');
9
+
10
+ // 引入加载器
11
+ const configLoader = require('./loader/config');
12
+ const extendLoader = require('./loader/extend');
13
+ const middlewareLoader = require('./loader/middleware');
14
+ const routerSchemaLoader = require('./loader/router-schema');
15
+ const serviceLoader = require('./loader/service');
16
+ const controllerLoader = require('./loader/controller');
17
+ const routerLoader = require('./loader/router');
18
+
19
+ module.exports = {
20
+ /**
21
+ * 启动项目
22
+ * @params options 项目配置
23
+ * options{
24
+ * name // 项目名称
25
+ * homePath // 项目首页
26
+ * }
27
+ */
28
+ start (options = {}) {
29
+ // 创建koa实例
30
+ const app = new Koa();
31
+ // 应用配置
32
+ app.options = options;
33
+
34
+ // 设置基础路径为当前工作目录 = 根目录
35
+ app.baseDir = process.cwd();
36
+
37
+ // 业务文件路径的绝对路径 = 根目录 + app目录 的绝对路径
38
+ app.businessPath = path.resolve(app.baseDir,`.${sep}app`);
39
+
40
+ // 初始化环境配置
41
+ app.env = env();
42
+ console.log(`-- [start] env: ${app.env.get()} --`);
43
+
44
+ // 加载配置
45
+ configLoader(app);
46
+ console.log(`-- [start] config done --`);
47
+
48
+ // 加载扩展
49
+ extendLoader(app);
50
+ console.log(`-- [start] extend done --`);
51
+
52
+ // 加载中间件
53
+ middlewareLoader(app);
54
+ console.log(`-- [start] middleware done --`);
55
+
56
+ // 加载路由配置
57
+ routerSchemaLoader(app);
58
+ console.log(`-- [start] routerSchema done --`);
59
+
60
+ // 加载服务
61
+ serviceLoader(app);
62
+ console.log(`-- [start] service done --`);
63
+
64
+ // 加载控制器
65
+ controllerLoader(app);
66
+ console.log(`-- [start] controller done --`);
67
+
68
+ // 注册elpis全局中间件
69
+ const elpisMiddlewarePath = path.resolve(__dirname,`..${sep}app${sep}middleware.js`);
70
+ const elpisMiddleware = require(elpisMiddlewarePath);
71
+ elpisMiddleware(app);
72
+ console.log(`-- [start] load global elpis middleware done --`);
73
+
74
+ // 注册业务全局中间件
75
+ try {
76
+ require(`${app.businessPath}${sep}middleware.js`)(app);
77
+ console.log(`-- [start] load global business middleware done --`);
78
+ } catch (e) {
79
+ console.log(`-- [exception] there is no global business middleware file --`);
80
+ }
81
+
82
+ // 加载路由
83
+ routerLoader(app);
84
+ console.log(`-- [start] router done --`);
85
+
86
+
87
+ // 启动服务
88
+ try {
89
+ const port = process.env.PORT || 8080;
90
+ const host = process.env.HOST || '0.0.0.0';
91
+ app.listen(port, host);
92
+ console.log(`Server running on port:${port}`);
93
+ } catch(e) {
94
+ console.error(e);
95
+ }
96
+
97
+ return app;
98
+ }
99
+ }
@@ -0,0 +1,51 @@
1
+ const path = require('path')
2
+ const { sep } = path
3
+
4
+ /**
5
+ * config loader
6
+ * @param {object} app koa 实例
7
+ *
8
+ * 通过区别 本地/测试/生产,通过env环境读取不同文件配置 env.config
9
+ * 通过env.config 覆盖 default.config 加载到 app.config 中
10
+ *
11
+ * 目录下对应的 config配置
12
+ * 默认配置 config/config.default.js
13
+ * 本地配置 config/config.local.js
14
+ * 测试配置 config/config.beta.js
15
+ * 生产配置 config/config.prod.js
16
+ */
17
+ module.exports = (app) => {
18
+ // elpis内部的默认配置文件(内部只有一个默认配置)
19
+ const elpisConfigPath = path.resolve(__dirname, `..${sep}..${sep}config`);
20
+ let defaultConfig = require(path.resolve(elpisConfigPath,`.${sep}config.default.js`));
21
+ // 找到config目录
22
+ const businessConfigPath = path.resolve(app.baseDir, `.${sep}config`);
23
+ // 业务配置、并且集成elpis默认配置
24
+ try {
25
+ defaultConfig = {
26
+ ...defaultConfig,
27
+ ...require(path.resolve(businessConfigPath, `.${sep}config.default.js`))
28
+ };
29
+ } catch (e) {
30
+ console.log(`[exception] 未配置 default.config.js)`);
31
+ // console.log(`[exception] there is no default.config.js:${e.message})`);
32
+ // console.debug(`[exception] Stack trace: ${e.stack}`);
33
+ }
34
+ // 获取env.config
35
+ let envConfig = {};
36
+ try {
37
+ if (app.env.isLocal()) { // 本地
38
+ envConfig = require(path.resolve(businessConfigPath, `.${sep}config.local.js`));
39
+ } else if (app.env.isBeta()) { // 测试
40
+ envConfig = require(path.resolve(businessConfigPath, `.${sep}config.beta.js`));
41
+ } else if (app.env.isProduction()) { // 生产
42
+ envConfig = require(path.resolve(businessConfigPath, `.${sep}config.prod.js`));
43
+ }
44
+ } catch (e) {
45
+ const envName = app.env.isLocal() ? 'local' : app.env.isBeta() ? 'beta' : 'prod';
46
+ console.log(`[exception] Failed to load config.${envName}.js: ${e.message}`);
47
+ console.debug(`[exception] Stack trace: ${e.stack}`);
48
+ }
49
+ // 覆盖并加载 config 配置
50
+ app.config = Object.assign({}, defaultConfig, envConfig);
51
+ }
@@ -0,0 +1,75 @@
1
+ const path = require('path')
2
+ const glob = require('glob')
3
+ const { sep } = path
4
+
5
+ /**
6
+ * controller loader
7
+ * @param {object} app Koa 实例
8
+ *
9
+ * 加载所有 controller 可通过 'app.controller.${目录}.${文件名}' 访问'
10
+ *
11
+ * 例如
12
+ * app/controller
13
+ * |
14
+ * | -- custom-module
15
+ * |
16
+ * | -- custom-controller.js
17
+ * => app.controller.customModule.customController
18
+ */
19
+
20
+ module.exports = (app) => {
21
+ const controller = {};
22
+
23
+ // elpis中的controller的加载
24
+ const elpisControllerPath = path.resolve(__dirname, `..${sep}..${sep}app${sep}controller`);
25
+ // 使用glob模式匹配查找所有嵌套目录下的.js文件 (**表示任意层级子目录)
26
+ const elpisControllerFileList = glob.sync(path.resolve(elpisControllerPath, `.${sep}**${sep}**.js`));
27
+ elpisControllerFileList.forEach(handleFile);
28
+
29
+ // 拼接控制器文件所在目录的完整路径 (如: D:\Elpis\app\controller)
30
+ const businessControllerPath = path.resolve(app.businessPath, `.${sep}controller`);
31
+ // 使用glob模式匹配查找所有嵌套目录下的.js文件 (**表示任意层级子目录)
32
+ const businessControllerFileList = glob.sync(path.resolve(businessControllerPath, `.${sep}**${sep}**.js`));
33
+
34
+ // 遍历所有文件目录,把内容加载到app.controller 下
35
+ businessControllerFileList.forEach(handleFile);
36
+
37
+ function handleFile(file) {
38
+ // 提取文件名
39
+ let name = path.resolve(file);
40
+
41
+ // 截取路径 => app/controller/custom-module/custom-controller.js => custom-module/custom-controller
42
+ name = name.substring(name.lastIndexOf(`controller${sep}`) + `controller${sep}`.length, name.lastIndexOf('.'))
43
+
44
+ // 把'-'统一成驼峰式,custom-module/custom-controller => customModule/customController
45
+ name = name.replace(/[_-][a-z]/ig, (s) => s.substring(1).toUpperCase());
46
+
47
+ // 挂载 controller 到内容 app 对象中
48
+
49
+ // 创建临时引用指向控制器容器,用于构建嵌套结构
50
+ let tempController = controller
51
+ // 将控制器路径按分隔符分割成数组,例如 'user/auth' => ['user'(目录), 'auth'(文件)]
52
+ const names = name.split(sep);
53
+ // 遍历路径数组,构建层次化的对象结构
54
+ for (let i = 0; i < names.length; i++){
55
+ // 判断是否为最后一层
56
+ if (i === names.length - 1){
57
+ // 创建控制器实例对象
58
+ // 1. 加载控制器模块并传入app实例,获取返回的控制器类
59
+ const ControllerModule = require(path.resolve(file))(app);
60
+ // 2. 实例化控制器类,创建具体的控制器对象实例
61
+ tempController[names[i]] = new ControllerModule();
62
+ }else{
63
+ // 处理控制器目录结构
64
+ // 如果当前层级的对象不存在,则创建空对象
65
+ if (!tempController[names[i]]){
66
+ tempController[names[i]] = {}
67
+ }
68
+ // 将临时引用指向下一层级,继续构建更深层的结构
69
+ tempController = tempController[names[i]]
70
+ }
71
+ }
72
+ };
73
+ // 挂载 middlewares 到内容 app 对象中
74
+ app.controller = controller;
75
+ }
@@ -0,0 +1,54 @@
1
+ const path = require("path")
2
+ const glob = require("glob")
3
+ const {sep} = path
4
+ /**
5
+ * entend loader
6
+ * @param {object} app Koa 实例
7
+ *
8
+ * 加载所有 extend, 可通过 'app.extend.${文件}访问'
9
+ *
10
+ * 例子:
11
+ * app/extend
12
+ * |
13
+ * | -- custom-extend.js
14
+ * => app.extend.customExtend 访问
15
+ */
16
+ module.exports = (app) => {
17
+
18
+ // 拼接elpis内部的extend
19
+ const elpisExtendPath = path.resolve(__dirname, `..${sep}..${sep}app${sep}extend`)
20
+ // 使用glob模式匹配查找extend目录下的所有.js文件
21
+ const elpisExtendFileList = glob.sync(path.resolve(elpisExtendPath, `.${sep}**${sep}**.js`))
22
+ elpisExtendFileList.forEach(handleFileList);
23
+
24
+ // 拼接extend目录的完整路径 (如: D:\Elpis\app\extend)
25
+ const businessExtendPath = path.resolve(app.businessPath, `.${sep}extend`)
26
+ // 使用glob模式匹配查找extend目录下的所有.js文件
27
+ const businessExtendFileList = glob.sync(path.resolve(businessExtendPath, `.${sep}**${sep}**.js`))
28
+
29
+ // 遍历所有找到的扩展文件
30
+ businessExtendFileList.forEach(handleFileList);
31
+ function handleFileList(file) {
32
+ // 提取文件的完整路径
33
+ let name = path.resolve(file)
34
+
35
+ // 截取路径 => app/extend/custom-extend.js => custom-extend
36
+ name = name.substring(name.indexOf(`extend${sep}`) + `extend${sep}`.length, name.indexOf('.'))
37
+
38
+ // 把'-'换成驼峰式,custom-extend => customExtend
39
+ name = name.replace(/[_-][a-z]/ig, (s) => s.substring(1).toUpperCase())
40
+
41
+ // 检查app中是否已存在同名属性,避免覆盖
42
+ for(const key in app){
43
+ if(key === name){
44
+ console.log(`[extend load error] name: ${name} is already in app `)
45
+ return;
46
+ }
47
+ }
48
+ // 加载扩展模块并传入app实例,将返回结果挂载到app上
49
+ // 例如: app.customExtend = require('custom-extend.js')(app)
50
+ app[name] = require(path.resolve(file))(app)
51
+
52
+ };
53
+
54
+ }
@@ -0,0 +1,69 @@
1
+ const path = require('path')
2
+ const glob = require('glob')
3
+ const { sep } = path
4
+
5
+ /**
6
+ * middleware loader
7
+ * @param {object} app Koa 实例
8
+ *
9
+ * 加载所有 middleware 可通过 'app.middlewares.${目录}.${文件名}' 访问'
10
+ *
11
+ * 例如
12
+ * app/middleware
13
+ * |
14
+ * | -- custom-moudle
15
+ * |
16
+ * | -- costom-middleware.js
17
+ * => app.middlewares.customMoudle.costomMiddleware
18
+ */
19
+
20
+ module.exports = (app) => {
21
+ const middlewares = {};
22
+ // 读取/elpis/app/middleware/**/**.js下的所有文件
23
+ const elpisMiddlePath = path.resolve(__dirname, `..${sep}..${sep}app${sep}middleware`);
24
+ // 使用glob模式匹配查找所有嵌套目录下的.js文件 (**表示任意层级子目录)
25
+ const elpisFileList = glob.sync(path.resolve(elpisMiddlePath, `.${sep}**${sep}**.js`));
26
+ elpisFileList.forEach(handleFile)
27
+
28
+ const businessMiddleWarePath = path.resolve(app.businessPath, `.${sep}middleware`);
29
+ // 使用glob模式匹配查找所有嵌套目录下的.js文件 (**表示任意层级子目录)
30
+ const businessFileList = glob.sync(path.resolve(businessMiddleWarePath, `.${sep}**${sep}**.js`));
31
+
32
+ // 遍历所有文件目录,把内容加载到app.middlewares下
33
+ businessFileList.forEach(handleFile);
34
+ function handleFile(file) {
35
+ // 提取文件名
36
+ let name = path.resolve(file);
37
+
38
+ // 截取路径 => app/middleware/custom-moudle/costom-middleware.js => custom-moudle/costom-middleware
39
+ name = name.substring(name.lastIndexOf(`middleware${sep}`) + `middleware${sep}`.length, name.lastIndexOf('.'))
40
+
41
+ // 把'-'统一成驼峰式,custom-moudle/costom-middleware => customMoudle/costomMiddleware
42
+ name = name.replace(/[_-][a-z]/ig, (s) => s.substring(1).toUpperCase());
43
+
44
+ // 挂载 middlewares 到内容 app 对象中
45
+
46
+ // 创建临时引用指向中间件容器,用于构建嵌套结构
47
+ let tempMiddleware = middlewares
48
+ // 将中间件路径按分隔符分割成数组,例如 'user/auth' => ['user', 'auth']
49
+ const names = name.split(sep);
50
+ // 遍历路径数组,构建层次化的对象结构
51
+ for (let i = 0; i < names.length; i++){
52
+ // 判断是否为最后一层
53
+ if (i === names.length - 1){
54
+ // 创建中间件对象
55
+ tempMiddleware[names[i]] = require(path.resolve(file))(app);
56
+ }else{
57
+ // 处理中间层目录结构
58
+ // 如果当前层级的对象不存在,则创建空对象
59
+ if (!tempMiddleware[names[i]]){
60
+ tempMiddleware[names[i]] = {}
61
+ }
62
+ // 将临时引用指向下一层级,继续构建更深层的结构
63
+ tempMiddleware = tempMiddleware[names[i]]
64
+ }
65
+ }
66
+ }
67
+ // 挂载 middlewares 到内容 app 对象中
68
+ app.middlewares = middlewares;
69
+ }
@@ -0,0 +1,50 @@
1
+ const path = require('path')
2
+ const glob = require('glob')
3
+ const { sep } = path
4
+
5
+ /**
6
+ * router-schema loader
7
+ * @param {object} app koa 实例
8
+ *
9
+ * 通过 'json-schema' & 'ajv' 对 API 规则进行约束, 配合 api-params-verify 中间件使用
10
+ *
11
+ * app/router-schema/**.js
12
+ *
13
+ * 输出:
14
+ * app.rouSchema = {
15
+ * '${api1}': ${jsonSschema},
16
+ * '${api2}': ${jsonSschema},
17
+ * '${api3}': ${jsonSschema},
18
+ * }
19
+ */
20
+ module.exports = (app) => {
21
+ // 注册所有 router-schema, 使得可以 'app.routerSchema' 这样访问
22
+ // 初始化空对象,用于存储所有路由规则
23
+ let routerSchema = {}
24
+
25
+ // 拼接中间件文件所在目录的完整路径
26
+ const elpisRouterPath = path.resolve(__dirname, `..${sep}..${sep}app${sep}router-schema`);
27
+ // 使用glob模式匹配查找所有嵌套目录下的.js文件 (**表示任意层级子目录)
28
+ const elpisRouterFileList = glob.sync(path.resolve(elpisRouterPath, `.${sep}**${sep}*.js`))
29
+ elpisRouterFileList.forEach(handleFile);
30
+ // 拼接中间件文件所在目录的完整路径
31
+ const businessRouterSchemaPath = path.resolve(app.businessPath, `.${sep}router-schema`)
32
+ // 使用glob模式匹配查找所有嵌套目录下的.js文件 (**表示任意层级子目录)
33
+ const businessFileList = glob.sync(path.resolve(businessRouterSchemaPath, `.${sep}**${sep}*.js`))
34
+
35
+ // 遍历所有找到的路由规则文件
36
+ businessFileList.forEach(handleFile);
37
+ function handleFile(file) {
38
+ if(!file) return;
39
+ // 将当前文件中的路由规则合并到 routerSchema 对象中
40
+ routerSchema = {
41
+ // 展开已有的路由规则(保持之前文件中已加载的规则)
42
+ ...routerSchema,
43
+
44
+ // 展开当前文件导出的路由规则(添加新规则)
45
+ ...require(path.resolve(file))
46
+ }
47
+ }
48
+
49
+ app.routerSchema = routerSchema
50
+ }