@codertqy/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/.eslintignore +2 -0
- package/.eslintrc +55 -0
- package/README.md +218 -0
- package/app/controller/base.js +40 -0
- package/app/controller/project.js +81 -0
- package/app/controller/view.js +22 -0
- package/app/extend/logger.js +43 -0
- package/app/middleware/api-params-verify.js +73 -0
- package/app/middleware/api-sign-verify.js +49 -0
- package/app/middleware/error-handler.js +31 -0
- package/app/middleware/project-handler.js +26 -0
- package/app/middleware.js +44 -0
- package/app/pages/assets/custom.css +14 -0
- package/app/pages/boot.js +56 -0
- package/app/pages/common/curl.js +84 -0
- package/app/pages/common/index.css +3 -0
- package/app/pages/common/utils.js +1 -0
- package/app/pages/dashboard/complex-view/header-view/complex-view/sub-menu/sub-menu.vue +19 -0
- package/app/pages/dashboard/complex-view/header-view/header-view.vue +126 -0
- package/app/pages/dashboard/complex-view/iframe-view/iframe-view.vue +45 -0
- package/app/pages/dashboard/complex-view/schema-view/complex-view/search-panel/search-panel.vue +35 -0
- package/app/pages/dashboard/complex-view/schema-view/complex-view/table-panel/table-panel.vue +120 -0
- package/app/pages/dashboard/complex-view/schema-view/components/component-config.js +23 -0
- package/app/pages/dashboard/complex-view/schema-view/components/create-form/create-form.vue +87 -0
- package/app/pages/dashboard/complex-view/schema-view/components/detail-panel/detail-panel.vue +100 -0
- package/app/pages/dashboard/complex-view/schema-view/components/edit-form/edit-form.vue +122 -0
- package/app/pages/dashboard/complex-view/schema-view/hook/schema.js +161 -0
- package/app/pages/dashboard/complex-view/schema-view/schema-view.vue +95 -0
- package/app/pages/dashboard/complex-view/sider-view/complex-view/sub-menu/sub-menu.vue +19 -0
- package/app/pages/dashboard/complex-view/sider-view/sider-view.vue +135 -0
- package/app/pages/dashboard/dashboard.vue +86 -0
- package/app/pages/dashboard/entry.dashboard.js +48 -0
- package/app/pages/store/index.js +3 -0
- package/app/pages/store/menu.js +68 -0
- package/app/pages/store/project.js +12 -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 +107 -0
- package/app/pages/widgets/schema-form/complex-view/input/input.vue +138 -0
- package/app/pages/widgets/schema-form/complex-view/input-number/input-number.vue +140 -0
- package/app/pages/widgets/schema-form/complex-view/select/select.vue +122 -0
- package/app/pages/widgets/schema-form/form-item-config.js +20 -0
- package/app/pages/widgets/schema-form/schema-form.vue +135 -0
- package/app/pages/widgets/schema-search-bar/complex-view/date-range/date-range.vue +51 -0
- package/app/pages/widgets/schema-search-bar/complex-view/dynamic-select/dynamic-select.vue +63 -0
- package/app/pages/widgets/schema-search-bar/complex-view/input/input.vue +41 -0
- package/app/pages/widgets/schema-search-bar/complex-view/select/select.vue +49 -0
- package/app/pages/widgets/schema-search-bar/schema-search-bar.vue +126 -0
- package/app/pages/widgets/schema-search-bar/search-item-config.js +22 -0
- package/app/pages/widgets/schema-table/schema-table.vue +259 -0
- package/app/pages/widgets/sider-container/sider-container.vue +27 -0
- package/app/public/output/entry.page1.tpl +40 -0
- package/app/public/output/entry.page2.tpl +11 -0
- package/app/public/static/logo.png +0 -0
- package/app/public/static/normalize.css +239 -0
- package/app/router/project.js +22 -0
- package/app/router/view.js +17 -0
- package/app/router-schema/project.js +34 -0
- package/app/service/base.js +15 -0
- package/app/service/project.js +59 -0
- package/app/view/entry.tpl +25 -0
- package/app/webpack/config/webpack.base.js +280 -0
- package/app/webpack/config/webpack.dev.js +57 -0
- package/app/webpack/config/webpack.prod.js +127 -0
- package/app/webpack/dev.js +63 -0
- package/app/webpack/libs/blank.js +1 -0
- package/app/webpack/prod.js +22 -0
- package/config/config.beta.js +1 -0
- package/config/config.default.js +3 -0
- package/config/config.prod.js +1 -0
- package/elpis-core/env.js +27 -0
- package/elpis-core/index.js +98 -0
- package/elpis-core/loader/config.js +58 -0
- package/elpis-core/loader/controller.js +93 -0
- package/elpis-core/loader/extend.js +63 -0
- package/elpis-core/loader/middleware.js +84 -0
- package/elpis-core/loader/router-schema.js +56 -0
- package/elpis-core/loader/router.js +50 -0
- package/elpis-core/loader/service.js +85 -0
- package/index.js +38 -0
- package/model/index.js +129 -0
- package/package.json +92 -0
- package/test/controller/project.test.js +214 -0
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 第三步:获取本地文件数据/数据库数据 返回
|
|
3
|
+
* @param {Object} app
|
|
4
|
+
* @returns
|
|
5
|
+
*/
|
|
6
|
+
module.exports = (app) => {
|
|
7
|
+
const BaseService = require("./base")(app);
|
|
8
|
+
const modelList = require("../../model/index.js")(app);
|
|
9
|
+
return class ProjectService extends BaseService {
|
|
10
|
+
/**
|
|
11
|
+
* 根据 projKey 获取项目配置
|
|
12
|
+
* @param {string} projKey
|
|
13
|
+
*/
|
|
14
|
+
async get(projKey) {
|
|
15
|
+
let projConfig;
|
|
16
|
+
modelList.forEach((modelItem) => {
|
|
17
|
+
const { project } = modelItem;
|
|
18
|
+
if (project[projKey]) {
|
|
19
|
+
projConfig = project[projKey];
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
// 拿到对应的项目配置
|
|
23
|
+
return projConfig;
|
|
24
|
+
|
|
25
|
+
// 优化写法 拿到的数据,需要取出里面的对象
|
|
26
|
+
// return modelList.filter((modelItem) => {
|
|
27
|
+
// if (modelItem.project.key === projKey) {
|
|
28
|
+
// return modelItem;
|
|
29
|
+
// }
|
|
30
|
+
// });
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* 获取统一模型下的项目列表 比如 ppd、taobao这种而不是电商系统大范围的(如果无projKey,全量获取)
|
|
34
|
+
*/
|
|
35
|
+
async getList({ projKey }) {
|
|
36
|
+
return modelList.reduce((preList, modelItem) => {
|
|
37
|
+
const { project } = modelItem;
|
|
38
|
+
// 如果有 projKey
|
|
39
|
+
// 并且模型下没有projKey,正常返回原来的不做处理,并且不走后续代码
|
|
40
|
+
// 如果模型下有 projKey 不走该分支 继续往下执行代码 获取对应projKey所属模型下的项目
|
|
41
|
+
if (projKey && !project[projKey]) {
|
|
42
|
+
return preList;
|
|
43
|
+
}
|
|
44
|
+
// 没有传递 projKey 则 获取所有模型下的项目 pdd、taobao、douyin、bilibili
|
|
45
|
+
for (const pKey in project) {
|
|
46
|
+
preList.push(project[pKey]);
|
|
47
|
+
}
|
|
48
|
+
return preList;
|
|
49
|
+
}, []);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* 获取所有模型项目的结构化数据
|
|
54
|
+
*/
|
|
55
|
+
async getModelList() {
|
|
56
|
+
return modelList;
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html class="dark" 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="stylesheet" href="/static/normalize.css" />
|
|
8
|
+
<link href="/static/logo.png" rel="icon" type="image/x-icon" />
|
|
9
|
+
</head>
|
|
10
|
+
<body style="margin: 0; padding: 0">
|
|
11
|
+
<div id="root"></div>
|
|
12
|
+
<input id="projKey" value="{{ projKey }}" style="display: none" />
|
|
13
|
+
<input id="env" value="{{ env }}" style="display: none" />
|
|
14
|
+
<input id="options" value="{{ options }}" style="display: none" />
|
|
15
|
+
</body>
|
|
16
|
+
<script type="text/javascript">
|
|
17
|
+
try {
|
|
18
|
+
window.projKey = document.getElementById("projKey").value;
|
|
19
|
+
window.env = document.getElementById("env").value;
|
|
20
|
+
window.options = JSON.parse(document.getElementById("options").value);
|
|
21
|
+
} catch (error) {
|
|
22
|
+
console.log(error);
|
|
23
|
+
}
|
|
24
|
+
</script>
|
|
25
|
+
</html>
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
const glob = require("glob");
|
|
2
|
+
const path = require("path");
|
|
3
|
+
const fs = require("fs");
|
|
4
|
+
const { VueLoaderPlugin } = require("vue-loader");
|
|
5
|
+
const webpack = require("webpack");
|
|
6
|
+
const merge = require("webpack-merge");
|
|
7
|
+
const HtmlWebpackPlugin = require("html-webpack-plugin");
|
|
8
|
+
const CleanWebpackPlugin = require("clean-webpack-plugin");
|
|
9
|
+
|
|
10
|
+
// 动态构造 elpisPageEntries elpisHtmlWebpackPluginList
|
|
11
|
+
const elpisPageEntries = {};
|
|
12
|
+
const elpisHtmlWebpackPluginList = [];
|
|
13
|
+
|
|
14
|
+
// 获取 elpis/app/pages 目录下所有入口文件 (entry.xx.js)
|
|
15
|
+
const elpisEntryFiles = glob.sync(
|
|
16
|
+
path.resolve(__dirname, "../../pages/**/entry.*.js"),
|
|
17
|
+
);
|
|
18
|
+
elpisEntryFiles.forEach((file) => {
|
|
19
|
+
handleFile(file, elpisPageEntries, elpisHtmlWebpackPluginList);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
// 动态构造 businessPageEntries businessHtmlWebpackPluginList
|
|
23
|
+
const businessPageEntries = {};
|
|
24
|
+
const businessHtmlWebpackPluginList = [];
|
|
25
|
+
// 获取 business/app/pages 目录下所有入口文件 (entry.xx.js)
|
|
26
|
+
const businessEntryFiles = glob.sync(
|
|
27
|
+
path.resolve(process.cwd(), "./app/pages/**/entry.*.js"),
|
|
28
|
+
);
|
|
29
|
+
businessEntryFiles.forEach((file) => {
|
|
30
|
+
handleFile(file, businessPageEntries, businessHtmlWebpackPluginList);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
// 构造相关 webpack 处理的数据机构
|
|
34
|
+
function handleFile(file, entries = {}, HtmlWebpackPluginList = []) {
|
|
35
|
+
// 拿到所有的基础路径,将 .js 后缀去掉
|
|
36
|
+
const entryBaseName = path.basename(file, ".js");
|
|
37
|
+
entries[entryBaseName] = file;
|
|
38
|
+
HtmlWebpackPluginList.push(
|
|
39
|
+
// 将渲染后的数据保存的数组中
|
|
40
|
+
new HtmlWebpackPlugin({
|
|
41
|
+
// 输出文件名
|
|
42
|
+
filename: path.resolve(
|
|
43
|
+
process.cwd(),
|
|
44
|
+
"./app/public/dist/",
|
|
45
|
+
`${entryBaseName}.tpl`,
|
|
46
|
+
),
|
|
47
|
+
// 模板文件
|
|
48
|
+
template: path.resolve(__dirname, "../../view/entry.tpl"),
|
|
49
|
+
// 注入的代码块
|
|
50
|
+
chunks: [entryBaseName],
|
|
51
|
+
}),
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// 加载 业务 webpack 配置
|
|
56
|
+
let buinessWebpackConfig = {};
|
|
57
|
+
try {
|
|
58
|
+
buinessWebpackConfig = require(`${process.cwd()}/app/webpack.config.js`);
|
|
59
|
+
} catch (e) {}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* webpack 基础配置
|
|
63
|
+
*/
|
|
64
|
+
module.exports = merge.smart(
|
|
65
|
+
{
|
|
66
|
+
/**
|
|
67
|
+
* 入口配置
|
|
68
|
+
* 如果单入口。可以直接字符串指定路径
|
|
69
|
+
* 多入口,配置成对象
|
|
70
|
+
* */
|
|
71
|
+
entry: Object.assign({}, elpisPageEntries, businessPageEntries),
|
|
72
|
+
// 模块解析配置(决定了要加载解析哪些模块,以及用什么方式去解析)
|
|
73
|
+
module: {
|
|
74
|
+
rules: [
|
|
75
|
+
{
|
|
76
|
+
test: /\.vue$/,
|
|
77
|
+
use: {
|
|
78
|
+
loader: require.resolve("vue-loader"),
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
test: /\.js$/,
|
|
83
|
+
include: [
|
|
84
|
+
// 处理 elpis 目录
|
|
85
|
+
path.resolve(__dirname, "../../pages"),
|
|
86
|
+
// 处理 业务目录
|
|
87
|
+
path.resolve(process.cwd(), "./app/pages"),
|
|
88
|
+
],
|
|
89
|
+
use: {
|
|
90
|
+
loader: require.resolve("babel-loader"),
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
test: /\.(png|jpe?g|gif)(\?.+)?$/,
|
|
95
|
+
use: {
|
|
96
|
+
loader: require.resolve("url-loader"),
|
|
97
|
+
options: {
|
|
98
|
+
limit: 300,
|
|
99
|
+
esModule: false,
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
test: /\.css$/,
|
|
105
|
+
use: [require.resolve("style-loader"), require.resolve("css-loader")],
|
|
106
|
+
},
|
|
107
|
+
// loader的解析顺序是从右向左,从下向上
|
|
108
|
+
{
|
|
109
|
+
test: /\.less$/,
|
|
110
|
+
use: [
|
|
111
|
+
require.resolve("style-loader"),
|
|
112
|
+
require.resolve("css-loader"),
|
|
113
|
+
require.resolve("less-loader"),
|
|
114
|
+
],
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
test: /\.(eot|svg|ttf|woff|woff2)(\?\S*)?$/,
|
|
118
|
+
use: require.resolve("file-loader"),
|
|
119
|
+
},
|
|
120
|
+
],
|
|
121
|
+
},
|
|
122
|
+
// 产物输出路径 不指定路径则默认当前路径下的dist目录下
|
|
123
|
+
// 因为开发与生产环境输出不一致,所以在各自环境中自行配置
|
|
124
|
+
output: {},
|
|
125
|
+
// 配置模块解析的具体行为(定义 webpack 在打包时,如何找到并解析具体模块的路径)
|
|
126
|
+
resolve: {
|
|
127
|
+
extensions: [".css", ".less", ".js", ".vue"],
|
|
128
|
+
// 配置别名
|
|
129
|
+
alias: (() => {
|
|
130
|
+
const aliasMap = {};
|
|
131
|
+
const blankModulePath = path.resolve(__dirname, "../libs/blank.js");
|
|
132
|
+
|
|
133
|
+
// dashboard 路由扩展配置
|
|
134
|
+
const businessDashboardRouterConfig = path.resolve(
|
|
135
|
+
process.cwd(),
|
|
136
|
+
"./app/pages/dashboard/router.js",
|
|
137
|
+
);
|
|
138
|
+
aliasMap["$businessDashboardRouterConfig"] = fs.existsSync(
|
|
139
|
+
businessDashboardRouterConfig,
|
|
140
|
+
)
|
|
141
|
+
? businessDashboardRouterConfig
|
|
142
|
+
: blankModulePath;
|
|
143
|
+
|
|
144
|
+
// schema-view component 扩展配置
|
|
145
|
+
const businessComponentConfig = path.resolve(
|
|
146
|
+
process.cwd(),
|
|
147
|
+
"./app/pages/dashboard/complex-view/schema-view/components/component-config.js",
|
|
148
|
+
);
|
|
149
|
+
aliasMap["$businessComponentConfig"] = fs.existsSync(
|
|
150
|
+
businessComponentConfig,
|
|
151
|
+
)
|
|
152
|
+
? businessComponentConfig
|
|
153
|
+
: blankModulePath;
|
|
154
|
+
|
|
155
|
+
// schema-form 扩展配置
|
|
156
|
+
const businessFormItemConfig = path.resolve(
|
|
157
|
+
process.cwd(),
|
|
158
|
+
"./app/pages/widgets/schema-form/form-item-config.js",
|
|
159
|
+
);
|
|
160
|
+
aliasMap["$businessFormItemConfig"] = fs.existsSync(
|
|
161
|
+
businessFormItemConfig,
|
|
162
|
+
)
|
|
163
|
+
? businessFormItemConfig
|
|
164
|
+
: blankModulePath;
|
|
165
|
+
|
|
166
|
+
// schema-search-bar 扩展配置
|
|
167
|
+
const businessSearchItemConfig = path.resolve(
|
|
168
|
+
process.cwd(),
|
|
169
|
+
"./app/pages/widgets/schema-search-bar/search-item-config.js",
|
|
170
|
+
);
|
|
171
|
+
aliasMap["$businessSearchItemConfig"] = fs.existsSync(
|
|
172
|
+
businessSearchItemConfig,
|
|
173
|
+
)
|
|
174
|
+
? businessSearchItemConfig
|
|
175
|
+
: blankModulePath;
|
|
176
|
+
|
|
177
|
+
return {
|
|
178
|
+
vue: require.resolve("vue"),
|
|
179
|
+
$elpisPages: path.resolve(__dirname, "../../pages"),
|
|
180
|
+
$elpisCommon: path.resolve(__dirname, "../../pages/common"),
|
|
181
|
+
$elpisCurl: path.resolve(__dirname, "../../pages/common/curl.js"),
|
|
182
|
+
$elpisUtils: path.resolve(__dirname, "../../pages/common/utils.js"),
|
|
183
|
+
$elpisWidgets: path.resolve(__dirname, "../../pages/widgets"),
|
|
184
|
+
$elpisHeaderContainer: path.resolve(
|
|
185
|
+
__dirname,
|
|
186
|
+
"../../pages/widgets/header-container/header-container.vue",
|
|
187
|
+
),
|
|
188
|
+
$elpisSiderContainer: path.resolve(
|
|
189
|
+
__dirname,
|
|
190
|
+
"../../pages/widgets/sider-container/sider-container.vue",
|
|
191
|
+
),
|
|
192
|
+
$elpisSchemaTable: path.resolve(
|
|
193
|
+
__dirname,
|
|
194
|
+
"../../pages/widgets/schema-table/schema-table.vue",
|
|
195
|
+
),
|
|
196
|
+
$elpisSchemaForm: path.resolve(
|
|
197
|
+
__dirname,
|
|
198
|
+
"../../pages/widgets/schema-form/schema-form.vue",
|
|
199
|
+
),
|
|
200
|
+
$elpisSchemaSearchBar: path.resolve(
|
|
201
|
+
__dirname,
|
|
202
|
+
"../../pages/widgets/schema-search-bar/schema-search-bar.vue",
|
|
203
|
+
),
|
|
204
|
+
$elpisStore: path.resolve(__dirname, "../../pages/store"),
|
|
205
|
+
$elpisBoot: path.resolve(__dirname, "../../pages/boot.js"),
|
|
206
|
+
...aliasMap,
|
|
207
|
+
};
|
|
208
|
+
})(),
|
|
209
|
+
},
|
|
210
|
+
// 配置 webpack 插件
|
|
211
|
+
plugins: [
|
|
212
|
+
// 无论是 开发 还是 生产 每次 build 前, 清空 public/dist 目录
|
|
213
|
+
new CleanWebpackPlugin(["public/dist"], {
|
|
214
|
+
root: path.resolve(process.cwd(), "./app/"),
|
|
215
|
+
exclude: [],
|
|
216
|
+
verbose: true,
|
|
217
|
+
dry: false,
|
|
218
|
+
}),
|
|
219
|
+
// 处理.vue文件,必须配置,职责:将定义过的其他规则复制并应用到 .vue 文件中
|
|
220
|
+
// 例如:有一条匹配规则 /\.js$\ 的规则,那么它会应用到 .vue 文件中的 <script> 板块中
|
|
221
|
+
new VueLoaderPlugin(),
|
|
222
|
+
// 把第三方库中暴露到 window context 下
|
|
223
|
+
new webpack.ProvidePlugin({
|
|
224
|
+
Vue: "vue",
|
|
225
|
+
axios: "axios",
|
|
226
|
+
_: "lodash",
|
|
227
|
+
}),
|
|
228
|
+
// 定义全局常量
|
|
229
|
+
new webpack.DefinePlugin({
|
|
230
|
+
__VUE_OPTIONS_API__: "true", //支持 vue 解析 optionsApi
|
|
231
|
+
__VUE_PROD_DEVTOOLS__: "false",
|
|
232
|
+
__VUE_PROD_HYDRATION_MISMATCH_DETAILS__: "false", //禁用生产环境显示 ‘水合’ 信息
|
|
233
|
+
}),
|
|
234
|
+
// 构造最终渲染的文件
|
|
235
|
+
...elpisHtmlWebpackPluginList,
|
|
236
|
+
...businessHtmlWebpackPluginList,
|
|
237
|
+
],
|
|
238
|
+
// 配置打包输出优化(代码分割、模块合并、缓存、tree-shaking、压缩等优化策略)
|
|
239
|
+
optimization: {
|
|
240
|
+
/**
|
|
241
|
+
* 把 js 文件打包成三种类型
|
|
242
|
+
* - vender: 第三方库,基本不会改动,除非依赖版本升级
|
|
243
|
+
* - common: 公共库,基本不会改动,除非业务逻辑改动
|
|
244
|
+
* - entry.{page}: 不用页面 entry 里的业务组件代码的差异部分,会经常改动
|
|
245
|
+
* 目的:把改动和引用频率不一样的 js 区分出来,已达到更好利用浏览器缓存的效果
|
|
246
|
+
*/
|
|
247
|
+
splitChunks: {
|
|
248
|
+
chunks: "all", //同步异步都分割
|
|
249
|
+
maxAsyncRequests: 10, //每次异步加载的最大并行请求数
|
|
250
|
+
maxInitialRequests: 10, // 入口点的最大并行请求数
|
|
251
|
+
cacheGroups: {
|
|
252
|
+
/**
|
|
253
|
+
* 如果公共模块的优先级比第三方库的高,会导致将依赖库的也打包的common里面
|
|
254
|
+
*/
|
|
255
|
+
vender: {
|
|
256
|
+
//第三方依赖库
|
|
257
|
+
name: "vender",
|
|
258
|
+
test: /[\\/]node_modules[\\/]/,
|
|
259
|
+
priority: 20, //优先级:数字越大,优先级越高,默认是0
|
|
260
|
+
enforce: true, //强制执行
|
|
261
|
+
reuseExistingChunk: true, //如果该chunk中引用了已经被抽取的chunk,则不生成新的chunk
|
|
262
|
+
},
|
|
263
|
+
common: {
|
|
264
|
+
//公共 将动态导入的组件,懒加载使用
|
|
265
|
+
// test: /[\\/]common|widgets[\\/]/,
|
|
266
|
+
name: "common",
|
|
267
|
+
minChunks: 2, // 被两处引用即被归为公共模块
|
|
268
|
+
minSize: 1, //最小分割文件大小 ( 1 byte )
|
|
269
|
+
priority: 10,
|
|
270
|
+
reuseExistingChunk: true,
|
|
271
|
+
},
|
|
272
|
+
},
|
|
273
|
+
},
|
|
274
|
+
|
|
275
|
+
// 将 webpack 运行时的代码打包到 runtime.js 提升效率
|
|
276
|
+
runtimeChunk: true,
|
|
277
|
+
},
|
|
278
|
+
},
|
|
279
|
+
buinessWebpackConfig,
|
|
280
|
+
);
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
// 专门用来webpack合并的
|
|
2
|
+
const merge = require("webpack-merge");
|
|
3
|
+
const path = require("path");
|
|
4
|
+
const webpack = require("webpack");
|
|
5
|
+
// 基类配置
|
|
6
|
+
const baseConfig = require("./webpack.base.js");
|
|
7
|
+
|
|
8
|
+
// dev-servery 配置
|
|
9
|
+
const DEV_SERVER_CONFIG = {
|
|
10
|
+
HOST: "127.0.0.1",
|
|
11
|
+
PORT: 9002,
|
|
12
|
+
HMR_PATH: "/__webpack_hmr", // 官方规定的
|
|
13
|
+
TIMEOUT: 20000,
|
|
14
|
+
};
|
|
15
|
+
// 开发阶段的 entry 配置需要加入 hmr
|
|
16
|
+
Object.keys(baseConfig.entry).forEach((v) => {
|
|
17
|
+
// 第三方包不作为 hmr入口
|
|
18
|
+
if (v !== "vendor") {
|
|
19
|
+
baseConfig.entry[v] = [
|
|
20
|
+
// 主入口文件
|
|
21
|
+
baseConfig.entry[v],
|
|
22
|
+
// hmr 更新入口,官方指定的 hmr 路径
|
|
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.TIMEOUT}&reload=true`,
|
|
24
|
+
];
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
// 开发环境 webpack 配置
|
|
29
|
+
const webpackConfig = merge.smart(baseConfig, {
|
|
30
|
+
// 指定开发环境
|
|
31
|
+
mode: "development",
|
|
32
|
+
// 添加 source-map 开发工具,呈现代码的映射关系,便于在开发过程中调试代码
|
|
33
|
+
devtool: "eval-cheap-module-source-map",
|
|
34
|
+
// 开发环境的 output 配置
|
|
35
|
+
output: {
|
|
36
|
+
filename: "js/[name]_[contenthash:8].bundle.js",
|
|
37
|
+
path: path.resolve(process.cwd(), "./app/public/dist/dev/"), //输出文件存储路径
|
|
38
|
+
publicPath: `http://${DEV_SERVER_CONFIG.HOST}:${DEV_SERVER_CONFIG.PORT}/public/dist/dev/`, //外部资源公共路径
|
|
39
|
+
crossOriginLoading: "anonymous", //不携带凭证,允许跨域
|
|
40
|
+
clean: true, // 清理打包的结果,不会先删除再创建
|
|
41
|
+
globalObject: "this", //多环境打包
|
|
42
|
+
},
|
|
43
|
+
// 开发环境搭建
|
|
44
|
+
plugins: [
|
|
45
|
+
// HotModuleReplacementPlugin 实现热模块替换 HMR
|
|
46
|
+
// 允许在应用程序运行时替换模块、极大提升效率,因为可以让应用运行时更新
|
|
47
|
+
new webpack.HotModuleReplacementPlugin({
|
|
48
|
+
multiStep: true,
|
|
49
|
+
}),
|
|
50
|
+
],
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
module.exports = {
|
|
54
|
+
webpackConfig,
|
|
55
|
+
// dev-server 配置,暴露给 dev.js 使用
|
|
56
|
+
DEV_SERVER_CONFIG,
|
|
57
|
+
};
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
// 专门用来webpack合并的
|
|
2
|
+
const merge = require("webpack-merge");
|
|
3
|
+
const path = require("path");
|
|
4
|
+
|
|
5
|
+
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
|
|
6
|
+
|
|
7
|
+
const CSSMinimizerPlugin = require("css-minimizer-webpack-plugin");
|
|
8
|
+
|
|
9
|
+
const HtmlWebpackInjectAttributesPlugin = require("html-webpack-inject-attributes-plugin");
|
|
10
|
+
const TerserWebpackPlugin = require("terser-webpack-plugin");
|
|
11
|
+
|
|
12
|
+
// 开启多线程打包
|
|
13
|
+
const os = require("os");
|
|
14
|
+
|
|
15
|
+
// 基类配置
|
|
16
|
+
const baseConfig = require("./webpack.base.js");
|
|
17
|
+
// 生产环境 webpack 配置
|
|
18
|
+
const webpackProdConfig = merge.smart(baseConfig, {
|
|
19
|
+
// 指定生产环境
|
|
20
|
+
mode: "production",
|
|
21
|
+
module: {
|
|
22
|
+
rules: [
|
|
23
|
+
{
|
|
24
|
+
test: /\.css$/,
|
|
25
|
+
use: [
|
|
26
|
+
MiniCssExtractPlugin.loader,
|
|
27
|
+
{
|
|
28
|
+
loader: require.resolve("thread-loader"),
|
|
29
|
+
options: {
|
|
30
|
+
workers: os.cpus().length, // 根据 CPU 核心数设置线程数
|
|
31
|
+
workerParallelJobs: 50, // 每个线程并行任务数
|
|
32
|
+
poolTimeout: 2000, // 线程空闲时的超时时间
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
require.resolve("css-loader"),
|
|
36
|
+
],
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
test: /\.js$/,
|
|
40
|
+
include: [
|
|
41
|
+
// 处理 elpis 目录
|
|
42
|
+
path.resolve(__dirname, "../../pages"),
|
|
43
|
+
// 处理 业务目录
|
|
44
|
+
path.resolve(process.cwd(), "./app/pages"),
|
|
45
|
+
],
|
|
46
|
+
use: [
|
|
47
|
+
{
|
|
48
|
+
loader: require.resolve("thread-loader"),
|
|
49
|
+
options: {
|
|
50
|
+
workers: os.cpus().length,
|
|
51
|
+
workerParallelJobs: 50,
|
|
52
|
+
poolTimeout: 2000,
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
require.resolve("babel-loader"),
|
|
56
|
+
],
|
|
57
|
+
},
|
|
58
|
+
],
|
|
59
|
+
},
|
|
60
|
+
// 生产环境的 output 配置
|
|
61
|
+
output: {
|
|
62
|
+
filename: "js/[name]_[chunkhash:8].bundle.js",
|
|
63
|
+
path: path.join(process.cwd(), "./app/public/dist/prod/"),
|
|
64
|
+
publicPath: "/dist/prod/", //从哪个路径启动服务并访问输出文件
|
|
65
|
+
crossOriginLoading: "anonymous", //不携带凭证,允许跨域
|
|
66
|
+
},
|
|
67
|
+
// webpack 不会有大量 hints 信息 默认为 warning
|
|
68
|
+
performance: {
|
|
69
|
+
hints: false,
|
|
70
|
+
},
|
|
71
|
+
// 插件
|
|
72
|
+
plugins: [
|
|
73
|
+
// 提取 css 的公共部分,有效利用缓存,(非公共部分使用 inline)
|
|
74
|
+
new MiniCssExtractPlugin({
|
|
75
|
+
chunkFilename: "css/[name]_[contenthash:8].bundle.css",
|
|
76
|
+
}),
|
|
77
|
+
// // 多线程打包 JS ,加快打包速度
|
|
78
|
+
// new HappyPack({
|
|
79
|
+
// ...happypackCommonConfig,
|
|
80
|
+
// id: "js",
|
|
81
|
+
// loaders: [
|
|
82
|
+
// `babel-loader?${JSON.stringify({
|
|
83
|
+
// presets: ["@babel/preset-env"],
|
|
84
|
+
// plugins: ["@babel/plugin-transform-runtime"],
|
|
85
|
+
// })}`,
|
|
86
|
+
// ],
|
|
87
|
+
// }),
|
|
88
|
+
// // 多线程打包 CSS ,加快打包速度
|
|
89
|
+
// new HappyPack({
|
|
90
|
+
// ...happypackCommonConfig,
|
|
91
|
+
// id: "css",
|
|
92
|
+
// loaders: [
|
|
93
|
+
// {
|
|
94
|
+
// path: "css-loader",
|
|
95
|
+
// options: {
|
|
96
|
+
// importLoaders: 1,
|
|
97
|
+
// },
|
|
98
|
+
// },
|
|
99
|
+
// ],
|
|
100
|
+
// }),
|
|
101
|
+
// 浏览器在请求资源时不发送用户的身份凭证
|
|
102
|
+
new HtmlWebpackInjectAttributesPlugin({
|
|
103
|
+
crossorigin: "anonymous",
|
|
104
|
+
}),
|
|
105
|
+
],
|
|
106
|
+
optimization: {
|
|
107
|
+
// 使用 TerserWebpackPlugin 的并发和缓存,提升压缩阶段的性能
|
|
108
|
+
minimize: true,
|
|
109
|
+
minimizer: [
|
|
110
|
+
// 压缩 CSS
|
|
111
|
+
new CSSMinimizerPlugin(),
|
|
112
|
+
// 压缩 JS
|
|
113
|
+
new TerserWebpackPlugin({
|
|
114
|
+
parallel: true, //利用多核 CPU 加快 压缩速度
|
|
115
|
+
// cache: true, //启用缓存来加速构建过程
|
|
116
|
+
terserOptions: {
|
|
117
|
+
//配置项
|
|
118
|
+
compress: {
|
|
119
|
+
drop_console: true, //去掉 console.log 内容
|
|
120
|
+
drop_debugger: true, // 去掉debugger
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
}),
|
|
124
|
+
],
|
|
125
|
+
},
|
|
126
|
+
});
|
|
127
|
+
module.exports = webpackProdConfig;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 本地开发启动 devServer
|
|
3
|
+
*/
|
|
4
|
+
const express = require("express");
|
|
5
|
+
const path = require("path");
|
|
6
|
+
const consoler = require("consoler");
|
|
7
|
+
const webpack = require("webpack");
|
|
8
|
+
const devMiddleware = require("webpack-dev-middleware");
|
|
9
|
+
const hotMiddleware = require("webpack-hot-middleware");
|
|
10
|
+
|
|
11
|
+
module.exports = () => {
|
|
12
|
+
const { webpackConfig, DEV_SERVER_CONFIG } = require("./config/webpack.dev");
|
|
13
|
+
|
|
14
|
+
const app = express();
|
|
15
|
+
|
|
16
|
+
const compiler = webpack(webpackConfig);
|
|
17
|
+
|
|
18
|
+
// 指定静态文件目录
|
|
19
|
+
app.use(express.static(path.join(__dirname, "../public/dist")));
|
|
20
|
+
|
|
21
|
+
// 引用 devMiddelware 中间件(监控文件改动)
|
|
22
|
+
app.use(
|
|
23
|
+
devMiddleware(compiler, {
|
|
24
|
+
// 落地文件,不需要打包到内存中的,比如 tpl 文件
|
|
25
|
+
writeToDisk: (filePath) => {
|
|
26
|
+
return filePath.endsWith(".tpl");
|
|
27
|
+
},
|
|
28
|
+
// 资源路径
|
|
29
|
+
publicPath: webpackConfig.output.publicPath,
|
|
30
|
+
|
|
31
|
+
// headers 配置
|
|
32
|
+
headers: {
|
|
33
|
+
"Access-Control-Allow-Origin": "*",
|
|
34
|
+
"Access-Control-Allow-Methods":
|
|
35
|
+
"GET, POST, PUT, DELETE, PATCH, OPTIONS",
|
|
36
|
+
"Access-Control-Allow-Headers":
|
|
37
|
+
"X-Requested-With, content-type, Authorization",
|
|
38
|
+
},
|
|
39
|
+
stats: {
|
|
40
|
+
// 打印有颜色
|
|
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] 请等待 webpack 初次构建完成提升..");
|
|
55
|
+
|
|
56
|
+
// 启动kd
|
|
57
|
+
const port = DEV_SERVER_CONFIG.PORT;
|
|
58
|
+
app.listen(port, () => {
|
|
59
|
+
console.log(
|
|
60
|
+
`[webpack] app listening on port 成功, http://localhost:${port}`,
|
|
61
|
+
);
|
|
62
|
+
});
|
|
63
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
module.exports = {};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
const webpack = require("webpack");
|
|
2
|
+
const webpackProdConfig = require("./config/webpack.prod.js");
|
|
3
|
+
|
|
4
|
+
module.exports = () => {
|
|
5
|
+
console.log("\n building... \n");
|
|
6
|
+
|
|
7
|
+
webpack(webpackProdConfig, (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
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
module.exports = {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
module.exports = {};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 处理环境问题
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
module.exports = (app) => {
|
|
6
|
+
// process.env._ENV的值是自己定义的
|
|
7
|
+
const envValue = process.env._ENV.trim() ?? "local";
|
|
8
|
+
return {
|
|
9
|
+
// 判断是否本地环境
|
|
10
|
+
isLocal() {
|
|
11
|
+
return envValue === "local";
|
|
12
|
+
},
|
|
13
|
+
|
|
14
|
+
// 判断是否测试环境
|
|
15
|
+
isBeta() {
|
|
16
|
+
return envValue === "beta";
|
|
17
|
+
},
|
|
18
|
+
// 判断是否生产环境
|
|
19
|
+
isProd() {
|
|
20
|
+
return envValue === "prod";
|
|
21
|
+
},
|
|
22
|
+
// 获取当前环境
|
|
23
|
+
get() {
|
|
24
|
+
return envValue ?? "local";
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
};
|