@pixel-shell/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.
- package/.eslintgnore +1 -0
- package/.eslintrc +55 -0
- package/README.md +194 -0
- package/app/controller/base.js +40 -0
- package/app/controller/project.js +56 -0
- package/app/controller/view.js +18 -0
- package/app/extend/logger.js +37 -0
- package/app/middleware/api-params-verify.js +71 -0
- package/app/middleware/api-sign-verify.js +32 -0
- package/app/middleware/error-handler.js +33 -0
- package/app/middleware/project-handler.js +27 -0
- package/app/middleware.js +31 -0
- package/app/pages/asserts/custom.css +12 -0
- package/app/pages/boot.js +47 -0
- package/app/pages/common/curl.js +88 -0
- package/app/pages/common/utils.js +2 -0
- package/app/pages/dashboard/complex-view/header-view/complex-view/sub-menu/sub-menu.vue +17 -0
- package/app/pages/dashboard/complex-view/header-view/header-view.vue +129 -0
- package/app/pages/dashboard/complex-view/iframe-view/iframe-view.vue +43 -0
- package/app/pages/dashboard/complex-view/schema-view/complex-view/search-panel/search-panel.vue +37 -0
- package/app/pages/dashboard/complex-view/schema-view/complex-view/table-panel/table-panel.vue +114 -0
- package/app/pages/dashboard/complex-view/schema-view/components/component-config.js +22 -0
- package/app/pages/dashboard/complex-view/schema-view/components/create-form/create-form.vue +85 -0
- package/app/pages/dashboard/complex-view/schema-view/components/detail-panel/detail-panel.vue +92 -0
- package/app/pages/dashboard/complex-view/schema-view/components/edit-form/edit-form.vue +106 -0
- package/app/pages/dashboard/complex-view/schema-view/hook/schema.js +123 -0
- package/app/pages/dashboard/complex-view/schema-view/schema-view.vue +88 -0
- package/app/pages/dashboard/complex-view/sider-view/complex-view/sub-menu/sub-menu.vue +18 -0
- package/app/pages/dashboard/complex-view/sider-view/sider-view.vue +117 -0
- package/app/pages/dashboard/dashboard.vue +89 -0
- package/app/pages/dashboard/entry.dashboard.js +42 -0
- package/app/pages/store/index.js +5 -0
- package/app/pages/store/menu.js +57 -0
- package/app/pages/store/project.js +15 -0
- package/app/pages/widgets/header-container/asserts/avatar.png +0 -0
- package/app/pages/widgets/header-container/asserts/logo.png +0 -0
- package/app/pages/widgets/header-container/header-container.vue +102 -0
- package/app/pages/widgets/schema-form/complex-view/input/input.vue +129 -0
- package/app/pages/widgets/schema-form/complex-view/input-number/input-number.vue +130 -0
- package/app/pages/widgets/schema-form/complex-view/select/select.vue +116 -0
- package/app/pages/widgets/schema-form/form-item-config.js +23 -0
- package/app/pages/widgets/schema-form/schema-form.vue +121 -0
- package/app/pages/widgets/schema-search-bar/complex-view/date-range/date-range.vue +41 -0
- package/app/pages/widgets/schema-search-bar/complex-view/dynamic-select/dynamic-select.vue +51 -0
- package/app/pages/widgets/schema-search-bar/complex-view/input/input.vue +34 -0
- package/app/pages/widgets/schema-search-bar/complex-view/select/select.vue +36 -0
- package/app/pages/widgets/schema-search-bar/schema-search-bar.vue +121 -0
- package/app/pages/widgets/schema-search-bar/search-item-config.js +27 -0
- package/app/pages/widgets/schema-table/schema-table.vue +227 -0
- package/app/pages/widgets/sider-container/sider-container.vue +29 -0
- package/app/public/static/logo.png +0 -0
- package/app/public/static/normalize.css +241 -0
- package/app/router/project.js +6 -0
- package/app/router/view.js +8 -0
- package/app/router-schema/project.js +30 -0
- package/app/service/base.js +10 -0
- package/app/service/project.js +40 -0
- package/app/view/entry.tpl +25 -0
- package/app/webpack/build.js +18 -0
- package/app/webpack/config/webpack.base.js +234 -0
- package/app/webpack/config/webpack.dev.js +58 -0
- package/app/webpack/config/webpack.prod.js +113 -0
- package/app/webpack/dev.js +60 -0
- package/app/webpack/libs/blank.js +1 -0
- package/app/webpack/prod.js +22 -0
- package/config/config.default.js +3 -0
- package/docs/dashboard-mode.js +141 -0
- package/elpis-core/env.js +16 -0
- package/elpis-core/index.js +70 -0
- package/elpis-core/loader/config.js +51 -0
- package/elpis-core/loader/controller.js +71 -0
- package/elpis-core/loader/extend.js +61 -0
- package/elpis-core/loader/middleware.js +69 -0
- package/elpis-core/loader/roter-schema.js +54 -0
- package/elpis-core/loader/router.js +42 -0
- package/elpis-core/loader/service.js +70 -0
- package/index.js +35 -0
- package/model/index.js +86 -0
- package/package.json +92 -0
- package/test/controller/project.test.js +194 -0
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
module.exports = (app, router) => {
|
|
2
|
+
const {project: projectController} = app.controller;
|
|
3
|
+
router.get('/api/project/model_list', projectController.getModelList.bind(projectController));
|
|
4
|
+
router.get('/api/project/list', projectController.getProjectList.bind(projectController));
|
|
5
|
+
router.get('/api/project', projectController.getProjectConfig.bind(projectController));
|
|
6
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
module.exports = (app, router) => {
|
|
2
|
+
const {view: viewController} = app.controller;
|
|
3
|
+
|
|
4
|
+
// 当用户输入 http://IP:port/view/xxx 能渲染出对应页面
|
|
5
|
+
router.get('/view/:page', viewController.renderPage.bind(viewController));
|
|
6
|
+
// 当用户输入 http://IP:port/view/xxx/xxx/xxx/* 能渲染出对应页面
|
|
7
|
+
router.get('/view/:page/*', viewController.renderPage.bind(viewController));
|
|
8
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
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
|
+
};
|
|
@@ -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
|
+
* 获取所有模型与项目的结构化数据
|
|
7
|
+
*/
|
|
8
|
+
async getModelList() {
|
|
9
|
+
return modelList;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* 获取指定projKey下的项目列表(如果没有传projKey则全量获取)
|
|
13
|
+
*/
|
|
14
|
+
async getProjectList(projKey) {
|
|
15
|
+
return modelList.reduce((preList, modelItem) => {
|
|
16
|
+
const { project } = modelItem;
|
|
17
|
+
// 如果有传 projKey 则只去当前同模型下的项目,不传的情况下则取全量
|
|
18
|
+
if (projKey && !project[projKey]) {
|
|
19
|
+
return preList;
|
|
20
|
+
}
|
|
21
|
+
for (const key in project) {
|
|
22
|
+
preList.push(project[key]);
|
|
23
|
+
}
|
|
24
|
+
return preList;
|
|
25
|
+
}, []);
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* 获取指定projKey下的项目配置
|
|
29
|
+
*/
|
|
30
|
+
async getProjectConfig(projKey) {
|
|
31
|
+
let projConfig;
|
|
32
|
+
modelList.forEach(modelItem => {
|
|
33
|
+
if (modelItem.project[projKey]) {
|
|
34
|
+
projConfig = modelItem.project[projKey];
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
return projConfig;
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html class="dark">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<link rel="stylesheet" href="/static/normalize.css">
|
|
6
|
+
<link rel="icon" type="image/x-icon" href="/static/logo.png">
|
|
7
|
+
<title>{{ name }}</title>
|
|
8
|
+
</head>
|
|
9
|
+
<body style="margin: 0;">
|
|
10
|
+
<div id="root"></div>
|
|
11
|
+
<input id="projKey" value="{{ projKey }}" style="display: none;">
|
|
12
|
+
<input id="env" value="{{ env }}" style="display: none;">
|
|
13
|
+
<input 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,18 @@
|
|
|
1
|
+
const webpack = require("webpack");
|
|
2
|
+
const webBassConfig = require("./config/webpack.base.js");
|
|
3
|
+
|
|
4
|
+
console.log('\nbuilding... \n');
|
|
5
|
+
|
|
6
|
+
webpack(webBassConfig, (err, stats) => {
|
|
7
|
+
if(err){
|
|
8
|
+
console.log(err);
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
process.stdout.write(`${stats.toString({
|
|
12
|
+
colors: true, //在控制台输出色彩信息
|
|
13
|
+
modules: false, // 不显示每个模块的打包信息
|
|
14
|
+
children: false, // 不显示子编译任务的信息
|
|
15
|
+
chunks: false, // 不显示每个子代码块信息
|
|
16
|
+
chunkModules: true // 显示代码块块中模块的信息
|
|
17
|
+
})}\n`);
|
|
18
|
+
});
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
const path = require("path");
|
|
2
|
+
const glob = require("glob");
|
|
3
|
+
const fs = require("fs");
|
|
4
|
+
const webpack = require("webpack");
|
|
5
|
+
const merge = require("webpack-merge");
|
|
6
|
+
const { VueLoaderPlugin } = require("vue-loader");
|
|
7
|
+
const HtmlWebpackPlugin = require("html-webpack-plugin");
|
|
8
|
+
|
|
9
|
+
// 动态构造 elpisPageEntries elpisHtmlWebpackPluginList
|
|
10
|
+
const elpisPageEntries = {};
|
|
11
|
+
const elpisHtmlWebpackPluginList = [];
|
|
12
|
+
// 获取elpis/app/pages目录下所有入口文件
|
|
13
|
+
const elpisEntryList = path.resolve(__dirname, "../../pages/**/entry.*.js");
|
|
14
|
+
glob.sync(elpisEntryList).forEach((file) => {
|
|
15
|
+
handleFile(file, elpisPageEntries, elpisHtmlWebpackPluginList);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
// 动态构造 businessPageEntries businessHtmlWebpackPluginList
|
|
19
|
+
const businessPageEntries = {};
|
|
20
|
+
const businessHtmlWebpackPluginList = [];
|
|
21
|
+
// 获取elpis/app/pages目录下所有入口文件
|
|
22
|
+
const businessEntryList = path.resolve(
|
|
23
|
+
process.cwd(),
|
|
24
|
+
"./app/pages/**/entry.*.js",
|
|
25
|
+
);
|
|
26
|
+
glob.sync(businessEntryList).forEach((file) => {
|
|
27
|
+
handleFile(file, businessPageEntries, businessHtmlWebpackPluginList);
|
|
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(
|
|
39
|
+
process.cwd(),
|
|
40
|
+
"./app/public/dist/",
|
|
41
|
+
`${entryName}.tpl`,
|
|
42
|
+
),
|
|
43
|
+
// 指定要使用的模板文件
|
|
44
|
+
template: path.resolve(__dirname, "../../view/entry.tpl"),
|
|
45
|
+
// 要注入的代码块
|
|
46
|
+
chunks: [entryName],
|
|
47
|
+
}),
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
// 加载业务 webpack 配置
|
|
51
|
+
let buinessWebpackConfig = {};
|
|
52
|
+
try {
|
|
53
|
+
buinessWebpackConfig = require(`${process.cwd()}/app/webpack.config.js`);
|
|
54
|
+
} catch (e) {}
|
|
55
|
+
/**
|
|
56
|
+
* webpack基础配置
|
|
57
|
+
*/
|
|
58
|
+
module.exports = merge.smart(
|
|
59
|
+
{
|
|
60
|
+
// 入口配置
|
|
61
|
+
entry: Object.assign({}, elpisPageEntries, businessPageEntries),
|
|
62
|
+
// 模块解析配置(决定了要加载解析哪些模块,以及用什么方式去解析)
|
|
63
|
+
module: {
|
|
64
|
+
rules: [
|
|
65
|
+
{
|
|
66
|
+
test: /\.vue$/,
|
|
67
|
+
use: {
|
|
68
|
+
loader: require.resolve("vue-loader"),
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
test: /\.js$/,
|
|
73
|
+
include: [
|
|
74
|
+
// 处理elpis 目录
|
|
75
|
+
path.resolve(__dirname, "../../pages"),
|
|
76
|
+
// 处理业务目录
|
|
77
|
+
path.resolve(process.cwd(), "./app/pages"),
|
|
78
|
+
],
|
|
79
|
+
use: {
|
|
80
|
+
loader: require.resolve("babel-loader"),
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
test: /\.(png|jpg|gif|svg)(\?.*)?$/,
|
|
85
|
+
use: {
|
|
86
|
+
loader: require.resolve("url-loader"),
|
|
87
|
+
options: {
|
|
88
|
+
limit: 300,
|
|
89
|
+
esModule: false,
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
test: /\.less$/,
|
|
95
|
+
use: [
|
|
96
|
+
require.resolve("style-loader"),
|
|
97
|
+
require.resolve("css-loader"),
|
|
98
|
+
require.resolve("less-loader"),
|
|
99
|
+
],
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
test: /\.css$/,
|
|
103
|
+
use: [require.resolve("style-loader"), require.resolve("css-loader")],
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
test: /\.(woff|woff2|eot|ttf|otf)(\?\S*)?$/,
|
|
107
|
+
use: require.resolve("file-loader"),
|
|
108
|
+
},
|
|
109
|
+
],
|
|
110
|
+
},
|
|
111
|
+
// 产物输出路径
|
|
112
|
+
output: {
|
|
113
|
+
filename: "js/[name]_[chunkhash:8].bundle.js",
|
|
114
|
+
path: path.join(process.cwd(), "./app/public/dist/prod"),
|
|
115
|
+
publicPath: "/dist/prod",
|
|
116
|
+
crossOriginLoading: "anonymous",
|
|
117
|
+
},
|
|
118
|
+
// 配置模块解析的具体行为(定义 webpack 再打包时,如何找到并解析具体模块的路径)
|
|
119
|
+
resolve: {
|
|
120
|
+
extensions: [".js", ".vue", ".less", ".css"],
|
|
121
|
+
alias: (() => {
|
|
122
|
+
const aliasMap = {};
|
|
123
|
+
const blankModulePath = path.resolve(__dirname, "../libs/blank.js");
|
|
124
|
+
// dashboard 路由扩展配置
|
|
125
|
+
const businessDashboardRouterConfig = path.resolve(process.cwd(), "./app/pages/dashboard/router.js");
|
|
126
|
+
aliasMap["$businessDashboardRouterConfig"] = fs.existsSync(businessDashboardRouterConfig) ? businessDashboardRouterConfig : blankModulePath;
|
|
127
|
+
|
|
128
|
+
// schema-view component 扩展配置
|
|
129
|
+
const businessSchemaViewConfig = path.resolve(process.cwd(), "./app/pages/dashboard/complex-view/schema-view/components/component-config.js");
|
|
130
|
+
aliasMap["$businessSchemaViewConfig"] = fs.existsSync(businessSchemaViewConfig) ? businessSchemaViewConfig : blankModulePath;
|
|
131
|
+
|
|
132
|
+
// schema-view 扩展配置
|
|
133
|
+
const businessFormItemConfig = path.resolve(process.cwd(), "./app/pages/widgets/schema-form/form-item-config.js");
|
|
134
|
+
aliasMap["$businessFormItemConfig"] = fs.existsSync(businessFormItemConfig) ? businessFormItemConfig : blankModulePath;
|
|
135
|
+
|
|
136
|
+
// schema-search-bar 扩展配置
|
|
137
|
+
const businessSearchItemConfig = path.resolve(process.cwd(), "./app/pages/widgets/schema-search-bar/search-item-config.js");
|
|
138
|
+
aliasMap["$businessSearchItemConfig"] = fs.existsSync(businessSearchItemConfig) ? businessSearchItemConfig : blankModulePath;
|
|
139
|
+
return {
|
|
140
|
+
vue: require.resolve("vue"),
|
|
141
|
+
"@babel/runtime/helpers/toConsumableArray":
|
|
142
|
+
require.resolve("@babel/runtime/helpers/esm/toConsumableArray"),
|
|
143
|
+
"@babel/runtime/helpers/asyncToGenerator":
|
|
144
|
+
require.resolve("@babel/runtime/helpers/esm/asyncToGenerator"),
|
|
145
|
+
"@babel/runtime/regenerator":
|
|
146
|
+
require.resolve("@babel/runtime/regenerator"),
|
|
147
|
+
$elpisPages: path.resolve(__dirname, "../../pages"),
|
|
148
|
+
$elpisCommon: path.resolve(__dirname, "../../pages/common"),
|
|
149
|
+
$elpisCurl: path.resolve(__dirname, "../../pages/common/curl.js"),
|
|
150
|
+
$elpisUtils: path.resolve(__dirname, "../../pages/common/utils.js"),
|
|
151
|
+
$elpisWidgets: path.resolve(__dirname, "../../pages/widgets"),
|
|
152
|
+
$elpisHeaderContainer: path.resolve(
|
|
153
|
+
__dirname,
|
|
154
|
+
"../../pages/widgets/header-container/header-container.vue",
|
|
155
|
+
),
|
|
156
|
+
$elpisSchemaForm: path.resolve(
|
|
157
|
+
__dirname,
|
|
158
|
+
"../../pages/widgets/schema-form/schema-form.vue",
|
|
159
|
+
),
|
|
160
|
+
$elpisSchemaSearchBar: path.resolve(
|
|
161
|
+
__dirname,
|
|
162
|
+
"../../pages/widgets/schema-search-bar/schema-search-bar.vue",
|
|
163
|
+
),
|
|
164
|
+
$elpisSchemaTable: path.resolve(
|
|
165
|
+
__dirname,
|
|
166
|
+
"../../pages/widgets/schema-table/schema-table.vue",
|
|
167
|
+
),
|
|
168
|
+
$elpisSiderContainer: path.resolve(
|
|
169
|
+
__dirname,
|
|
170
|
+
"../../pages/widgets/sider-container/sider-container.vue",
|
|
171
|
+
),
|
|
172
|
+
$elpisStore: path.resolve(__dirname, "../../pages/store"),
|
|
173
|
+
$elpisBoot: path.resolve(__dirname, "../../pages/boot.js"),
|
|
174
|
+
...aliasMap,
|
|
175
|
+
};
|
|
176
|
+
})(),
|
|
177
|
+
},
|
|
178
|
+
// 配置 webpack 插件
|
|
179
|
+
plugins: [
|
|
180
|
+
// 处理 .vue 文件,这个插件是必须的
|
|
181
|
+
// 它的只能是将你定义过的其他规则复制并应用到.vue文件中
|
|
182
|
+
// 例如,如果有一条匹配规则是\.js$/,,那么你定义过的其他规则也会应用到.vue文件中的<script>块
|
|
183
|
+
new VueLoaderPlugin(),
|
|
184
|
+
// 把第三方库宝库到window context下
|
|
185
|
+
new webpack.ProvidePlugin({
|
|
186
|
+
Vue: "vue",
|
|
187
|
+
}),
|
|
188
|
+
// 定义全局常量
|
|
189
|
+
new webpack.DefinePlugin({
|
|
190
|
+
__VUE_OPTIONS_API__: "true", //支持 vue 解析 optionsApi
|
|
191
|
+
__VUE_PROD_DEVTOOLS__: "false", //禁用 VUE 调试工具
|
|
192
|
+
__VUE_PROD_HYDRATION_MISMATCH_DETAILS__: "false", //禁用生产环境显示 “水合” 信息
|
|
193
|
+
}),
|
|
194
|
+
// 构造最终渲染的页面模板
|
|
195
|
+
...elpisHtmlWebpackPluginList,
|
|
196
|
+
...businessHtmlWebpackPluginList,
|
|
197
|
+
],
|
|
198
|
+
// 配置打包输出优化(代码分割, 压缩, 合并, 缓存, TreeShaing等优化策略)
|
|
199
|
+
optimization: {
|
|
200
|
+
/**
|
|
201
|
+
* 把 js 文件打包成3中类型
|
|
202
|
+
* 1. vendor: 第三方库,基本不会改动,除非依赖版本升级
|
|
203
|
+
* 2. common: 公共代码,如全局组件、全局样式等,改动较少
|
|
204
|
+
* 3. entry.{page}: 不用页面 entry 里的业务组件代码的差异部分,会经常改动
|
|
205
|
+
* 目的:把改动和引用频率不一样的 js 区分出来,以达到更好利用浏览器缓存的效果
|
|
206
|
+
*/
|
|
207
|
+
splitChunks: {
|
|
208
|
+
chunks: "all", // 对同步和异步模块都进行分割
|
|
209
|
+
maxAsyncRequests: 5, // 每次异步加载的最大并行请求数
|
|
210
|
+
maxInitialRequests: 5, // 每个入口并行加载的最大并行请求数
|
|
211
|
+
cacheGroups: {
|
|
212
|
+
vendor: {
|
|
213
|
+
// 第三方库
|
|
214
|
+
test: /[\\/]node_modules[\\/]/, // 匹配 node_modules 目录下的模块
|
|
215
|
+
name: "vendor", // 模块名称
|
|
216
|
+
priority: 20, // 优先级,数值越大优先级越高
|
|
217
|
+
enforce: true, // 强制分割,不考虑其他规则
|
|
218
|
+
reuseExistingChunk: true, // 重用已存在的 chunk,避免重复打包
|
|
219
|
+
},
|
|
220
|
+
common: {
|
|
221
|
+
// 公共代码
|
|
222
|
+
test: /[\\/]common|widgets[\\/]/, // 匹配 common 目录下的模块
|
|
223
|
+
name: "common", // 模块名称
|
|
224
|
+
priority: 10, // 优先级,数值越大优先级越高
|
|
225
|
+
minChunks: 2, // 最小引用次数
|
|
226
|
+
minSize: 1, // 最小大小,单位字节,默认 0
|
|
227
|
+
reuseExistingChunk: true, // 重用已存在的 chunk,避免重复打包
|
|
228
|
+
},
|
|
229
|
+
},
|
|
230
|
+
},
|
|
231
|
+
},
|
|
232
|
+
},
|
|
233
|
+
buinessWebpackConfig,
|
|
234
|
+
);
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
const merge = require("webpack-merge");
|
|
2
|
+
const path = require("path");
|
|
3
|
+
const webpack = require("webpack");
|
|
4
|
+
|
|
5
|
+
// 基类配置
|
|
6
|
+
const baseConfig = require("./webpack.base.js");
|
|
7
|
+
|
|
8
|
+
// dev-server 配置
|
|
9
|
+
const DEV_SERVER_CONFIG = {
|
|
10
|
+
HOST: "127.0.0.1",
|
|
11
|
+
PORT: 9002,
|
|
12
|
+
HMR_PATH: "/__webpack_hmr",
|
|
13
|
+
TIMEOUT: 30000,
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
// 开发阶段的entry 配置需要加入hmr
|
|
17
|
+
Object.keys(baseConfig.entry).forEach((v) => {
|
|
18
|
+
// 第三方包不作为 hmr 入口
|
|
19
|
+
if( v!=="vendor") {
|
|
20
|
+
baseConfig.entry[v] = [
|
|
21
|
+
// 主入口文件
|
|
22
|
+
baseConfig.entry[v],
|
|
23
|
+
// hmr 更新入口,官方制定的hmr路径
|
|
24
|
+
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`,
|
|
25
|
+
];
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
// 开发环境配置
|
|
30
|
+
const webpackConfig = merge.smart(baseConfig, {
|
|
31
|
+
// 指定开发环境
|
|
32
|
+
mode: "development",
|
|
33
|
+
// 配置source-map ,方便调试
|
|
34
|
+
devtool: "inline-source-map",
|
|
35
|
+
// 开发环境下的输出配置
|
|
36
|
+
output: {
|
|
37
|
+
filename: "js/[name]_[chunkhash:8].bundle.js",
|
|
38
|
+
path: path.resolve(process.cwd(), "./app/public/dist/dev/"), // 输出文件存储路径
|
|
39
|
+
publicPath: `http://${DEV_SERVER_CONFIG.HOST}:${DEV_SERVER_CONFIG.PORT}/public/dist/dev/`, // 外部资源公共路径
|
|
40
|
+
globalObject: "this",
|
|
41
|
+
},
|
|
42
|
+
// 开发阶段插件
|
|
43
|
+
plugins: [
|
|
44
|
+
// 用户实现热模块替换(HMR)
|
|
45
|
+
// 模块热替换允许在应用程序运行时替换模块,而无需刷新整个页面
|
|
46
|
+
// 这在开发过程中非常有用,因为可以快速迭代和测试代码,而无需刷新页面,极大提升开发效率
|
|
47
|
+
new webpack.HotModuleReplacementPlugin({
|
|
48
|
+
multiStep: false,
|
|
49
|
+
}),
|
|
50
|
+
]
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
module.exports = {
|
|
54
|
+
// webpack配置
|
|
55
|
+
webpackConfig,
|
|
56
|
+
// dev-server配置
|
|
57
|
+
DEV_SERVER_CONFIG,
|
|
58
|
+
};
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
const path = require("path");
|
|
2
|
+
const merge = require("webpack-merge");
|
|
3
|
+
const os = require("os");
|
|
4
|
+
const HappyPack = require("happypack"); // 多进程打包
|
|
5
|
+
const MiniCssExtractPlugin = require("mini-css-extract-plugin"); // css提取
|
|
6
|
+
const CleanWebpackPlugin = require("clean-webpack-plugin");
|
|
7
|
+
const CSSMinimizerPlugin = require("css-minimizer-webpack-plugin"); // css压缩
|
|
8
|
+
const HtmlWebpackInjectAttributesPlugin = require("html-webpack-inject-attributes-plugin");
|
|
9
|
+
const TerserWebpackPlugin = require("terser-webpack-plugin"); // js压缩
|
|
10
|
+
|
|
11
|
+
// 多线程build设置
|
|
12
|
+
const happypackCommonConfig = {
|
|
13
|
+
debug: true,
|
|
14
|
+
threadPool: HappyPack.ThreadPool({ size: os.cpus().length }),
|
|
15
|
+
};
|
|
16
|
+
// 基类配置
|
|
17
|
+
const baseConfig = require("./webpack.base.js");
|
|
18
|
+
|
|
19
|
+
// 生产环境配置
|
|
20
|
+
const webpackConfig = merge.smart(baseConfig, {
|
|
21
|
+
// 指定生产环境
|
|
22
|
+
mode: "production",
|
|
23
|
+
// 生产环境下的输出配置
|
|
24
|
+
output: {
|
|
25
|
+
filename: "js/[name]_[chunkhash:8].bundle.js",
|
|
26
|
+
path: path.join(process.cwd(), "./app/public/dist/prod/"),
|
|
27
|
+
publicPath: "/dist/prod/",
|
|
28
|
+
crossOriginLoading: "anonymous",
|
|
29
|
+
},
|
|
30
|
+
module: {
|
|
31
|
+
rules: [
|
|
32
|
+
{
|
|
33
|
+
test: /\.css$/,
|
|
34
|
+
use: [
|
|
35
|
+
MiniCssExtractPlugin.loader,
|
|
36
|
+
`${require.resolve("happypack/loader")}?id=css`,
|
|
37
|
+
],
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
test: /\.js$/,
|
|
41
|
+
include: [
|
|
42
|
+
// 处理elpis 目录
|
|
43
|
+
path.resolve(__dirname, "../../pages"),
|
|
44
|
+
// 处理业务目录
|
|
45
|
+
path.resolve(process.cwd(), "./app/pages"),
|
|
46
|
+
],
|
|
47
|
+
use: [`${require.resolve("happypack/loader")}?id=js`],
|
|
48
|
+
},
|
|
49
|
+
],
|
|
50
|
+
},
|
|
51
|
+
performance: {
|
|
52
|
+
hints: false,
|
|
53
|
+
},
|
|
54
|
+
plugins: [
|
|
55
|
+
// 删除dist目录
|
|
56
|
+
new CleanWebpackPlugin(["public/dist"], {
|
|
57
|
+
root: path.resolve(process.cwd(), "./app/"),
|
|
58
|
+
exclude: ["public/dist/"],
|
|
59
|
+
verbose: true,
|
|
60
|
+
dry: false,
|
|
61
|
+
}),
|
|
62
|
+
// 提取css
|
|
63
|
+
new MiniCssExtractPlugin({
|
|
64
|
+
chunkFilename: "css/[name]_[chunkhash:8].bundle.css",
|
|
65
|
+
}),
|
|
66
|
+
// 压缩css
|
|
67
|
+
new CSSMinimizerPlugin(),
|
|
68
|
+
// 多进程打包js
|
|
69
|
+
new HappyPack({
|
|
70
|
+
...happypackCommonConfig,
|
|
71
|
+
id: "js",
|
|
72
|
+
loaders: [
|
|
73
|
+
`${require.resolve("babel-loader")}?${JSON.stringify({
|
|
74
|
+
presets: [require.resolve("@babel/preset-env")],
|
|
75
|
+
plugins: [require.resolve("@babel/plugin-transform-runtime")],
|
|
76
|
+
})}`,
|
|
77
|
+
],
|
|
78
|
+
}),
|
|
79
|
+
// 多进程打包css
|
|
80
|
+
new HappyPack({
|
|
81
|
+
...happypackCommonConfig,
|
|
82
|
+
id: "css",
|
|
83
|
+
loaders: [
|
|
84
|
+
{
|
|
85
|
+
loader: require.resolve("css-loader"),
|
|
86
|
+
options: {
|
|
87
|
+
importLoaders: 1,
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
],
|
|
91
|
+
}),
|
|
92
|
+
// 浏览器在请求资源时不发送用户的身份凭证
|
|
93
|
+
new HtmlWebpackInjectAttributesPlugin({
|
|
94
|
+
crossorigin: "anonymous",
|
|
95
|
+
}),
|
|
96
|
+
],
|
|
97
|
+
optimization: {
|
|
98
|
+
minimize: true,
|
|
99
|
+
minimizer: [
|
|
100
|
+
new TerserWebpackPlugin({
|
|
101
|
+
// cache: true, // 开启缓存
|
|
102
|
+
parallel: true, // 开启多进程并行压缩,提高构建速度
|
|
103
|
+
minimizerOptions: {
|
|
104
|
+
compress: {
|
|
105
|
+
drop_console: true, // 去除console.log等语句
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
}),
|
|
109
|
+
],
|
|
110
|
+
},
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
module.exports = webpackConfig;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// 本地开发环境配置
|
|
2
|
+
const express = require("express");
|
|
3
|
+
const path = require("path");
|
|
4
|
+
const consoler = require("consoler");
|
|
5
|
+
const webpack = require("webpack");
|
|
6
|
+
const divMiddleware = require("webpack-dev-middleware");
|
|
7
|
+
const hotMiddleware = require("webpack-hot-middleware");
|
|
8
|
+
|
|
9
|
+
module.exports = () => {
|
|
10
|
+
// 配置webpack-dev-middleware
|
|
11
|
+
const {
|
|
12
|
+
webpackConfig,
|
|
13
|
+
DEV_SERVER_CONFIG,
|
|
14
|
+
} = require("./config/webpack.dev.js");
|
|
15
|
+
|
|
16
|
+
const app = express();
|
|
17
|
+
|
|
18
|
+
const compiler = webpack(webpackConfig);
|
|
19
|
+
|
|
20
|
+
// 指定静态文件目录
|
|
21
|
+
app.use(express.static(path.join(__dirname, "../public/dist")));
|
|
22
|
+
|
|
23
|
+
// 引用divMiddleware中间件,监控文件改动
|
|
24
|
+
app.use(
|
|
25
|
+
divMiddleware(compiler, {
|
|
26
|
+
// 落地文件
|
|
27
|
+
writeToDisk: (filePath) => {
|
|
28
|
+
return filePath.endsWith(".tpl");
|
|
29
|
+
},
|
|
30
|
+
// 资源路径
|
|
31
|
+
publicPath: webpackConfig.output.publicPath,
|
|
32
|
+
// headers 配置
|
|
33
|
+
headers: {
|
|
34
|
+
"Access-Control-Allow-Origin": "*",
|
|
35
|
+
"Access-Control-Allow-Methods":
|
|
36
|
+
"GET, POST, PUT, DELETE, PATCH, OPTIONS",
|
|
37
|
+
"Access-Control-Allow-Headers":
|
|
38
|
+
"X-Requested-With, content-type, Authorization",
|
|
39
|
+
},
|
|
40
|
+
stats: {
|
|
41
|
+
colors: true,
|
|
42
|
+
},
|
|
43
|
+
}),
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
// 引用hotMiddleware中间件,实现热模块替换
|
|
47
|
+
app.use(
|
|
48
|
+
hotMiddleware(compiler, {
|
|
49
|
+
path: `${DEV_SERVER_CONFIG.HMR_PATH}`,
|
|
50
|
+
log: () => {},
|
|
51
|
+
}),
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
consoler.info("请等待webpack初次构建完成...");
|
|
55
|
+
|
|
56
|
+
const port = DEV_SERVER_CONFIG.PORT;
|
|
57
|
+
app.listen(port, () => {
|
|
58
|
+
console.log(`app listening on port ${port}`);
|
|
59
|
+
});
|
|
60
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
module.exports = {};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
const webpack = require("webpack");
|
|
2
|
+
const webBassConfig = require("./config/webpack.prod.js");
|
|
3
|
+
|
|
4
|
+
module.exports = () => {
|
|
5
|
+
console.log("\nbuilding... \n");
|
|
6
|
+
|
|
7
|
+
webpack(webBassConfig, (err, stats) => {
|
|
8
|
+
if (err) {
|
|
9
|
+
console.log(err);
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
process.stdout.write(
|
|
13
|
+
`${stats.toString({
|
|
14
|
+
colors: true, //在控制台输出色彩信息
|
|
15
|
+
modules: false, // 不显示每个模块的打包信息
|
|
16
|
+
children: false, // 不显示子编译任务的信息
|
|
17
|
+
chunks: false, // 不显示每个子代码块信息
|
|
18
|
+
chunkModules: true, // 显示代码块块中模块的信息
|
|
19
|
+
})}\n`,
|
|
20
|
+
);
|
|
21
|
+
});
|
|
22
|
+
};
|