@wanglindoc/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 (88) hide show
  1. package/.eslintignore +2 -0
  2. package/.eslintrc +52 -0
  3. package/.idea/codeStyles/Project.xml +14 -0
  4. package/.idea/codeStyles/codeStyleConfig.xml +5 -0
  5. package/.idea/elpis.iml +12 -0
  6. package/.idea/inspectionProfiles/Project_Default.xml +6 -0
  7. package/.idea/modules.xml +8 -0
  8. package/.idea/prettier.xml +7 -0
  9. package/.idea/vcs.xml +6 -0
  10. package/README.md +232 -0
  11. package/app/controller/base.js +42 -0
  12. package/app/controller/project.js +76 -0
  13. package/app/controller/view.js +19 -0
  14. package/app/extend/logger.js +42 -0
  15. package/app/middleware/api-params-verify.js +81 -0
  16. package/app/middleware/api-sign-verify.js +45 -0
  17. package/app/middleware/error-handler.js +41 -0
  18. package/app/middleware/project-handler.js +30 -0
  19. package/app/middleware.js +42 -0
  20. package/app/pages/assets/custom.css +14 -0
  21. package/app/pages/boot.js +51 -0
  22. package/app/pages/common/curl.js +91 -0
  23. package/app/pages/common/utils.js +7 -0
  24. package/app/pages/dashboard/complex-view/header-view/complex-view/sub-menu/sub-menu.vue +18 -0
  25. package/app/pages/dashboard/complex-view/header-view/header-view.vue +154 -0
  26. package/app/pages/dashboard/complex-view/iframe-view/iframe-view.vue +46 -0
  27. package/app/pages/dashboard/complex-view/schema-view/complex-view/search-panel/search-panel.vue +40 -0
  28. package/app/pages/dashboard/complex-view/schema-view/complex-view/table-panel/table-panel.vue +127 -0
  29. package/app/pages/dashboard/complex-view/schema-view/components/component-config.js +22 -0
  30. package/app/pages/dashboard/complex-view/schema-view/components/create-form/create-form.vue +95 -0
  31. package/app/pages/dashboard/complex-view/schema-view/components/detail-panel/detail-panel.vue +104 -0
  32. package/app/pages/dashboard/complex-view/schema-view/components/edit-form/edit-form.vue +129 -0
  33. package/app/pages/dashboard/complex-view/schema-view/hook/schema.js +137 -0
  34. package/app/pages/dashboard/complex-view/schema-view/schema-view.vue +102 -0
  35. package/app/pages/dashboard/complex-view/sider-view/complex-view/sub-menu.vue +21 -0
  36. package/app/pages/dashboard/complex-view/sider-view/sider-view.vue +141 -0
  37. package/app/pages/dashboard/dashboard.vue +96 -0
  38. package/app/pages/dashboard/entry.dashboard.js +53 -0
  39. package/app/pages/dashboard/todo/todo.vue +6 -0
  40. package/app/pages/store/index.js +5 -0
  41. package/app/pages/store/menu.js +73 -0
  42. package/app/pages/store/project.js +15 -0
  43. package/app/pages/widgets/header-container/asserts/avatar.png +0 -0
  44. package/app/pages/widgets/header-container/asserts/logo.png +0 -0
  45. package/app/pages/widgets/header-container/header-container.vue +106 -0
  46. package/app/pages/widgets/schema-form/complex-view/input/input.vue +137 -0
  47. package/app/pages/widgets/schema-form/complex-view/input-number/input-number.vue +135 -0
  48. package/app/pages/widgets/schema-form/complex-view/select/select.vue +119 -0
  49. package/app/pages/widgets/schema-form/form-item-config.js +20 -0
  50. package/app/pages/widgets/schema-form/schema-form.vue +145 -0
  51. package/app/pages/widgets/schema-search-bar/complex-view/date-range/date-range.vue +52 -0
  52. package/app/pages/widgets/schema-search-bar/complex-view/dynamic-select/dynamic-select.vue +65 -0
  53. package/app/pages/widgets/schema-search-bar/complex-view/input/input.vue +42 -0
  54. package/app/pages/widgets/schema-search-bar/complex-view/select/select.vue +49 -0
  55. package/app/pages/widgets/schema-search-bar/schema-search-bar.vue +129 -0
  56. package/app/pages/widgets/schema-search-bar/search-item-config.js +24 -0
  57. package/app/pages/widgets/schema-table/schema-table.vue +212 -0
  58. package/app/pages/widgets/sider-container/sider-container.vue +26 -0
  59. package/app/public/output/entry.page1.tpl +55 -0
  60. package/app/public/output/entry.page2.tpl +11 -0
  61. package/app/public/static/favicon.ico +0 -0
  62. package/app/public/static/normalize.css +267 -0
  63. package/app/router/project.js +14 -0
  64. package/app/router/view.js +9 -0
  65. package/app/router-schema/project.js +32 -0
  66. package/app/service/base.js +15 -0
  67. package/app/service/project.js +48 -0
  68. package/app/view/entry.tpl +22 -0
  69. package/app/webpack/build-dev.js +64 -0
  70. package/app/webpack/build-prod.js +29 -0
  71. package/app/webpack/config/webpack.base.js +352 -0
  72. package/app/webpack/config/webpack.dev.js +59 -0
  73. package/app/webpack/config/webpack.prod.js +145 -0
  74. package/app/webpack/libs/blank.js +1 -0
  75. package/config/config.default.js +4 -0
  76. package/elpis-core/env.js +20 -0
  77. package/elpis-core/index.js +106 -0
  78. package/elpis-core/loader/config.js +62 -0
  79. package/elpis-core/loader/controller.js +79 -0
  80. package/elpis-core/loader/extend.js +67 -0
  81. package/elpis-core/loader/middleware.js +77 -0
  82. package/elpis-core/loader/router-schema.js +57 -0
  83. package/elpis-core/loader/router.js +57 -0
  84. package/elpis-core/loader/service.js +76 -0
  85. package/index.js +39 -0
  86. package/model/index.js +128 -0
  87. package/package.json +90 -0
  88. package/test/controller/project.test.js +243 -0
