@james-zhang/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 (86) hide show
  1. package/.eslintignore +3 -0
  2. package/.eslintrc +55 -0
  3. package/.tmp-check.js +47 -0
  4. package/README.md +287 -0
  5. package/app/controller/base.js +37 -0
  6. package/app/controller/project.js +76 -0
  7. package/app/controller/view.js +17 -0
  8. package/app/extend/logger.js +36 -0
  9. package/app/middleware/api-params-verify.js +78 -0
  10. package/app/middleware/api-sign-verify.js +31 -0
  11. package/app/middleware/error-handler.js +36 -0
  12. package/app/middleware/project-handler.js +26 -0
  13. package/app/middleware.js +69 -0
  14. package/app/pages/asserts/custom.css +10 -0
  15. package/app/pages/boot.js +44 -0
  16. package/app/pages/common/curl.js +76 -0
  17. package/app/pages/common/utils.js +2 -0
  18. package/app/pages/dashboard/complex-view/header-view/complex-view/sub-menu/sub-menu.vue +19 -0
  19. package/app/pages/dashboard/complex-view/header-view/header-view.vue +131 -0
  20. package/app/pages/dashboard/complex-view/iframe-view/iframe-view.vue +29 -0
  21. package/app/pages/dashboard/complex-view/schema-view/complex-view/search-pannel/search-pannel.vue +36 -0
  22. package/app/pages/dashboard/complex-view/schema-view/complex-view/table-pannel/table-pannel.vue +125 -0
  23. package/app/pages/dashboard/complex-view/schema-view/components/component-config.js +19 -0
  24. package/app/pages/dashboard/complex-view/schema-view/components/create-form/create-form.vue +119 -0
  25. package/app/pages/dashboard/complex-view/schema-view/components/detail-panel/detail-panel.vue +131 -0
  26. package/app/pages/dashboard/complex-view/schema-view/components/edit-form/edit-form.vue +149 -0
  27. package/app/pages/dashboard/complex-view/schema-view/hook/schema.js +126 -0
  28. package/app/pages/dashboard/complex-view/schema-view/schema-view.vue +111 -0
  29. package/app/pages/dashboard/complex-view/sider-view/complex-view/sub-menu/sub-menu.vue +28 -0
  30. package/app/pages/dashboard/complex-view/sider-view/sider-view.vue +138 -0
  31. package/app/pages/dashboard/dashboard.vue +121 -0
  32. package/app/pages/dashboard/entry.dashboard.js +52 -0
  33. package/app/pages/dashboard/router.js +3 -0
  34. package/app/pages/dashboard/todo/todo.vue +10 -0
  35. package/app/pages/store/index.js +3 -0
  36. package/app/pages/store/menu.js +71 -0
  37. package/app/pages/store/project.js +15 -0
  38. package/app/pages/widgets/header-container/asserts/avatar.png +0 -0
  39. package/app/pages/widgets/header-container/asserts/logo.png +0 -0
  40. package/app/pages/widgets/header-container/header-container.vue +118 -0
  41. package/app/pages/widgets/schema-form/complex-view/input/input.vue +165 -0
  42. package/app/pages/widgets/schema-form/complex-view/input-number/input-number.vue +164 -0
  43. package/app/pages/widgets/schema-form/complex-view/select/select.vue +138 -0
  44. package/app/pages/widgets/schema-form/form-item-config.js +20 -0
  45. package/app/pages/widgets/schema-form/schema-form.vue +154 -0
  46. package/app/pages/widgets/schema-search-bar/complex-view/date-range/date-range.vue +49 -0
  47. package/app/pages/widgets/schema-search-bar/complex-view/dynamic-select/dynamic-select.vue +65 -0
  48. package/app/pages/widgets/schema-search-bar/complex-view/input/input.vue +44 -0
  49. package/app/pages/widgets/schema-search-bar/complex-view/select/select.vue +50 -0
  50. package/app/pages/widgets/schema-search-bar/schema-search-bar.vue +134 -0
  51. package/app/pages/widgets/schema-search-bar/search-item-config.js +27 -0
  52. package/app/pages/widgets/schema-table/schema-table.vue +277 -0
  53. package/app/pages/widgets/sider-container/sider-container.vue +42 -0
  54. package/app/public/static/logo.png +0 -0
  55. package/app/public/static/normalize.css +239 -0
  56. package/app/router/project.js +7 -0
  57. package/app/router/view.js +7 -0
  58. package/app/router-schema/project.js +34 -0
  59. package/app/service/base.js +10 -0
  60. package/app/service/project.js +43 -0
  61. package/app/view/entry.tpl +31 -0
  62. package/app/webpack/config/webpack.base.js +224 -0
  63. package/app/webpack/config/webpack.dev.js +53 -0
  64. package/app/webpack/config/webpack.prod.js +104 -0
  65. package/app/webpack/dev.js +54 -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 +150 -0
  70. package/elpis-core/env.js +21 -0
  71. package/elpis-core/index.js +82 -0
  72. package/elpis-core/loader/config.js +58 -0
  73. package/elpis-core/loader/controller.js +55 -0
  74. package/elpis-core/loader/extend.js +42 -0
  75. package/elpis-core/loader/middleware.js +50 -0
  76. package/elpis-core/loader/router-schema.js +28 -0
  77. package/elpis-core/loader/router.js +42 -0
  78. package/elpis-core/loader/service.js +51 -0
  79. package/index.js +37 -0
  80. package/logs/application.log +50 -0
  81. package/logs/application.log.2026-06-13 +159 -0
  82. package/model/index.js +119 -0
  83. package/package.json +88 -0
  84. package/scripts/generate-cover.py +93 -0
  85. package/scripts/generate-diagrams.js +80 -0
  86. package/test/controller/project.test.js +218 -0
