@misstalor17/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 (84) hide show
  1. package/.eslintignore +3 -0
  2. package/.eslintrc +56 -0
  3. package/README.md +6 -0
  4. package/app/controller/base.js +43 -0
  5. package/app/controller/business.js +121 -0
  6. package/app/controller/project.js +75 -0
  7. package/app/controller/view.js +24 -0
  8. package/app/extend/logger.js +37 -0
  9. package/app/middleware/api-params-verify.js +70 -0
  10. package/app/middleware/api-sign-verify.js +31 -0
  11. package/app/middleware/error-handler.js +32 -0
  12. package/app/middleware/project-handler.js +28 -0
  13. package/app/middleware.js +44 -0
  14. package/app/pages/asserts/custom.css +12 -0
  15. package/app/pages/boot.js +45 -0
  16. package/app/pages/common/curl.js +96 -0
  17. package/app/pages/common/utils.js +2 -0
  18. package/app/pages/dashboard/complex-view/header-view/complex-view/sub-menu.vue +22 -0
  19. package/app/pages/dashboard/complex-view/header-view/header-view.vue +106 -0
  20. package/app/pages/dashboard/complex-view/iframe-view/iframe-view.vue +45 -0
  21. package/app/pages/dashboard/complex-view/schema-view/complex-view/search-panel/search-panel.vue +33 -0
  22. package/app/pages/dashboard/complex-view/schema-view/complex-view/table-panel/table-panel.vue +105 -0
  23. package/app/pages/dashboard/complex-view/schema-view/components/component-config.js +23 -0
  24. package/app/pages/dashboard/complex-view/schema-view/components/create-form/create-form.vue +85 -0
  25. package/app/pages/dashboard/complex-view/schema-view/components/detail-panel/detail-panel.vue +90 -0
  26. package/app/pages/dashboard/complex-view/schema-view/components/edit-form/edit-form.vue +113 -0
  27. package/app/pages/dashboard/complex-view/schema-view/hook/schema.js +109 -0
  28. package/app/pages/dashboard/complex-view/schema-view/schema-view.vue +66 -0
  29. package/app/pages/dashboard/complex-view/sider-view/complex-view/sub-menu/sub-menu.vue +17 -0
  30. package/app/pages/dashboard/complex-view/sider-view/sider-view.vue +116 -0
  31. package/app/pages/dashboard/dashboard.vue +96 -0
  32. package/app/pages/dashboard/entry.dashboard.js +45 -0
  33. package/app/pages/store/index.js +3 -0
  34. package/app/pages/store/menu.js +60 -0
  35. package/app/pages/store/project.js +17 -0
  36. package/app/pages/widgets/header-container/asserts/logo.png +0 -0
  37. package/app/pages/widgets/header-container/asserts/user.png +0 -0
  38. package/app/pages/widgets/header-container/header-container.vue +105 -0
  39. package/app/pages/widgets/schema-form/complex-view/input/input.vue +120 -0
  40. package/app/pages/widgets/schema-form/complex-view/input-number/input-number.vue +121 -0
  41. package/app/pages/widgets/schema-form/complex-view/select/select.vue +106 -0
  42. package/app/pages/widgets/schema-form/form-item-config.js +20 -0
  43. package/app/pages/widgets/schema-form/schema-form.vue +122 -0
  44. package/app/pages/widgets/schema-search-bar/complex-view/date-range/date-range.vue +42 -0
  45. package/app/pages/widgets/schema-search-bar/complex-view/dynamic-select/dynamic-select.vue +55 -0
  46. package/app/pages/widgets/schema-search-bar/complex-view/input/input.vue +37 -0
  47. package/app/pages/widgets/schema-search-bar/complex-view/select/select.vue +41 -0
  48. package/app/pages/widgets/schema-search-bar/schema-search-bar.vue +109 -0
  49. package/app/pages/widgets/schema-search-bar/search-item-config.js +23 -0
  50. package/app/pages/widgets/schema-table/schema.table.vue +191 -0
  51. package/app/pages/widgets/sider-container/sider-container.vue +34 -0
  52. package/app/public/static/logo.png +0 -0
  53. package/app/public/static/normalize.css +240 -0
  54. package/app/router/business.js +9 -0
  55. package/app/router/project.js +6 -0
  56. package/app/router/view.js +13 -0
  57. package/app/router-schema/business.js +82 -0
  58. package/app/router-schema/project.js +31 -0
  59. package/app/service/base.js +13 -0
  60. package/app/service/project.js +40 -0
  61. package/app/view/entry.tpl +25 -0
  62. package/app/webpack/config/webpack.base.js +204 -0
  63. package/app/webpack/config/webpack.dev.js +56 -0
  64. package/app/webpack/config/webpack.prod.js +116 -0
  65. package/app/webpack/dev.js +52 -0
  66. package/app/webpack/libs/blank.js +1 -0
  67. package/app/webpack/prod.js +17 -0
  68. package/config/config.default.js +3 -0
  69. package/docs/dashboard-model.js +143 -0
  70. package/elpis-core/env.js +23 -0
  71. package/elpis-core/index.js +93 -0
  72. package/elpis-core/loader/config.js +52 -0
  73. package/elpis-core/loader/controller.js +61 -0
  74. package/elpis-core/loader/extend.js +52 -0
  75. package/elpis-core/loader/middleware.js +61 -0
  76. package/elpis-core/loader/router-schema.js +46 -0
  77. package/elpis-core/loader/router.js +43 -0
  78. package/elpis-core/loader/service.js +61 -0
  79. package/index.js +38 -0
  80. package/model/buiness/model.js +200 -0
  81. package/model/index.js +93 -0
  82. package/npminstall-debug.log +218 -0
  83. package/package.json +92 -0
  84. package/test/controller/project.test.js +194 -0