@@ -0,0 +1,352 @@
1
+ const path = require("path");
2
+ const webpack = require("webpack");
3
+ const fs = require("fs");
4
+ const merge = require("webpack-merge");
5
+ const { VueLoaderPlugin } = require("vue-loader");
6
+ const HtmlWebpackPlugin = require("html-webpack-plugin");
7
+
8
+ // 由于entry的配置内容和HtmlWebpackPlugin插件的配置内容都是相同的配置格式,只是文件名的差别,所以可以将这两部分的配置动态化
9
+ const glob = require("glob");
10
+
11
+ /**
12
+ * elpis 入口文件处理
13
+ * 约定好入口文件为统一存放在app/pages下,以entry.开头的文件
14
+ */
15
+ const elpisPageEntrys = {};
16
+ const elpisHtmlWebpackPluginList = [];
17
+
18
+ // 获取 elpis app/pages 目录下的所有入口文件 (entry.xx.js)
19
+ const elpisEntryPath = path.resolve(__dirname, "../../pages/**/entry.*.js");
20
+
21
+ glob
22
+ .sync(elpisEntryPath)
23
+ .forEach((file) =>
24
+ handleFile(file, elpisPageEntrys, elpisHtmlWebpackPluginList),
25
+ );
26
+
27
+ /**
28
+ * business 入口文件处理
29
+ * 约定好入口文件为统一存放在app/pages下,以entry.开头的文件
30
+ */
31
+ const businessPageEntrys = {};
32
+ const businessHtmlWebpackPluginList = [];
33
+
34
+ // 获取 business app/pages 目录下的所有入口文件 (entry.xx.js)
35
+ const businessEntryPath = path.resolve(
36
+ process.cwd(),
37
+ "./app/pages/**/entry.*.js",
38
+ );
39
+
40
+ glob
41
+ .sync(businessEntryPath)
42
+ .forEach((file) =>
43
+ handleFile(file, businessPageEntrys, businessHtmlWebpackPluginList),
44
+ );
45
+
46
+ function handleFile(file, entries = {}, htmlWebpackPluginList = []) {
47
+ const entryName = path.basename(file, ".js");
48
+ // 构造 entry
49
+ entries[entryName] = file;
50
+
51
+ // 构造最终渲染的页面文件
52
+ htmlWebpackPluginList.push(
53
+ // 将 chunks 中的代码块注入到 template 模板中生成 filename 文件
54
+ new HtmlWebpackPlugin({
55
+ // 产物: 最终模板的路径及文件名
56
+ filename: path.resolve(
57
+ process.cwd(),
58
+ "./app/public/dist/",
59
+ `${entryName}.tpl`,
60
+ ),
61
+
62
+ // 指定要是用的模版文件
63
+ template: path.resolve(__dirname, "../../view/entry.tpl"),
64
+
65
+ // 要注入的代码块
66
+ chunks: [entryName],
67
+ }),
68
+ );
69
+ }
70
+
71
+ // 加载业务 webpack 配置
72
+ let businessWebpackConfig = {};
73
+ try {
74
+ businessWebpackConfig = require(`${process.cwd()}/app/webpack.config.js`);
75
+ } catch (error) {}
76
+
77
+ /**
78
+ * webpack 基础配置
79
+ */
80
+ module.exports = merge.smart(
81
+ {
82
+ // 入口配置
83
+ entry: Object.assign({}, elpisPageEntrys, businessPageEntrys),
84
+
85
+ // 模块解析配置:决定了要加载解析哪些模块,以及用什么方式去解析
86
+ module: {
87
+ rules: [
88
+ {
89
+ test: /\.vue$/,
90
+ use: {
91
+ loader: require.resolve("vue-loader"),
92
+ },
93
+ },
94
+ {
95
+ test: /\.js$/,
96
+
97
+ // 只针对此路径下的js文件才去解析,其他文件不处理
98
+ include: [
99
+ // 只对 elpis 业务代码进行babel处理,加快webpack打包速度
100
+ path.resolve(__dirname, "../../pages"),
101
+ // 只对 business 业务代码进行babel处理,加快webpack打包速度
102
+ path.resolve(process.cwd(), "./app/pages"),
103
+ ],
104
+
105
+ use: {
106
+ loader: require.resolve("babel-loader"),
107
+ },
108
+ },
109
+ {
110
+ test: /\.(png|jpe?g|gif)(\?.+)?$/,
111
+ use: {
112
+ loader: require.resolve("url-loader"),
113
+ options: {
114
+ limit: 300, // 大小限制
115
+ esModule: false,
116
+ },
117
+ },
118
+ },
119
+ {
120
+ test: /\.css$/,
121
+ use: [require.resolve("style-loader"), require.resolve("css-loader")], // 从右到左链式调用
122
+ },
123
+ {
124
+ test: /\.less$/,
125
+ use: [
126
+ require.resolve("style-loader"),
127
+ require.resolve("css-loader"),
128
+ require.resolve("less-loader"),
129
+ ], // 从右到左链式调用
130
+ },
131
+ {
132
+ test: /\.(eot|svg|ttf|woff|woff2)(\?\S*)?$/,
133
+ use: require.resolve("file-loader"),
134
+ },
135
+ ],
136
+ },
137
+
138
+ // 产物输出配置
139
+ // 因为开发和生产环境输出不一致,所以这部分需要对应各自的环境自行配置,所以此处留空
140
+ output: {
141
+ // filename: "js/[name]_[chunkhash:8].bundle.js",
142
+ // path: path.join(process.cwd(), "./app/public/dist/prod"),
143
+ // publicPath: "/dist/prod",
144
+ // crossOriginLoading: "anonymous",
145
+ },
146
+
147
+ // 配置模块解析的具体行为(定义webpack在打包时,如何找到并解析具体模块的路径)
148
+ resolve: {
149
+ extensions: [".js", ".vue", ".less", ".css"],
150
+ alias: (() => {
151
+ const aliasMap = {};
152
+ const blankModulePath = path.resolve(__dirname, "../libs/blank.js");
153
+
154
+ // dashboard 路由拓展配置
155
+ const businessDashboardRouterConfig = path.resolve(
156
+ process.cwd(),
157
+ "./app/pages/dashboard/router.js",
158
+ );
159
+
160
+ aliasMap["$businessDashboardRouterConfig"] = fs.existsSync(
161
+ businessDashboardRouterConfig,
162
+ )
163
+ ? businessDashboardRouterConfig
164
+ : blankModulePath;
165
+
166
+ // schema-view component 拓展配置
167
+ const businessComponentConfig = path.resolve(
168
+ process.cwd(),
169
+ "./app/pages/dashboard/complex-view/schema-view/components/component-config.js",
170
+ );
171
+
172
+ aliasMap["$businessComponentConfig"] = fs.existsSync(
173
+ businessComponentConfig,
174
+ )
175
+ ? businessComponentConfig
176
+ : blankModulePath;
177
+
178
+ // schema-Form component 拓展配置
179
+ const businessFormItemConfig = path.resolve(
180
+ process.cwd(),
181
+ "./app/pages/widgets/schema-form/form-item-config.js",
182
+ );
183
+
184
+ aliasMap["$businessFormItemConfig"] = fs.existsSync(
185
+ businessFormItemConfig,
186
+ )
187
+ ? businessFormItemConfig
188
+ : blankModulePath;
189
+
190
+ // schema-search-bar component 拓展配置
191
+ const businessSearchItemConfig = path.resolve(
192
+ process.cwd(),
193
+ "./app/pages/widgets/schema-search-bar/search-item-config.js",
194
+ );
195
+ aliasMap["$businessSearchItemConfig"] = fs.existsSync(
196
+ businessSearchItemConfig,
197
+ )
198
+ ? businessSearchItemConfig
199
+ : blankModulePath;
200
+
201
+ return {
202
+ vue: require.resolve("vue"),
203
+ "@babel/runtime/helpers/toConsumableArray":
204
+ require.resolve("@babel/runtime/helpers/toConsumableArray"),
205
+ "@babel/runtime/helpers/asyncToGenerator":
206
+ require.resolve("@babel/runtime/helpers/asyncToGenerator"),
207
+ "@babel/runtime/regenerator":
208
+ require.resolve("@babel/runtime/regenerator"),
209
+
210
+ $elpisPages: path.resolve(__dirname, "../../pages"),
211
+
212
+ $elpisCommon: path.resolve(__dirname, "../../pages/common"),
213
+ $elpisCurl: path.resolve(__dirname, "../../pages/common/curl.js"),
214
+ $elpisUtils: path.resolve(__dirname, "../../pages/common/utils.js"),
215
+
216
+ $elpisWidgets: path.resolve(__dirname, "../../pages/widgets"),
217
+ $elpisHeaderContainer: path.resolve(
218
+ __dirname,
219
+ "../../pages/widgets/header-container/header-container.vue",
220
+ ),
221
+ $elpisSiderContainer: path.resolve(
222
+ __dirname,
223
+ "../../pages/widgets/sider-container/sider-container.vue",
224
+ ),
225
+ $elpisSchemaTable: path.resolve(
226
+ __dirname,
227
+ "../../pages/widgets/schema-table/schema-table.vue",
228
+ ),
229
+ $elpisSchemaForm: path.resolve(
230
+ __dirname,
231
+ "../../pages/widgets/schema-form/schema-form.vue",
232
+ ),
233
+ $elpisSchemaSearchBar: path.resolve(
234
+ __dirname,
235
+ "../../pages/widgets/schema-search-bar/schema-search-bar.vue",
236
+ ),
237
+
238
+ $elpisStore: path.resolve(__dirname, "../../pages/store"),
239
+ $elpisBoot: path.resolve(__dirname, "../../pages/boot.js"),
240
+
241
+ // $businessDashboardRouterConfig: path.resolve(
242
+ // process.cwd(),
243
+ // "./app/pages/dashboard/router.js",
244
+ // ),
245
+
246
+ ...aliasMap,
247
+ };
248
+ })(),
249
+ },
250
+
251
+ // 配置 webpack 插件
252
+ // plugins 配置是在打包构建(工程化)过程中, 在webpack不同的生命周期去介入的能力
253
+ plugins: [
254
+ // 处理 .vue 文件的插件
255
+ // 将定义过的其他规则复制并应用到 .vue 文件里
256
+ // 例如:如果有一条匹配规则 /\.js$/ 的规则(import xxx from 'xxx.js'),那么它将被应用到 .vue 文件中的 <script> 板块中。
257
+ new VueLoaderPlugin(),
258
+
259
+ // 把第三方库暴露到 window context 下
260
+ new webpack.ProvidePlugin({
261
+ // $: "jquery",
262
+ Vue: "vue",
263
+ axios: "axios",
264
+ _: "lodash",
265
+ }),
266
+
267
+ // 定义全局常量
268
+ new webpack.DefinePlugin({
269
+ __VUE_OPTIONS_API__: "true", // 支持 vue 解析 options API
270
+ __VUE_PROD_DEVTOOLS__: "false", // 禁用 Vue 调试工具
271
+ __VUE_PROD_HYDRATION_MISMATCH_DETAILS__: "false", // 禁用生产环境显示 "水合" 信息
272
+ }),
273
+
274
+ // 构建最终渲染的页面模板
275
+ // 将 chunks 中的代码块注入到 template 模板中生成 filename 文件
276
+ // new HtmlWebpackPlugin({
277
+ // // 产物: 最终模板
278
+ // filename: path.resolve(
279
+ // process.cwd(),
280
+ // "./app/public/dist/",
281
+ // "entry.page1.tpl"
282
+ // ),
283
+
284
+ // // 指定要是用的模版文件
285
+ // template: path.resolve(process.cwd(), "./app/view/entry.tpl"),
286
+
287
+ // // 要注入的代码块
288
+ // chunks: ["entry.page1"],
289
+ // }),
290
+
291
+ // new HtmlWebpackPlugin({
292
+ // // 产物: 最终模板
293
+ // filename: path.resolve(
294
+ // process.cwd(),
295
+ // "./app/public/dist/",
296
+ // "entry.page2.tpl"
297
+ // ),
298
+
299
+ // // 指定要是用的模版文件
300
+ // template: path.resolve(process.cwd(), "./app/view/entry.tpl"),
301
+
302
+ // // 要注入的代码块
303
+ // chunks: ["entry.page2"],
304
+ // }),
305
+ ...elpisHtmlWebpackPluginList,
306
+ ...businessHtmlWebpackPluginList,
307
+ ],
308
+
309
+ // 配置打包输出优化(代码分割,模块合并,缓存,treeshaing,压缩等优化策略)
310
+ optimization: {
311
+ // common文件夹中存放的utils文件是系统的工具类函数,它在page1和page2中都被引入
312
+ // 所以也会被分别打包至page1.bundle.js和page2.bundle.js中
313
+ // 所以在加载page1和page2时会加载同一段utils代码,可以将其单独打包
314
+ /**
315
+ * 把 js 文件打包成3种类型
316
+ * 1、vendor: 第三方 lib 库,基本不会变动,除非依赖版本升级
317
+ * 2、common:业务组件代码的公共部分抽取出来,改动较少
318
+ * 3、entry.{page}:不同页面 entry 里面的业务组件代码的差异部分,会经常改动
319
+ * 目的:把改动和引用频率不一样的 js 区分出来,以达到更好利用浏览器缓存的效果
320
+ */
321
+ splitChunks: {
322
+ chunks: "all", // 对同步和异步模块都进行分割
323
+ maxAsyncRequests: 10, // 每次异步加载的最大请求数
324
+ maxInitialRequests: 10, // 入口点最大并行请求数
325
+ // 配置打包规则
326
+ cacheGroups: {
327
+ // 第三方依赖库
328
+ vendor: {
329
+ test: /[\\/]node_modules[\\/]/, // 打包 node_modules 中的文件
330
+ name: "vendor", // 模块名称
331
+ priority: 20, // 分包策略的优先级,数字越大,优先级越高
332
+ enforce: true, // 强制执行
333
+ reuseExistingChunk: true, // 复用已有的公共 chunk
334
+ },
335
+
336
+ // 公共模块
337
+ common: {
338
+ test: /[\\/]common|widgets[\\/]/,
339
+ name: "common", // 模块名称
340
+ minChunks: 2, // 被两处引用即被归为公共模块
341
+ minSize: 1, // 最小分割文件大小 (1 byte)单位是字节
342
+ priority: 10, // 分包策略的优先级,数字越大,优先级越高
343
+ reuseExistingChunk: true, // 复用已有的公共 chunk
344
+ },
345
+ },
346
+ },
347
+ // 将 webpack 运行时生成的代码打包到 runtime.js
348
+ runtimeChunk: true,
349
+ },
350
+ },
351
+ businessWebpackConfig, // 业务 webpack 配置
352
+ );
@@ -0,0 +1,59 @@
1
+ const path = require("path");
2
+ const webpack = require("webpack");
3
+ // 配置合并
4
+ const merge = require("webpack-merge");
5
+
6
+ // 基类配置
7
+ const webpackBaseConfig = require("./webpack.base");
8
+
9
+ // devServer配置
10
+ const DEV_SERVER_CONFIG = {
11
+ HOST: "127.0.0.1",
12
+ PORT: 9002,
13
+ HMR_PATH: "_webpack-hmr", // 官方规定
14
+ TIME_OUT: 20000,
15
+ };
16
+
17
+ // 开发阶段的 entry 配置需要加入 hmr
18
+ Object.keys(webpackBaseConfig.entry).forEach((v) => {
19
+ // 第三方包不作为 hmr 入口
20
+ if (v !== "vendor") {
21
+ webpackBaseConfig.entry[v] = [
22
+ webpackBaseConfig.entry[v],
23
+ `${require.resolve("webpack-hot-middleware/client")}?path=http://${DEV_SERVER_CONFIG.HOST}:${DEV_SERVER_CONFIG.PORT}/${DEV_SERVER_CONFIG.HMR_PATH}&timeout=${DEV_SERVER_CONFIG.TIME_OUT}&reload=true`,
24
+ ];
25
+ }
26
+ });
27
+
28
+ // 开发环境webpack配置
29
+ const webpackDevConfig = merge.smart(webpackBaseConfig, {
30
+ // 指定开发环境
31
+ mode: "development",
32
+
33
+ // source-map 开发工具,呈现代码的映射关系,便于在开发过程中调试代码
34
+ devtool: "eval-cheap-module-source-map",
35
+
36
+ // 开发环境的output配置
37
+ output: {
38
+ filename: "js/[name]_[chunkhash:8].bundle.js",
39
+ path: path.resolve(process.cwd(), "./app/public/dist/dev/"), // 输出文件存储路径
40
+ publicPath: `http://${DEV_SERVER_CONFIG.HOST}:${DEV_SERVER_CONFIG.PORT}/public/dist/dev/`, // 外部资源公共路径,页面引用服务端js、css代码片段的路径
41
+ globalObject: "this",
42
+ },
43
+
44
+ // 开发阶段插件
45
+ plugins: [
46
+ // HotModuleReplacementPlugin 用于实现热模块替换 简称 HMR
47
+ // 模块热替换允许在程序运行时替换模块,极大提高开发效率,因为能让应用程序一直保持运行状态
48
+ new webpack.HotModuleReplacementPlugin({
49
+ multiStep: false,
50
+ }),
51
+ ],
52
+ });
53
+
54
+ module.exports = {
55
+ // webpack 配置
56
+ webpackDevConfig,
57
+ // devServer 配置,暴露给 build-dev.js 使用
58
+ DEV_SERVER_CONFIG,
59
+ };
@@ -0,0 +1,145 @@
1
+ const path = require("path");
2
+ // 配置合并
3
+ const merge = require("webpack-merge");
4
+
5
+ // 涉及多线程,需要用到 os 模块
6
+ const os = require("os");
7
+ const HappyPack = require("happypack"); // 多线程打包工具
8
+
9
+ // 多线程打包配置
10
+ const happypackCommonConfig = {
11
+ debug: false,
12
+ threadPool: HappyPack.ThreadPool({ size: os.cpus().length }),
13
+ };
14
+
15
+ // 提取css公共部分
16
+ const MiniCssExtractPlugin = require("mini-css-extract-plugin");
17
+
18
+ // 清空打包结果目录
19
+ const CleanWebpackPlugin = require("clean-webpack-plugin");
20
+
21
+ // css压缩插件
22
+ const CssMinimizerWebpackPlugin = require("css-minimizer-webpack-plugin");
23
+
24
+ //
25
+ const HtmlWebpackInjectAttributesPlugin = require("html-webpack-inject-attributes-plugin");
26
+
27
+ //
28
+ const TerserWebpackPlugin = require("terser-webpack-plugin");
29
+
30
+ // 基类配置
31
+ const webpackBaseConfig = require("./webpack.base");
32
+
33
+ // 生产环境webpack配置
34
+ const webpackProdConfig = merge.smart(webpackBaseConfig, {
35
+ // 指定生产环境
36
+ mode: "production",
37
+
38
+ // 生产环境的output配置
39
+ output: {
40
+ filename: "js/[name]_[chunkhash:8].bundle.js",
41
+ path: path.join(process.cwd(), "./app/public/dist/prod/"),
42
+ publicPath: "/dist/prod/",
43
+ crossOriginLoading: "anonymous",
44
+ },
45
+
46
+ // 打包可以多线程,优化打包速度
47
+ module: {
48
+ rules: [
49
+ {
50
+ test: /\.css$/,
51
+ // 使用MiniCssExtractPlugin插件打包并压缩css文件,同时通过happypack启用多线程打包
52
+ use: [
53
+ MiniCssExtractPlugin.loader,
54
+ `${require.resolve("happypack/loader")}?id=css`,
55
+ ], // 后面跟的ID是 plugin 中 new HappyPack 配置的ID,通过loader调用对应的plugin
56
+ },
57
+ {
58
+ test: /\.js$/,
59
+ include: [
60
+ // 处理 elpis 目录
61
+ path.resolve(__dirname, "../../pages"),
62
+ // 处理 business 目录
63
+ path.resolve(process.cwd(), "./app/pages"),
64
+ ],
65
+ use: [`${require.resolve("happypack/loader")}?id=js`], // 后面跟的ID是 plugin 中 new HappyPack 配置的ID,通过loader调用对应的plugin
66
+ },
67
+ ],
68
+ },
69
+
70
+ // webpack不会有大量的hints信息
71
+ performance: {
72
+ hints: false,
73
+ },
74
+
75
+ plugins: [
76
+ // 每次打包前,清空 public/dist 目录
77
+ new CleanWebpackPlugin(["public/dist"], {
78
+ root: path.resolve(process.cwd(), "./app/"),
79
+ exclude: [],
80
+ verbose: true,
81
+ dry: false,
82
+ }),
83
+
84
+ // 提取 css 的公共部分,有效利用缓存,(非公共部分使用 inline)
85
+ new MiniCssExtractPlugin({
86
+ chunkFilename: "css/[name]_[contenthash:8].bundle.css",
87
+ }),
88
+
89
+ // 优化并压缩css资源
90
+ new CssMinimizerWebpackPlugin(),
91
+
92
+ // 多线程打包js,加快打包速度
93
+ new HappyPack({
94
+ ...happypackCommonConfig,
95
+ id: "js",
96
+ loaders: [
97
+ `${require.resolve("babel-loader")}?${JSON.stringify({
98
+ presets: [require.resolve("@babel/preset-env")],
99
+ plugins: [require.resolve("@babel/plugin-transform-runtime")],
100
+ })}`,
101
+ ],
102
+ }),
103
+
104
+ // 多线程打包css,加快打包速度
105
+ new HappyPack({
106
+ ...happypackCommonConfig,
107
+ id: "css",
108
+ loaders: [
109
+ {
110
+ path: require.resolve("css-loader"),
111
+ options: {
112
+ importLoaders: 1,
113
+ },
114
+ },
115
+ ],
116
+ }),
117
+
118
+ // 浏览器在请求资源时不发送用户的身份凭证
119
+ new HtmlWebpackInjectAttributesPlugin({
120
+ crossorigin: "anonymous",
121
+ }),
122
+ ],
123
+
124
+ optimization: {
125
+ // 使用 TerserWebpackPlugin 的并发和缓存,提升压缩阶段的性能
126
+ // 清除 console.log
127
+ minimize: true, // 压缩代码
128
+ minimizer: [
129
+ new TerserWebpackPlugin({
130
+ // 启用缓存来加速构建过程
131
+ cache: true,
132
+ // 利用多核 cpu 的优势来加快压缩速度
133
+ parallel: true,
134
+ terserOptions: {
135
+ compress: {
136
+ // 去掉console.log内容
137
+ drop_console: true,
138
+ },
139
+ },
140
+ }),
141
+ ],
142
+ },
143
+ });
144
+
145
+ module.exports = webpackProdConfig;
@@ -0,0 +1 @@
1
+ module.exports = {};
@@ -0,0 +1,4 @@
1
+ module.exports = {
2
+ name: "elpis",
3
+ desc: "elpis",
4
+ };
@@ -0,0 +1,20 @@
1
+ module.exports = (app) => {
2
+ return {
3
+ // 判断是否本地环境
4
+ isLocal() {
5
+ return process.env._ENV === "local";
6
+ },
7
+ // 判断是否测试环境
8
+ isBeta() {
9
+ return process.env._ENV === "beta";
10
+ },
11
+ // 判断是否生产环境
12
+ isProduction() {
13
+ return process.env._ENV === "prod";
14
+ },
15
+ // 获取当前环境
16
+ get() {
17
+ return process.env._ENV ?? "local";
18
+ },
19
+ };
20
+ };
@@ -0,0 +1,106 @@
1
+ const Koa = require("koa");
2
+
3
+ // 涉及到路径需要用到path
4
+ const path = require("path");
5
+
6
+ // 兼容不同操作系统上的斜杠 /
7
+ const { sep } = path;
8
+
9
+ // 引入环境文件
10
+ const env = require("./env");
11
+
12
+ // 引入loader
13
+ const middlewareLoader = require("./loader/middleware");
14
+ const routerSchemaLoader = require("./loader/router-schema");
15
+ const controllerLoader = require("./loader/controller");
16
+ const serviceLoader = require("./loader/service");
17
+ const configLoader = require("./loader/config");
18
+ const extendLoader = require("./loader/extend");
19
+ const routerLoader = require("./loader/router");
20
+
21
+ module.exports = {
22
+ /**
23
+ * 启动项目
24
+ * @param {*} options 项目配置
25
+ * options = {
26
+ * name, // 项目名称
27
+ * homePage, // 项目首页
28
+ * }
29
+ */
30
+ start(options = {}) {
31
+ // koa实例
32
+ const app = new Koa();
33
+
34
+ // 应用配置
35
+ app.options = options;
36
+
37
+ // 基础路径(项目根目录)
38
+ app.baseDir = process.cwd();
39
+
40
+ // 业务文件路径 (./app)
41
+ app.businessPath = path.resolve(app.baseDir, `.${sep}app`);
42
+
43
+ // 挂载环境文件
44
+ app.env = env();
45
+ console.log(`-- [start] env: ${app.env.get()} --`);
46
+
47
+ // 加载 middleware
48
+ middlewareLoader(app);
49
+ console.log("-- [start] load middlewareLoader done --");
50
+
51
+ // 加载 routerSchema
52
+ routerSchemaLoader(app);
53
+ console.log("-- [start] load routerSchemaLoader done --");
54
+
55
+ // 加载 controller
56
+ controllerLoader(app);
57
+ console.log("-- [start] load controllerLoader done --");
58
+
59
+ // 加载 service
60
+ serviceLoader(app);
61
+ console.log("-- [start] load serviceLoader done --");
62
+
63
+ // 加载 config
64
+ configLoader(app);
65
+ console.log("-- [start] load configLoader done --");
66
+
67
+ // 加载 extend
68
+ extendLoader(app);
69
+ console.log("-- [start] load extendLoader done --");
70
+
71
+ // 挂载所有中间件
72
+ // 注册 elpis 全局中间件 (用户引用的外部中间件: 全部写在 app/middleware.js 文件下)
73
+ const elpisMiddlewarePath = path.resolve(
74
+ __dirname,
75
+ `..${sep}app${sep}middleware.js`,
76
+ );
77
+ const elpisMiddleware = require(elpisMiddlewarePath);
78
+ elpisMiddleware(app);
79
+ console.log("-- [start] load elpis global middleware done --");
80
+
81
+ // 注册业务全局中间件 (用户引用的外部中间件: 全部写在 app/middleware.js 文件下)
82
+ try {
83
+ require(`${app.businessPath}${sep}middleware.js`)(app);
84
+ console.log("-- [start] load business global middleware done --");
85
+ } catch (error) {
86
+ console.log("[exception] there is no business global middleware file");
87
+ }
88
+
89
+ // 注册路由 (注: 路由注册必须在最后)
90
+ routerLoader(app);
91
+ console.log("-- [start] load routerLoader done --");
92
+
93
+ // 启动服务
94
+ try {
95
+ const host = process.env.HOST || "0.0.0.0";
96
+ const port = process.env.PORT || 3000;
97
+ app.listen(port, host, () => {
98
+ console.log(`server is running at http://${host}:${port}`);
99
+ });
100
+ } catch (error) {
101
+ console.error(error);
102
+ }
103
+
104
+ return app;
105
+ },
106
+ };