@@ -0,0 +1,7 @@
1
+ module.exports=(app,router)=>{
2
+ const { project : projectController }=app.controller
3
+ router.get('/api/project',projectController.get.bind(projectController))
4
+ router.get('/api/project/list',projectController.getList.bind(projectController))
5
+ router.get('/api/project/model_list',projectController.getModelList.bind(projectController))
6
+ }
7
+
@@ -0,0 +1,7 @@
1
+ module.exports=(app,router)=>{
2
+ const {view:ViewController}=app.controller;
3
+ //用户输入 http://ip:port/view/xxx 能渲染出对应的页面
4
+ router.get('/view/:page',ViewController.renderPage.bind(ViewController));
5
+ //用户输入 http://ip:port/view/xxx/xx/xx/* 能渲染出对应的页面
6
+ router.get('/view/:page/*',ViewController.renderPage.bind(ViewController));
7
+ }
@@ -0,0 +1,34 @@
1
+ module.exports={
2
+ '/api/project':{
3
+ get:{
4
+ query:{
5
+ type:'object',
6
+ properties:{
7
+ proj_key:{
8
+ type:'string'
9
+ }
10
+ },
11
+ required:['proj_key']
12
+ }
13
+ }
14
+ },
15
+ '/api/project/list':{
16
+ get:{
17
+ query:{
18
+ type:'object',
19
+ properties:{
20
+ proj_key:{
21
+ type:'string'
22
+ }
23
+ }
24
+ }
25
+ }
26
+ },
27
+ '/api/project/model_list':{
28
+ get:{
29
+
30
+ }
31
+ },
32
+
33
+
34
+ }
@@ -0,0 +1,10 @@
1
+ const superagent=require('superagent')
2
+ module.exports=(app)=>{
3
+ return class BaseService{
4
+ constructor(){
5
+ this.app = app
6
+ this.config = app.config
7
+ this.superagent = superagent
8
+ }
9
+ }
10
+ }
@@ -0,0 +1,43 @@
1
+ module.exports=(app)=>{
2
+ const BaseService=require('./base')(app)
3
+ const modelList=require('../../model/index')(app)
4
+ return class ProjectService extends BaseService{
5
+ /**
6
+ * 根据proj_key获取项目配置
7
+ */
8
+ async get({proj_key} ){
9
+ let projectConfig
10
+ modelList.forEach((modelItem)=>{
11
+ if(modelItem.project[proj_key]){
12
+ projectConfig=modelItem.project[proj_key]
13
+ }
14
+ })
15
+ return projectConfig
16
+ }
17
+
18
+
19
+
20
+ /**
21
+ * 获取当前projectKey 对应模型下的项目列表(如果无 projectKey 则返回所有项目)
22
+ */
23
+ async getList({projKey} ){
24
+ return modelList.reduce((preList,modelItem)=>{
25
+ const {project} = modelItem
26
+ if(projKey && !project[projKey]){
27
+ return preList
28
+ }
29
+ for(const pKey in project){
30
+ preList.push(project[pKey])
31
+ }
32
+ return preList
33
+ },[])
34
+ }
35
+
36
+ /**
37
+ * 获取项目模型与项目的结构化数据
38
+ */
39
+ async getModelList(){
40
+ return modelList
41
+ }
42
+ }
43
+ }
@@ -0,0 +1,31 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>{{name}}</title>
7
+ <link rel="icon" href="/static/logo.png" type="image/x-icon">
8
+ <link rel="stylesheet" href="/static/normalize.css">
9
+ </head>
10
+ <body>
11
+ <div id="root"></div>
12
+ <input id="projKey" type="hidden" value="{{projKey}}" />
13
+ <input id="env" type="hidden" value="{{env}}" />
14
+ <input id="options" type="hidden" data-value="{{options}}" />
15
+ </body>
16
+ <script src="https://unpkg.com/axios@1.6.7/dist/axios.min.js"></script>
17
+ <script src="https://cdn.jsdelivr.net/npm/js-md5@0.8.3/src/md5.min.js"></script>
18
+ <script type="text/javascript">
19
+ try {
20
+ const projKeyEl = document.getElementById('projKey');
21
+ const envEl = document.getElementById('env');
22
+ const optionsEl = document.getElementById('options');
23
+ if (projKeyEl) window.projKey = projKeyEl.value;
24
+ if (envEl) window.env = envEl.value;
25
+ if (optionsEl) window.options = JSON.parse(optionsEl.dataset.value);
26
+ } catch (err) {
27
+ console.log(err);
28
+ }
29
+
30
+ </script>
31
+ </html>
@@ -0,0 +1,224 @@
1
+ const path = require('path')
2
+ const glob = require('glob')
3
+ const fs = require('fs')
4
+ const {VueLoaderPlugin}=require('vue-loader')
5
+ const HtmlWebpackPlugin=require('html-webpack-plugin')
6
+ const webpack=require('webpack')
7
+ const merge = require('webpack-merge')
8
+
9
+
10
+ //动态构造elpis pageEntries和HtmlWebpackPluginList
11
+ const elpisPageEntries = {}
12
+ const elpisHtmlWebpackPluginList = []
13
+
14
+ //获取 elpis/app/pages 下的所有页面入口文件(entry.**.js)
15
+ const elpisEntryList=glob.sync(path.resolve(__dirname,'../../pages/**/entry.*.js'))
16
+ elpisEntryList.forEach((file)=>{
17
+ handleFile(file,elpisPageEntries,elpisHtmlWebpackPluginList)
18
+ })
19
+
20
+ const businessPageEntries = {}
21
+ const businessHtmlWebpackPluginList = []
22
+ //获取 business/app/pages 下的所有页面入口文件(entry.**.js)
23
+ const businessEntryList=glob.sync(path.resolve(process.cwd(),'./app/pages/**/entry.*.js'))
24
+ businessEntryList.forEach((file)=>{
25
+ handleFile(file,businessPageEntries,businessHtmlWebpackPluginList)
26
+ })
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
+ new HtmlWebpackPlugin({
37
+ //产物输出路径
38
+ filename: path.resolve(process.cwd(),'./app/public/dist/',`${entryName}.tpl`),
39
+ //指定要使用的模版文件
40
+ template: path.resolve(__dirname,'../../view/entry.tpl'),
41
+ //指定要注入的代码块
42
+ chunks:['runtime','vendor','common',entryName],
43
+ })
44
+ )
45
+ }
46
+
47
+
48
+ //加载业务 webpack基础配置
49
+ let businessWebpackConfig={}
50
+ try{
51
+ businessWebpackConfig = require(`${process.cwd()}/app/webpack.config.js`)
52
+ }catch(err){
53
+ console.error(err)
54
+ }
55
+
56
+ /*
57
+ * webpack基础配置
58
+ */
59
+ const baseConfig={
60
+ entry:Object.assign({},elpisPageEntries,businessPageEntries),
61
+
62
+ //配置输出路径,因为开发环境和生产环境的输出路径不同,所以需要自行配置
63
+ output:{},
64
+ module:{
65
+ rules:[
66
+ {
67
+ test:/\.vue$/,
68
+ use:require.resolve('vue-loader'),
69
+ },
70
+ {
71
+ test:/\.js$/,
72
+ include:[
73
+ //处理elpis目录
74
+ path.resolve(__dirname,'../../pages'),
75
+ //处理业务目录
76
+ path.resolve(process.cwd(),'./app/pages'),
77
+ ],
78
+ use:{
79
+ loader:require.resolve('babel-loader'),
80
+ },
81
+ },
82
+ {
83
+ test:/\.css$/,
84
+ use:[require.resolve('style-loader'),require.resolve('css-loader')]
85
+ },
86
+ {
87
+ test:/\.less$/,
88
+ use:[require.resolve('style-loader'),require.resolve('css-loader'),require.resolve('less-loader')]
89
+ },
90
+ {
91
+ test:/\.(png|jpe?g|gif|svg)(\?.+)?$/,
92
+ use:{
93
+ loader:require.resolve('url-loader'),
94
+ options:{
95
+ limit:300,
96
+ esModule:false
97
+ }
98
+ }
99
+ },{
100
+ test:/\.(eot|ttf|otf|woff|woff2|svg)(\?\S*)?$/,
101
+ use:require.resolve('file-loader')
102
+ }
103
+ ]
104
+ },
105
+ //配置模块解析的具体行为(定义webpack在打包时,如何找到并解析具体模块的路径)
106
+ resolve:{
107
+ //模块查找目录:优先业务项目node_modules,再找框架(node_modules,最后回退默认
108
+ modules:[
109
+ path.resolve(process.cwd(),'node_modules'),
110
+ path.resolve(__dirname,'../../../node_modules'),
111
+ 'node_modules',
112
+ ],
113
+ extensions:['.js','.vue','.css','.less'],
114
+ alias:(()=>{
115
+ const aliasMap={}
116
+ const blankModulePath=path.resolve(__dirname,'../libs/blank.js')
117
+
118
+ //dashboard 路由扩展配置
119
+ const businessDashboardRouterConfig=path.resolve(process.cwd(),'./app/pages/dashboard/router.js')
120
+ aliasMap['$businessDashboardRouterConfig']=fs.existsSync(businessDashboardRouterConfig)?businessDashboardRouterConfig:blankModulePath
121
+
122
+ //schema-view component 扩展配置
123
+ const businessSchemaViewComponentConfig=path.resolve(process.cwd(),'./app/pages/dashboard/complex-view/schema-view/components/component-config.js')
124
+ aliasMap['$businessSchemaViewComponentConfig']=fs.existsSync(businessSchemaViewComponentConfig)?businessSchemaViewComponentConfig:blankModulePath
125
+ //schema-form component 扩展配置
126
+ const businessSchemaFormItemConfig=path.resolve(process.cwd(),'./app/pages/widgets/schema-form/form-item-config.js')
127
+ aliasMap['$businessSchemaFormItemConfig']=fs.existsSync(businessSchemaFormItemConfig)?businessSchemaFormItemConfig:blankModulePath
128
+ //schema-search-bar component 扩展配置
129
+ const businessSchemaSearchItemConfig=path.resolve(process.cwd(),'./app/pages/widgets/schema-search-bar/search-item-config.js')
130
+ aliasMap['$businessSchemaSearchItemConfig']=fs.existsSync(businessSchemaSearchItemConfig)?businessSchemaSearchItemConfig:blankModulePath
131
+
132
+ return {
133
+ 'vue$':require.resolve('vue/dist/vue.esm-bundler.js'),
134
+ $elpisPages:path.resolve(__dirname,'../../pages'),
135
+ $elpisCommon:path.resolve(__dirname,'../../pages/common'),
136
+ $elpisCurl:path.resolve(__dirname,'../../pages/common/curl'),
137
+ $elpisUtils:path.resolve(__dirname,'../../pages/common/utils'),
138
+
139
+ $elpisWidgets:path.resolve(__dirname,'../../pages/widgets'),
140
+ $elpisHeaderContainer:path.resolve(__dirname,'../../pages/widgets/header-container/header-container.vue'),
141
+ $elpisSiderContainer:path.resolve(__dirname,'../../pages/widgets/sider-container/sider-container.vue'),
142
+ $elpisSchemaForm:path.resolve(__dirname,'../../pages/widgets/schema-form/schema-form.vue'),
143
+ $elpisSchemaTable:path.resolve(__dirname,'../../pages/widgets/schema-table/schema-table.vue'),
144
+ $elpisSchemaSearchBar:path.resolve(__dirname,'../../pages/widgets/schema-search-bar/schema-search-bar.vue'),
145
+
146
+ $elpisStore:path.resolve(__dirname,'../../pages/store'),
147
+ $elpisBoot:path.resolve(__dirname,'../../pages/boot.js'),
148
+ ...aliasMap,
149
+ }})()
150
+ },
151
+ plugins:[
152
+ //处理.vue文件这个插件是必须的,它能将你定义的其它规则复制并应用到.vue文件上
153
+ new VueLoaderPlugin(),
154
+
155
+ //把第三方库暴露到window context下
156
+ new webpack.ProvidePlugin({
157
+ Vue:'vue',
158
+ axios:'axios',
159
+ _:'lodash',
160
+ }),
161
+ //定义全局变量
162
+ new webpack.DefinePlugin({
163
+ __VUE_OPTIONS_API__:true, //支持vue解析o·ptionsAPI
164
+ __VUE_PROD_DEVTOOLS__:false, //关闭vue的生产环境开发工具
165
+ __VUE_PROD_HYDRATION_MISMATCH_DETAILS__:false, //禁止生产环境显示水合信息
166
+ }),
167
+
168
+ //构造最终渲染的页面模版
169
+ ...elpisHtmlWebpackPluginList,
170
+ ...businessHtmlWebpackPluginList,
171
+ ],
172
+ //配置优化行为(定义webpack在打包时,如何优化代码)
173
+ optimization:{
174
+ /**
175
+ * 把js打包成3种类型:
176
+ * 1. vendor:第三方库代码,基本不会改变,除非依赖版本升级
177
+ * 2. common:公共代码,每个页面都有,但是不会改变改变,例如utils.js
178
+ * 3. entry.{page}:不用页面entry里的业务组件代码,会经常改动
179
+ * 目的:把改动和引用频率不一样的js区分出来,以达到更好利用浏览器缓存的效果
180
+ */
181
+ splitChunks:{
182
+ chunks:'all',
183
+ maxAsyncRequests:10,//异步最大并行请求数
184
+ maxInitialRequests:10,//入口最大初始请求数
185
+ cacheGroups:{
186
+ vendor:{
187
+ test:/[\\/]node_modules[\\/]/,
188
+ name:'vendor',
189
+ priority:20,//第三方库优先级
190
+ enforce:true,//强制打包成vendor
191
+ reuseExistingChunk:true, //如果第三方库已经打包了,就直接使用
192
+ },
193
+ common:{
194
+ test:/[\\/](common|widgets)[\\/]/,
195
+ name:'common',
196
+ minChunks:2,//公共代码最小引用次数,超过2次才打包成common.js
197
+ minSize:0,//公共代码最小大小,超过1才打包成common.js
198
+ priority:10,//公共代码优先级
199
+ chunks:'all',
200
+ enforce:true,//强制打包成common
201
+ reuseExistingChunk:true, //如果公共代码已经打包了,就直接使用
202
+ },
203
+ }
204
+ },
205
+ //将webpack运行时生成代码打包到runtime.js文件中
206
+ runtimeChunk:{
207
+ name:'runtime',
208
+ },
209
+ }
210
+ }
211
+
212
+ //深度合并resolve.alias
213
+ if (businessWebpackConfig.resolve && businessWebpackConfig.resolve.alias) {
214
+ const businessAliases = businessWebpackConfig.resolve.alias
215
+ const baseAliases = baseConfig.resolve.alias
216
+ for (const key in businessAliases) {
217
+ if (!baseAliases[key]) {
218
+ baseAliases[key] = businessAliases[key]
219
+ }
220
+ }
221
+ }
222
+
223
+ module.exports = baseConfig
224
+
@@ -0,0 +1,53 @@
1
+ const path = require('path')
2
+ const merge = require('webpack-merge')
3
+ const webpack = require('webpack')
4
+
5
+ //基类配置
6
+ const baseConfig = require('./webpack.base.js')
7
+ //devServer配置
8
+ const DEV_SERVER_CONFIG = {
9
+ HOST:'127.0.0.1',
10
+ PORT: 9002,
11
+ HMR_PATH:'__webpack_hmr__',
12
+ TIMEOUT:20000,
13
+ }
14
+ //开发阶段的entry配置需要加入hmr
15
+ Object.keys(baseConfig.entry).forEach(v=>{
16
+ //第三方包不作为hmr的入口
17
+ if(v !== 'vendor'){
18
+ //主入口文件
19
+ baseConfig.entry[v]=[
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
+ //生产环境
28
+ const webpackConfig = merge(baseConfig,{
29
+ mode:'development',
30
+ //souce-map开发工具,呈现代码的映射关系,便于开发过程中调试代码
31
+ devtool:'eval-cheap-module-source-map',
32
+ output:{
33
+ filename:'js/[name].[hash:8].bundle.js',
34
+ path:path.resolve(process.cwd(),'./app/public/dist/dev/'), //输出目录
35
+ publicPath:'/public/dist/dev/', //外部资源公共路径,开发环境走主应用代理到webpack dev server,避免跨域/扩展拦截
36
+ globalObject:'this', //指定全局对象为this,避免在ie中报错
37
+ },
38
+ plugins:[
39
+ //HotModuleReplacementPlugin 热模块替换插件
40
+ //模块热替换运行应用程序运行时替换模块
41
+ //极大提升开发效率,因为能让应用程序一致保持运行状态
42
+ new webpack.HotModuleReplacementPlugin({
43
+ multiStep:true, //是否开启多步热模块替换
44
+ logTimeout:DEV_SERVER_CONFIG.TIMEOUT, //热模块替换超时时间
45
+ log:true,
46
+ }), //热模块替换插件
47
+ ],
48
+ })
49
+ module.exports = {
50
+ webpackConfig,
51
+ //devServer配置,暴露给dev.js使用
52
+ DEV_SERVER_CONFIG,
53
+ }
@@ -0,0 +1,104 @@
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 CssMinimizerPlugin = require('css-minimizer-webpack-plugin')
8
+ const HtmlWebpackInjectAttributesPlugin = require('html-webpack-inject-attributes-plugin')
9
+
10
+ //多线程build设置
11
+ const happyPackCommonConfig = {
12
+ debug:false,
13
+ threadPool:happyPack.ThreadPool({
14
+ //线程池大小
15
+ //根据cpu核心数来设置
16
+ size:os.cpus().length
17
+ })
18
+ }
19
+
20
+ //基类配置
21
+ const baseConfig = require('./webpack.base.js')
22
+
23
+ //生产环境
24
+ const webpackConfig = merge(baseConfig,{
25
+ mode:'production',
26
+ output:{
27
+ filename:'js/[name].[hash:8].bundle.js',
28
+ path:path.resolve(process.cwd(),'./app/public/dist/prod/'),
29
+ chunkFilename:'js/[id].[hash:8].bundle.js',
30
+ publicPath:'/dist/prod/',
31
+ crossOriginLoading:'anonymous' //允许跨域加载 主要通过jsonp方式
32
+ },
33
+ module:{
34
+ rules:[
35
+ {
36
+ test:/\.js$/,
37
+ include:[
38
+ //处理elpis目录
39
+ path.resolve(__dirname,'../../pages'),
40
+ //处理业务目录
41
+ path.resolve(process.cwd(),'./app/pages'),
42
+ ],
43
+ use:`${require.resolve('happypack/loader')}?id=js`,
44
+ },
45
+ {
46
+ test:/\.css$/,
47
+ exclude:/\.vue$/,
48
+ use:[
49
+ MiniCssExtractPlugin.loader,
50
+ `${require.resolve('happypack/loader')}?id=css`
51
+ ]
52
+ }
53
+ ]
54
+ },
55
+ plugins:[
56
+ //清理dist目录下的文件
57
+ new CleanWebpackPlugin(['public/dist'],{
58
+ root:path.resolve(process.cwd(),'./app/'),
59
+ exclude:[],
60
+ verbose:false, //是否在控制台输出清理信息
61
+ dry:false //是否在实际清理前先模拟清理
62
+ }),
63
+ //提取css公共部分,有效利用缓存(非公共部分使用inline)
64
+ new MiniCssExtractPlugin({
65
+ filename:'css/[name].[hash:8].css',
66
+ chunkFilename:'css/[chunkname].[hash:8].css',
67
+ }),
68
+ //优化并压缩css资源
69
+ new CssMinimizerPlugin(),
70
+ //多线程打包css,加快打包速度
71
+ new happyPack({
72
+ ...happyPackCommonConfig,
73
+ id:'css',
74
+ loaders:[{
75
+ path:require.resolve('css-loader'),
76
+ options:{
77
+ importLoaders:1, //往前执行一层loader,避免嵌套样式丢失转换逻辑
78
+ }
79
+ }],
80
+ }),
81
+ //多线程打包js,加快打包速度
82
+ new happyPack({
83
+ ...happyPackCommonConfig,
84
+ id:'js',
85
+ loaders:[{
86
+ loader:require.resolve('babel-loader'),
87
+ options:{
88
+ presets:[require.resolve('@babel/preset-env')],
89
+ plugins:[require.resolve('@babel/plugin-transform-runtime')],
90
+ }
91
+ }],
92
+ }),
93
+ //浏览器在请求资源时不发生用户身份凭证
94
+ new HtmlWebpackInjectAttributesPlugin({
95
+ crossorigin:'anonymous',
96
+ })
97
+ ],
98
+ optimization:{
99
+ //使用TerserWebpackPlugin 的并发和缓存,提升压缩阶段的性能
100
+ //清除console.log语句
101
+ minimize:true,
102
+ }
103
+ })
104
+ module.exports = webpackConfig
@@ -0,0 +1,54 @@
1
+ //本地开发启动 devServer
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和DEV_SERVER_CONFIG配置
11
+ const {webpackConfig,DEV_SERVER_CONFIG} = require('./config/webpack.dev.js')
12
+
13
+ const app = express()
14
+
15
+ const compiler = webpack(webpackConfig) //创建webpack编译器
16
+
17
+ //指定静态目录
18
+ app.use(express.static(path.resolve(process.cwd(),'./app/public')))
19
+ //引用devMiddleware中间件(监控改动)
20
+ app.use(devMiddleware(compiler,{
21
+ //落地文件到磁盘
22
+ writeToDisk:(filePath)=>{
23
+ return filePath.endsWith('.tpl')
24
+ },
25
+ //指定外部资源公共路径
26
+ publicPath:webpackConfig.output.publicPath,
27
+ //headers配置
28
+ headers:{
29
+ 'Access-Control-Allow-Origin':'*',
30
+ 'Access-Control-Allow-Methods':'GET,POST,PUT,DELETE,OPTIONS',
31
+ 'Access-Control-Allow-Headers':'X-Requested-With,Content-Type,Authorization',
32
+ },
33
+ //stats配置,指定输出的统计信息
34
+ stats:{
35
+ colors:true,//打印日志有颜色
36
+ },
37
+ }))
38
+ //引用hotMiddleware中间件(热模块替换)
39
+ app.use(hotMiddleware(compiler,{
40
+ path:`/${DEV_SERVER_CONFIG.HMR_PATH}`,
41
+ log:(data)=>{
42
+ consoler.info(data)
43
+ }
44
+ }))
45
+
46
+ consoler.info(`devServer is running at http://${DEV_SERVER_CONFIG.HOST}:${DEV_SERVER_CONFIG.PORT}`)
47
+
48
+ //启动devServer
49
+ const PORT = DEV_SERVER_CONFIG.PORT
50
+ app.listen(PORT,()=>{
51
+ consoler.info(`devServer is running at http://${DEV_SERVER_CONFIG.HOST}:${PORT}`)
52
+ })
53
+ }
54
+
@@ -0,0 +1 @@
1
+ module.exports={}
@@ -0,0 +1,17 @@
1
+ const webpack=require('webpack')
2
+ const webpaceProdConfig=require('./config/webpack.prod.js')
3
+
4
+ module.exports=()=>{
5
+ console.log('\nbuilding ...\n')
6
+
7
+ webpack(webpaceProdConfig,(err,stats)=>{
8
+ if(err) console.log(err)
9
+ process.stdout.write(`${stats.toString({
10
+ colors:true, //在控制台输出色彩信息
11
+ modules:false, //是否输出模块信息
12
+ children:false, //是否输出子编译人物信息
13
+ chunks:false, //是否输出每个代码块信息(false即为看成一个大的代码块)
14
+ chunkModules:true //是否输出每个代码块中的模块信息
15
+ })}\n`)
16
+ })
17
+ }
@@ -0,0 +1,3 @@
1
+ module.exports={
2
+ name:'elpis-learning',
3
+ }