@@ -0,0 +1,13 @@
1
+ module.exports = (app, router) => {
2
+ // 从app的controller对象中,解构出名为view的控制器,并重命名为viewController
3
+ // (这里的app.controller是你项目中统一管理控制器的地方,之前的ViewController应该被注册到了这里)
4
+ const { view: viewController } = app.controller;
5
+
6
+ // 注释说明:用户访问http://ip:port/view/xxx,就能渲染对应页面
7
+ // 给router注册一个GET请求的路由:
8
+ // 路径是/view/:page(:page是动态参数,比如访问/view/index,page的值就是index)
9
+ // 对应的处理方法是viewController里的renderPage,同时用bind绑定控制器的this指向(避免方法内this丢失)
10
+ router.get('/view/:page', viewController.renderPage.bind(viewController))
11
+ //用户访问http://ip:port/view/xxx/xxx/*,就能渲染对应页面
12
+ router.get('/view/:page/*', viewController.renderPage.bind(viewController))
13
+ }
@@ -0,0 +1,82 @@
1
+ module.exports = {
2
+ '/api/proj/product/list':{
3
+ get:{
4
+ query:{
5
+ type:'object',
6
+ properties:{
7
+ page:{
8
+ type:'string'
9
+ },
10
+ size:{
11
+ type:'string'
12
+ }
13
+ },
14
+ required:['page','size']
15
+ }
16
+ }
17
+ },
18
+ '/api/proj/product':{
19
+ put:{
20
+ body:{
21
+ type:'object',
22
+ properties:{
23
+ product_id:{
24
+ type:'string'
25
+ },
26
+ product_name:{
27
+ type:'string'
28
+ },
29
+ price:{
30
+ type:'number'
31
+ },
32
+ inventory:{
33
+ type:'number'
34
+ }
35
+ },
36
+ required:['product_name','product_id']
37
+ }
38
+ },
39
+ post:{
40
+ body:{
41
+ type:'object',
42
+ properties:{
43
+ product_name:{
44
+ type:'string'
45
+ },
46
+ price:{
47
+ type:'number'
48
+ },
49
+ inventory:{
50
+ type:'number'
51
+ }
52
+ },
53
+ required:['product_name']
54
+ }
55
+ },
56
+ delete:{
57
+ body:{
58
+ type:'object',
59
+ properties:{
60
+ product_id:{
61
+ type:'string'
62
+ }
63
+ },
64
+ required:['product_id']
65
+ }
66
+ },
67
+ get:{
68
+ query:{
69
+ type:'object',
70
+ properties:{
71
+ product_id:{
72
+ type:'string'
73
+ }
74
+ },
75
+ required:['product_id']
76
+ }
77
+ }
78
+ },
79
+ '/api/proj/product_enum/list':{
80
+ get:{}
81
+ }
82
+ }
@@ -0,0 +1,31 @@
1
+
2
+ module.exports = {
3
+ '/api/project':{
4
+ get:{
5
+ query:{
6
+ type:'object',
7
+ properties:{
8
+ proj_key:{
9
+ type:'string'
10
+ }
11
+ },
12
+ required:['proj_key']
13
+ }
14
+ }
15
+ },
16
+ '/api/project/list':{
17
+ get:{
18
+ query:{
19
+ type:'object',
20
+ properties:{
21
+ proj_key:{
22
+ type:'string'
23
+ }
24
+ }
25
+ }
26
+ }
27
+ },
28
+ '/api/project/model_list':{
29
+ get:{},
30
+ }
31
+ }
@@ -0,0 +1,13 @@
1
+ const superagent = require('superagent')
2
+ module.exports = (app) => class BaseService {
3
+ /**
4
+ * serveice 基类
5
+ * 统一收拢 service 曾的公共方法
6
+ */
7
+
8
+ constructor() {
9
+ this.app = app;
10
+ this.config = app.config
11
+ this.curl = superagent
12
+ }
13
+ }
@@ -0,0 +1,40 @@
1
+ module.exports = (app) => {
2
+ const BaseService = require('./base')(app)
3
+ const modelList = require('../../model/index.js')(app)
4
+ return class ProjectService extends BaseService {
5
+ /**
6
+ * 根据 proj_key 获取项目配置
7
+ */
8
+ get(projKey) {
9
+ let projConfig;
10
+ modelList.forEach(modelItem => {
11
+ if(modelItem.project[projKey]){
12
+ projConfig = modelItem.project[projKey]
13
+ }
14
+ })
15
+
16
+ return projConfig;
17
+ }
18
+ /**
19
+ * 获取统一模型下的项目列表(如果无projectKey,全量获取)
20
+ */
21
+ getList({ projKey }) {
22
+ return modelList.reduce((preList, modelItem) => {
23
+ const { project } = modelItem
24
+ if (projKey && !project[projKey]) { return preList; }
25
+ //如果有传 projKey,则去当前同模型下的项目,不传的情况则取全量
26
+ for (const pKey in project) {
27
+ preList.push(project[pKey])
28
+ }
29
+ return preList;
30
+ }, [])
31
+ }
32
+ /**
33
+ * 获取所有模型与项目的结构化数据
34
+ *
35
+ */
36
+ async getModelList() {
37
+ return modelList;
38
+ }
39
+ }
40
+ }
@@ -0,0 +1,25 @@
1
+ <!DOCTYPE html>
2
+ <html lang="zh-CN" class="dark">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <link rel="stylesheet" href="/static/normalize.css">
6
+ <link rel="icon" href="/static/logo.png" type="image/x-icon">
7
+ <title>{{name}}</title>
8
+ </head>
9
+ <body style="margin: 0;">
10
+ <div id="root"></div>
11
+ <input type="text" id="projKey" value="{{projKey}}" style="display: none;">
12
+ <input type="text" id="env" value="{{env}}" style="display: none;">
13
+ <input type="text" id="options" value="{{options}}" style="display: none;">
14
+ </body>
15
+ <script type="text/javascript">
16
+ try {
17
+ window.projKey = document.getElementById('projKey').value
18
+ window.env = document.getElementById('env').value
19
+ const options = document.getElementById('options').value
20
+ window.options = JSON.parse(options)
21
+ } catch (error) {
22
+ console.log(error);
23
+ }
24
+ </script>
25
+ </html>
@@ -0,0 +1,204 @@
1
+ const path = require('path')
2
+ const glob = require('glob')
3
+ const fs = require('fs')
4
+ const { VueLoaderPlugin } = require('vue-loader')
5
+ const webpack = require('webpack')
6
+ const HtmlWebpackPlugin = require('html-webpack-plugin')
7
+ const merge = require('webpack-merge')
8
+
9
+ //动态构造 elpisPageEntries elpisHtmlWebpackPluginList
10
+ const elpisPageEntries = {}
11
+ const elpisHtmlWebpackPluginList = []
12
+
13
+ //获取 elpis/app/pages 目录下所有的入口文件 (entry.xx.js)
14
+ const elpisEntryList = path.resolve(__dirname, '../../pages/**/entry.*.js')
15
+ glob.sync(elpisEntryList).forEach(file => {
16
+ handleFile(file, elpisPageEntries, elpisHtmlWebpackPluginList)
17
+ })
18
+
19
+ //动态构造 businessPageEntries businessHtmlWebpackPluginList
20
+ const businessPageEntries = {}
21
+ const businessHtmlWebpackPluginList = []
22
+
23
+ //获取 业务/app/pages 目录下所有的入口文件 (entry.xx.js)
24
+ const businessEntryList = path.resolve(process.cwd(), './app/pages/**/entry.*.js')
25
+ glob.sync(businessEntryList).forEach(file => {
26
+ handleFile(file, businessPageEntries, businessHtmlWebpackPluginList)
27
+ })
28
+
29
+ //构造相关 webpack 处理的数据机构
30
+ function handleFile(file, entries = {}, htmlWebpackPluginList = []) {
31
+ const entryName = path.basename(file, '.js')
32
+ //构造entry
33
+ entries[entryName] = file
34
+ //构造最终渲染的页面文件
35
+ htmlWebpackPluginList.push(
36
+ // html-webpack-plugin 辅助注入打包后的 bundle 文件到tpl 文件中
37
+ new HtmlWebpackPlugin({
38
+ //产物(最终模版)输出路径
39
+ filename: path.resolve(process.cwd(), './app/public/dist/', `${entryName}.tpl`),
40
+ //指定要使用的的模版文件
41
+ template: path.resolve(__dirname, '../../view/entry.tpl'),
42
+ //要注入的代码块
43
+ chunks: [entryName]
44
+ })
45
+ )
46
+ }
47
+ //加载业务 webpack 配置
48
+ let businessWebpackConfig = {}
49
+ try {
50
+ businessWebpackConfig = require(`${process.cwd()}/app/webpack.config.js`)
51
+ } catch (e) { }
52
+
53
+ /**
54
+ * webpack 基础配置
55
+ */
56
+ module.exports = merge.smart({
57
+ // 入口配置
58
+ entry: Object.assign({}, elpisPageEntries, businessPageEntries),
59
+ // 模块解析配置(决定了要加载那些模块,以及用什么方式去解析)
60
+ module: {
61
+ rules: [{
62
+ test: /\.vue$/,
63
+ use: {
64
+ loader: require.resolve('vue-loader')
65
+ }
66
+ },
67
+ {
68
+ test: /\.js$/,
69
+ include: [
70
+ // 处理 elpis 目录
71
+ path.resolve(__dirname, '../../pages'),
72
+ // 处理 业务 目录
73
+ path.resolve(process.cwd(), './app/pages')
74
+ ],
75
+ use: {
76
+ loader: require.resolve('babel-loader')
77
+ }
78
+ },
79
+ {
80
+ test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
81
+ use: {
82
+ loader: require.resolve('url-loader'),
83
+ options: {
84
+ limit: 8 * 1024,
85
+ esModule: false
86
+ }
87
+ }
88
+ },
89
+ {
90
+ test: /\.css$/,
91
+ use: [require.resolve('style-loader'), require.resolve('css-loader')]
92
+ },
93
+ {
94
+ test: /\.less$/,
95
+ use: [require.resolve('style-loader'), require.resolve('css-loader'), require.resolve('less-loader')]
96
+ },
97
+ {
98
+ test: /\.(eot|svg|ttf|woff|woff2)(\?\S*)?$/,
99
+ use: require.resolve('file-loader')
100
+ }]
101
+ },
102
+ //产物输出路径,因为开发和生产环境输出不一致,所以在各自环境中自行配置
103
+ output: {},
104
+ // 配置模块解析的具体行为(定义webpack 在打包时如何找到并解析具体模块的路径)
105
+ resolve: {
106
+ extensions: ['.js', '.vue', '.less', '.css'],
107
+ alias: (() => {
108
+ const aliasMap = {}
109
+ const blankModulePath = path.resolve(__dirname, '../libs/blank.js')
110
+
111
+ //dashboadr 路由扩展配置
112
+ const businessDashboardRouterConfig = path.resolve(process.cwd(), './app/pages/dashboard/router.js')
113
+ aliasMap['$businessDashboardRouterConfig'] = fs.existsSync(businessDashboardRouterConfig) ? businessDashboardRouterConfig : blankModulePath
114
+
115
+ //schema-view component 路由扩展配置
116
+ const businessComponentConfig = path.resolve(process.cwd(), './app/pages/dashboard/complex-view/schema-view/components/component-config.js')
117
+ aliasMap['$businessComponentConfig'] = fs.existsSync(businessComponentConfig) ? businessComponentConfig : blankModulePath
118
+
119
+ //schema-form 路由扩展配置
120
+ const businessFormItemConfig = path.resolve(process.cwd(), './app/pages/widgets/schema-form/form-item-config.js')
121
+ aliasMap['$businessFormItemConfig'] = fs.existsSync(businessFormItemConfig) ? businessFormItemConfig : blankModulePath
122
+
123
+ //schema-search-bar 路由扩展配置
124
+ const businessSearchItemConfig = path.resolve(process.cwd(), './app/pages/widgets/schema-search-bar/search-item-config.js')
125
+ aliasMap['$businessSearchItemConfig'] = fs.existsSync(businessSearchItemConfig) ? businessSearchItemConfig : blankModulePath
126
+
127
+ return {
128
+ 'vue': require.resolve('vue'),
129
+ '@babel/runtime/helpers/toConsumableArray': require.resolve('@babel/runtime/helpers/toConsumableArray'),
130
+ '@babel/runtime/helpers/asyncToGenerator': require.resolve('@babel/runtime/helpers/asyncToGenerator'),
131
+ '@babel/runtime/regenerator': require.resolve('@babel/runtime/regenerator'),
132
+ $elpisPages: path.resolve(__dirname, '../../pages'),
133
+ $elpisCommon: path.resolve(__dirname, '../../pages/common'),
134
+ $elpisCurl: path.resolve(__dirname, '../../pages/common/curl.js'),
135
+ $elpisUtils: path.resolve(__dirname, '../../pages/common/utils.js'),
136
+ $elpisWidgets: path.resolve(__dirname, '../../pages/widgets'),
137
+ $elpisHeaderContainer: path.resolve(__dirname, '../../pages/widgets/header-container/header-container.vue'),
138
+ $elpisSiderContainer: path.resolve(__dirname, '../../pages/widgets/sider-container/sider-container.vue'),
139
+ $elpisSchemaTable: path.resolve(__dirname, '../../pages/widgets/schema-table/schema-table.vue'),
140
+ // $elpisSchemaForm: path.resolve(__dirname, '../../pages/widgets/schema-form/schema-form.vue'),
141
+ $elpisSchemaSearchBar: path.resolve(__dirname, '../../pages/widgets/schema-search-bar/schema-search-bar.vue'),
142
+ $elpisStore: path.resolve(__dirname, '../../pages/store'),
143
+ $elpisBoot: path.resolve(__dirname, '../../pages/boot.js'),
144
+ ...aliasMap
145
+ }
146
+ })()
147
+ },
148
+ // 配置 webpack 配置
149
+ plugins: [
150
+ // 处理 .vue 文件, 这个插件是必须的
151
+ // 它的职能是讲你定义过的其他规则复制并应用到 .vue 文件里
152
+ // 例如,如果一条匹配规则 /\.js$/的规则,那么他会应用到<script> 模块中
153
+ new VueLoaderPlugin(),
154
+ //把第三方库暴露到 window context 下
155
+ new webpack.ProvidePlugin({
156
+ Vue: 'vue',
157
+ axios: 'axios',
158
+ _: 'lodash'
159
+ }),
160
+
161
+ new webpack.DefinePlugin({
162
+ __VUE_OPTIONS_API__: 'true',// 支持 vue 解析 optionsAPi
163
+ __VUE_PROD_DEVTOOLS__: 'false',// 禁用 Vue 调试工具
164
+ __VUE_PROD_HYDRATION_MISMATCH_DETAILS: 'false' //禁用生产环境显示 “水合” 信息
165
+ }),
166
+ //构造最终渲染的页面文件
167
+ ...elpisHtmlWebpackPluginList,
168
+ ...businessHtmlWebpackPluginList
169
+ ],
170
+ //配置打包输出优化(配置代码分割,模块合并,缓存,TreeShaing,压缩等优化策略)
171
+ optimization: {
172
+ /**
173
+ * 把 js 文件打包成三种类型
174
+ * 1.vendor:第三方 lib 库,基本不会改动,除非依赖版本升级
175
+ * 2.common:业务组件代码的公共部分抽取出来,改动较少
176
+ * 3.entry.{page}:不用页面 entry 里的业务组件代码的差异部分,会经常改动
177
+ * 目的:把改动和引用频率不一样的js区分出来,以到达更好利用浏览器缓存的效果
178
+ */
179
+ splitChunks: {
180
+ chunks: 'all',// 对同步和异步模块都进行分割
181
+ maxAsyncRequests: 10,//每次异步加载的最大并行请求数
182
+ maxInitialRequests: 10,//入口点的最大并行请求数
183
+ cacheGroups: {
184
+ vendor: { //第三方依赖库
185
+ test: /[\\/]node_modules[\\/]/,//打包 node_modules 中的文件
186
+ name: 'vendor',//模块名称
187
+ priority: 20,//打包优先级,数字越大,优先级越高
188
+ enforce: true,//强制执行
189
+ reuseExistingChunk: true // 复用已有的公共chunk
190
+ },
191
+ common: {
192
+ test: /[\\/]common|widgets[\\/]/,
193
+ name: 'common',//模块名称
194
+ minChunks: 2,//被几处引用即被归为公共模块(此处为2处)
195
+ minSize: 1,//最小分割文件大小(1 byte)
196
+ priority: 10,//打包优先级,数字越大,优先级越高
197
+ reuseExistingChunk: true// 复用已有的公共chunk
198
+ }
199
+ }
200
+ },
201
+ //将 webpack 运行时生成的代码打包到 runtime.js
202
+ runtimeChunk: true
203
+ }
204
+ }, businessWebpackConfig)
@@ -0,0 +1,56 @@
1
+ const path = require('path')
2
+ const merge = require('webpack-merge')
3
+ const webpack = require('webpack')
4
+ //基类配置
5
+ const baseConfig = require('./webpack.base')
6
+ //devServe 配置
7
+ const DEV_SERVER_CONFIG = {
8
+ HOST:'127.0.0.1',
9
+ PORT:9002,
10
+ HMR_PATH:'__webpack_hmr',//官方规定
11
+ TIMEOUT:20000
12
+ }
13
+
14
+ //开发阶段的entry配置需要加入 hmr
15
+ Object.keys(baseConfig.entry).forEach(v => {
16
+ //第三方库不作为hmr入口
17
+ if(v !== 'vendor'){
18
+ baseConfig.entry[v] = [
19
+ //主入口文件
20
+ baseConfig.entry[v],
21
+ //hmr 更新入口,官方指定的 hmr 路径
22
+ `${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.TIMEOUT}&reload=true`
23
+ ]
24
+ }
25
+ })
26
+
27
+ //开发环境 webpack 配置
28
+ const webpackConfig = merge.smart(baseConfig,{
29
+ //指定开发环境
30
+ mode: 'development',
31
+ // source-map开发工具,呈现代码的映射瓜系,便于在开发过程中调试代码
32
+ devtool:'eval-cheap-module-source-map',
33
+ //开发环境 output 配置
34
+ output: {
35
+ filename: 'js/[name]_[chunkhash:8].bundle.js',
36
+ path: path.join(process.cwd(), './app/public/dist/dev'),//输出文件储存路径
37
+ publicPath: `http://${DEV_SERVER_CONFIG.HOST}:${DEV_SERVER_CONFIG.PORT}/public/dist/dev`,//外部资源公共路径
38
+ globalObject:'this'
39
+ },
40
+ //开发阶段插件
41
+ plugins:[
42
+ //HotModuleReplacementPlugin用于实现热模块替换(简称:HMR)
43
+ //模块热替换允许在应用程序运行时替换模块
44
+ //极大的提升开发效率,因为能让应用一直保持允许状态
45
+ new webpack.HotModuleReplacementPlugin({
46
+ multiStep:false
47
+ })
48
+ ]
49
+ });
50
+
51
+ module.exports = {
52
+ //webpack配置
53
+ webpackConfig,
54
+ //devserver配置 暴露给 dev.js使用
55
+ DEV_SERVER_CONFIG
56
+ }
@@ -0,0 +1,116 @@
1
+ const merge = require('webpack-merge')
2
+ const path = require('path')
3
+ const os = require('os')
4
+ const HappyPack = require('happypack')
5
+ const MiniCssExtractPlugin = require('mini-css-extract-plugin')
6
+ const CleanWebpackPlugin = require('clean-webpack-plugin')
7
+ const HtmlWebpackInjectAttributesPlugin = require('html-webpack-inject-attributes-plugin')
8
+ const TerserWebpackPlugin = require('terser-webpack-plugin')
9
+ // 多线程 build 配置
10
+ const happypackCommonConfig = {
11
+ debug: false,
12
+ threadPool: HappyPack.ThreadPool({ size: os.cpus().length })
13
+ }
14
+
15
+ //基类配置
16
+ const baseConfig = require('./webpack.base')
17
+ const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')
18
+ //生产环境 webpack 配置
19
+ const webpackConfig = merge.smart(baseConfig, {
20
+ //指定生产环境
21
+ mode: 'production',
22
+ //生产环境 output 配置
23
+ output: {
24
+ filename: 'js/[name]_[chunkhash:8].bundle.js',
25
+ path: path.join(process.cwd(), './app/public/dist/prod/'),
26
+ publicPath: '/dist/prod/',
27
+ crossOriginLoading: 'anonymous'
28
+ },
29
+ module: {
30
+ rules: [{
31
+ test: /\.css$/,
32
+ use: [
33
+ MiniCssExtractPlugin.loader,
34
+ `${require.resolve('happypack/loader')}?id=css`
35
+ ]
36
+ }, {
37
+ test: /\.js$/,
38
+ include: [
39
+ // 处理 elpis 目录
40
+ path.resolve(__dirname, '../../pages'),
41
+ // 处理 业务 目录
42
+ path.resolve(process.cwd(), './app/pages')
43
+ ],
44
+ use: [`${require.resolve('happypack/loader')}?id=js`]
45
+ }
46
+ ]
47
+ },
48
+ //webpack 不会有大量 hints 信息,默认为 warning
49
+ performance: {
50
+ hints: false
51
+ },
52
+ plugins: [
53
+ //每次 build 前,清空 public/dist 目录
54
+ new CleanWebpackPlugin(['public/dist'], {
55
+ root: path.resolve(process.cwd(), './app/'),
56
+ exclude: [],
57
+ verbose: true,
58
+ dry: false
59
+ }),
60
+ //提取 css的公共部分,有效利用缓存,(非公共部分使用 inline)
61
+ new MiniCssExtractPlugin({
62
+ chunkFilename: 'css/[name]_[chunkhash:8].bundle.css'
63
+ }),
64
+ //优化并压缩CSS资源
65
+ new CssMinimizerPlugin(),
66
+ //多线程打包JS,加快打包速度
67
+ new HappyPack({
68
+ ...happypackCommonConfig,
69
+ id: 'js',
70
+ loaders: [`${require.resolve('babel-loader')}?${JSON.stringify({
71
+ presets: [require.resolve("@babel/preset-env")],
72
+ plugins: [require.resolve("@babel/plugin-transform-runtime")]
73
+ })}`]
74
+ }),
75
+ //多线程打包CSS,加快打包速度
76
+ new HappyPack({
77
+ ...happypackCommonConfig,
78
+ id: 'css',
79
+ loaders: [{
80
+ path: require.resolve('css-loader'),
81
+ options: {
82
+ importLoaders: 1
83
+ }
84
+ }]
85
+ }),
86
+ //浏览器在请求资源时不发送用户的身份凭证
87
+ new HtmlWebpackInjectAttributesPlugin({
88
+ crossorigin: 'anonymous'
89
+ })
90
+ ],
91
+ optimization: {
92
+ //使用 TerserWebpackPlugin 的并发和缓存,提升压缩阶段的性能
93
+ //清楚 console.log
94
+ minimize: true,
95
+ minimizer: [
96
+ new TerserWebpackPlugin({
97
+ // 新版不再支持 cache,直接删除
98
+ // cache: true,
99
+ parallel: true, // 并行压缩,保留这个配置
100
+ terserOptions: {
101
+ // 所有压缩选项都写在这里
102
+ compress: {
103
+ drop_console: true, // 生产环境移除 console
104
+ drop_debugger: true
105
+ },
106
+ format: {
107
+ comments: false // 移除注释
108
+ }
109
+ },
110
+ extractComments: false // 不提取注释到单独文件
111
+ })
112
+ ]
113
+ }
114
+ });
115
+
116
+ module.exports = webpackConfig
@@ -0,0 +1,52 @@
1
+ //本地开发启动的 devServe
2
+ const express = require('express')
3
+ const path = require('path')
4
+ const consoler = require('consoler')
5
+ const webpack = require('webpack')
6
+ const devMiddleware = require('webpack-dev-middleware')
7
+ const hotMiddleware = require('webpack-hot-middleware')
8
+
9
+ module.exports = () => {
10
+ //从 webpack.dev.js 获取 webpackConfig 配置 和 devServe配置
11
+ const {
12
+ webpackConfig,
13
+ DEV_SERVER_CONFIG
14
+ } = require('./config/webpack.dev')
15
+
16
+
17
+ const app = express()
18
+
19
+ const compiler = webpack(webpackConfig)
20
+ //指定静态文件目录
21
+ app.use(express.static(path.join(__dirname,'../public/dist')))
22
+ //引用devMiddleware 中间件(监控文件改动)
23
+ app.use(devMiddleware(compiler,{
24
+ //落地文件
25
+ writeToDisk:(filePath) => filePath.endsWith('.tpl'),
26
+ //资源路径
27
+ publicPath:webpackConfig.output.publicPath,
28
+ //headers 配置
29
+ headers:{
30
+ 'Access-Control-Allow-Origin':'*',
31
+ 'Access-Control-Allow-Methods':'GET,POST,PUT,DELETE,PATCH,OPTIONS',
32
+ 'Access-Control-Allow-Headers':'X-Requested-With,content-type,Authorization',
33
+ },
34
+ stats:{
35
+ colors:true
36
+ }
37
+ }))
38
+
39
+ //引用hotMiddleware 中间件(实现热更新通讯)
40
+ app.use(hotMiddleware(compiler,{
41
+ path:`/${DEV_SERVER_CONFIG.HMR_PATH}`,
42
+ log:() => {}
43
+ }))
44
+
45
+ consoler.info('请等待webpack初次构建完成提示。。。。')
46
+
47
+ //启动 devServe
48
+ const port = DEV_SERVER_CONFIG.PORT
49
+ app.listen(port,() => {
50
+ console.log(`app listening on port ${port}`);
51
+ })
52
+ }
@@ -0,0 +1 @@
1
+ module.exports = {}
@@ -0,0 +1,17 @@
1
+ const webpack = require('webpack')
2
+ const webpackProdConfig = require('./config/webpack.prod')
3
+
4
+ module.exports = () => {
5
+ console.log('\nbuilding... \n');
6
+
7
+ webpack(webpackProdConfig, (err,stats) => {
8
+ if(err) { console.log(err); return;}
9
+ process.stdout.write(`${stats.toString({
10
+ colors:true, //在控制台输出彩色信息
11
+ modules:false,//不限时每个模块的打包信息
12
+ children:false,//不显示子编译任务的信息
13
+ chunks:false,//不显示每个代码块的信息
14
+ chunkModules:true//显示代码块中模块的信息
15
+ })}\n`)
16
+ })
17
+ }
@@ -0,0 +1,3 @@
1
+ module.exports = {
2
+ name:'elpis'
3
+ }