akfun 5.1.15 → 6.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/README.md +342 -215
- package/package.json +15 -15
- package/src/build2esm.js +9 -7
- package/src/config/babel.config.js +2 -0
- package/src/config/index.js +3 -0
- package/src/config/rollup.config.js +13 -4
- package/src/initData/akfun-package.json +14 -10
- package/src/initData/config/babel.config.js +3 -1
- package/src/manage/ConfigManager.js +8 -8
- package/src/utils/configValidator.js +8 -13
- package/src/webpack/webpack.base.conf.js +52 -11
- package/src/webpack/webpack.dev.conf.js +1 -1
- package/src/webpack/webpack.library.conf.js +1 -1
- package/src/webpack/webpack.prod.conf.js +1 -1
package/README.md
CHANGED
|
@@ -1,341 +1,468 @@
|
|
|
1
|
-
|
|
2
|
-
AKFun 是一个基于 Webpack 与 Rollup 的多场景前端打包工具,支持 Vue、React、React+TS 技术栈,致力于提供“零配置、开箱即用”的工程能力,让开发者专注业务。
|
|
3
|
-
|
|
4
|
-
### 主要特性
|
|
5
|
-
- **零配置**: 内置默认配置,开箱即用;
|
|
6
|
-
- **多技术栈**: 支持 Vue、React、React+TS 的调试与构建;
|
|
7
|
-
- **多构建场景**: 本地开发(含热更新/代理)、生产构建、库构建(UMD/ESM);
|
|
8
|
-
- **灵活可配**: 支持入口、别名、代理、SASS 注入、ESLint/StyleLint、Babel/Loader/Plugin 扩展等配置;
|
|
9
|
-
- **样式与规范**: 集成 Autoprefixer、Sass、PostCSS、ESLint、StyleLint;
|
|
10
|
-
- **参数替换**: 支持基于 [params-replace-loader](https://www.npmjs.com/package/params-replace-loader) 的环境变量批量替换;
|
|
11
|
-
- **模板支持**: 提供完整的 Vue/React 项目模板。
|
|
1
|
+
# AKFun 前端脚手架
|
|
12
2
|
|
|
13
|
-
|
|
3
|
+
AKFun 是一个基于 Webpack 与 Rollup 的多场景前端打包工具,支持 Vue、React、React+TS 技术栈,致力于提供"零配置、开箱即用"的工程能力,让开发者专注业务。
|
|
4
|
+
|
|
5
|
+
## 目录
|
|
6
|
+
|
|
7
|
+
- [主要特性](#主要特性)
|
|
8
|
+
- [安装](#安装)
|
|
9
|
+
- [快速开始](#快速开始)
|
|
10
|
+
- [命令说明](#命令说明)
|
|
11
|
+
- [配置指南](#配置指南)
|
|
12
|
+
- [配置文件说明](#配置文件说明)
|
|
13
|
+
- [基础配置](#基础配置)
|
|
14
|
+
- [开发配置](#开发配置)
|
|
15
|
+
- [构建配置](#构建配置)
|
|
16
|
+
- [高级配置](#高级配置)
|
|
17
|
+
- [其他说明](#其他说明)
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## 主要特性
|
|
22
|
+
|
|
23
|
+
- **零配置**: 内置默认配置,开箱即用
|
|
24
|
+
- **多技术栈**: 支持 Vue、React、React+TS 的调试与构建
|
|
25
|
+
- **多构建场景**: 本地开发(含热更新/代理)、生产构建、库构建(UMD/ESM)
|
|
26
|
+
- **灵活可配**: 支持入口、别名、代理、SASS 注入、ESLint/StyleLint、Babel/Loader/Plugin 扩展等配置
|
|
27
|
+
- **样式与规范**: 集成 Autoprefixer、Sass、PostCSS、ESLint、StyleLint
|
|
28
|
+
- **参数替换**: 支持基于 [params-replace-loader](https://www.npmjs.com/package/params-replace-loader) 的环境变量批量替换
|
|
29
|
+
- **模板支持**: 提供完整的 Vue/React 项目模板
|
|
30
|
+
- **内置缓存机制**: 内置缓存机制,提升二次构建速度
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## 安装
|
|
35
|
+
|
|
36
|
+
### 全局安装
|
|
14
37
|
|
|
15
|
-
### 方法一:全局安装
|
|
16
|
-
1) 安装
|
|
17
38
|
```bash
|
|
18
39
|
yarn global add akfun
|
|
19
40
|
# 或
|
|
20
41
|
npm i -g akfun
|
|
21
42
|
```
|
|
22
|
-
2) 创建项目(可指定模板与目录)
|
|
23
|
-
```bash
|
|
24
|
-
akfun init -t=vue
|
|
25
|
-
# 指定目录
|
|
26
|
-
akfun init -t=vue --dir=myTest1
|
|
27
|
-
```
|
|
28
|
-
3) 运行构建(需先安装依赖)
|
|
29
|
-
```bash
|
|
30
|
-
# 本地开发调试
|
|
31
|
-
akfun dev
|
|
32
|
-
|
|
33
|
-
# 生产环境构建
|
|
34
|
-
akfun build
|
|
35
43
|
|
|
36
|
-
|
|
37
|
-
akfun build2lib
|
|
38
|
-
|
|
39
|
-
# 构建库(ESM)
|
|
40
|
-
akfun build2esm
|
|
41
|
-
```
|
|
44
|
+
### 项目内安装
|
|
42
45
|
|
|
43
|
-
### 方法二:在现有项目中使用
|
|
44
|
-
1) 安装到当前项目
|
|
45
46
|
```bash
|
|
46
47
|
yarn add akfun --dev
|
|
47
48
|
# 或
|
|
48
49
|
npm i akfun --save-dev
|
|
49
50
|
```
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
```bash
|
|
59
|
-
akfun
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## 快速开始
|
|
55
|
+
|
|
56
|
+
### 方式一:创建新项目
|
|
57
|
+
|
|
58
|
+
1. **创建项目**(可指定模板与目录)
|
|
59
|
+
```bash
|
|
60
|
+
akfun init -t=vue
|
|
61
|
+
# 指定目录
|
|
62
|
+
akfun init -t=vue --dir=myTest1
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
2. **安装依赖**
|
|
66
|
+
```bash
|
|
67
|
+
cd myTest1
|
|
68
|
+
npm install
|
|
69
|
+
# 或
|
|
70
|
+
yarn install
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
3. **开始开发**
|
|
74
|
+
```bash
|
|
75
|
+
akfun dev
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### 方式二:在现有项目中使用
|
|
79
|
+
|
|
80
|
+
1. **安装依赖**(见上方安装说明)
|
|
81
|
+
|
|
82
|
+
2. **初始化配置文件**
|
|
83
|
+
```bash
|
|
84
|
+
akfun config init
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
3. **在 package.json 添加脚本**
|
|
88
|
+
```json
|
|
89
|
+
{
|
|
90
|
+
"scripts": {
|
|
91
|
+
"dev": "akfun dev",
|
|
92
|
+
"build": "akfun build",
|
|
93
|
+
"build2lib": "akfun build2lib",
|
|
94
|
+
"build2esm": "akfun build2esm"
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
4. **运行命令**
|
|
100
|
+
```bash
|
|
101
|
+
npm run dev
|
|
102
|
+
npm run build
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## 命令说明
|
|
108
|
+
|
|
109
|
+
| 命令 | 说明 |
|
|
110
|
+
|------|------|
|
|
111
|
+
| `akfun init` | 交互式创建项目,支持 `-t`(模板类型)、`--dir`(目录名)参数 |
|
|
112
|
+
| `akfun config init` | 在当前项目生成 `akfun.config.js` 配置文件 |
|
|
113
|
+
| `akfun dev` | 启动本地开发服务器(含热更新、接口代理、可选 HTTPS、可选 ESLint/StyleLint) |
|
|
114
|
+
| `akfun build` | 生产环境构建(压缩优化、可选分析) |
|
|
115
|
+
| `akfun build2lib` | 构建 UMD 格式的库产物 |
|
|
116
|
+
| `akfun build2esm` | 构建 ESM 格式的库产物 |
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
## 配置指南
|
|
121
|
+
|
|
122
|
+
### 配置文件说明
|
|
123
|
+
|
|
124
|
+
AKFun 默认提供完整配置,开箱即用。如需自定义配置,执行 `akfun config init` 生成 `akfun.config.js` 文件,然后按需修改。
|
|
125
|
+
|
|
126
|
+
配置文件采用 CommonJS 格式,导出一个配置对象:
|
|
127
|
+
|
|
128
|
+
```javascript
|
|
129
|
+
module.exports = {
|
|
130
|
+
// 配置项...
|
|
131
|
+
}
|
|
67
132
|
```
|
|
68
133
|
|
|
69
|
-
|
|
70
|
-
- **akfun init**: 交互式创建项目(支持 -t、--dir)。
|
|
71
|
-
- **akfun config init**: 在当前项目生成 `akfun.config.js`。
|
|
72
|
-
- **akfun dev**: 本地开发调试(含热更新、接口代理、可选 HTTPS、可选 ESLint/StyleLint)。
|
|
73
|
-
- **akfun build**: 生产环境构建(压缩优化、可选分析)。
|
|
74
|
-
- **akfun build2lib**: 构建 UMD 库产物。
|
|
75
|
-
- **akfun build2esm**: 构建 ESM 库产物。
|
|
134
|
+
---
|
|
76
135
|
|
|
77
|
-
|
|
78
|
-
- 当 `entry` 仅配置一个且对应文件不存在时,会自动从 `src/pages` 扫描以 `.ts/.tsx/.js/.jsx` 结尾的文件作为入口,匹配同名 HTML 作为模板(对应正则 `/\.[tj]sx?$/`)。
|
|
79
|
-
- 仅 `dev` 和 `build` 使用页面模板;`build2lib` 不向页面注入打包产物。
|
|
80
|
-
- 优先使用 `./src/index.html`;不存在时使用内置默认模板。多页面时若 `pages` 下存在同名 HTML,将其作为页面模板。
|
|
136
|
+
### 基础配置
|
|
81
137
|
|
|
82
|
-
|
|
83
|
-
AKFun 默认提供完整配置;如需自定义,执行 `akfun config init` 生成 `akfun.config.js` 并按需修改。以下为常用配置。
|
|
138
|
+
#### 1. 代码规范检查
|
|
84
139
|
|
|
85
|
-
|
|
86
|
-
|
|
140
|
+
控制 ESLint 和 StyleLint 的启用与自动修复:
|
|
141
|
+
|
|
142
|
+
```javascript
|
|
87
143
|
module.exports = {
|
|
88
144
|
settings: {
|
|
89
|
-
enableESLint: true,
|
|
90
|
-
enableESLintFix: false,
|
|
91
|
-
enableStyleLint: true,
|
|
92
|
-
enableStyleLintFix: false
|
|
93
|
-
}
|
|
94
|
-
...
|
|
145
|
+
enableESLint: true, // 是否开启 ESLint,默认开启
|
|
146
|
+
enableESLintFix: false, // 是否 ESLint 自动修正代码格式
|
|
147
|
+
enableStyleLint: true, // 是否开启 StyleLint,默认开启
|
|
148
|
+
enableStyleLintFix: false // 是否 StyleLint 自动修正代码格式
|
|
149
|
+
}
|
|
95
150
|
}
|
|
96
151
|
```
|
|
97
152
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
153
|
+
#### 2. 构建入口
|
|
154
|
+
|
|
155
|
+
配置构建入口文件,支持多入口。优先级:`dev/build/build2lib.entry` > `webpack.entry`
|
|
156
|
+
|
|
157
|
+
> **提示**: 建议以 key/value(object `{ <key>: string | [string] }`)配置 entry。详情参考 [Webpack 文档](https://www.webpackjs.com/configuration/entry-context/#entry)
|
|
158
|
+
|
|
159
|
+
```javascript
|
|
101
160
|
module.exports = {
|
|
102
|
-
...
|
|
103
161
|
webpack: {
|
|
104
|
-
entry: {
|
|
162
|
+
entry: {
|
|
163
|
+
index: './src/index.js'
|
|
164
|
+
}
|
|
105
165
|
},
|
|
106
|
-
|
|
166
|
+
// 各场景可单独配置入口
|
|
107
167
|
dev: { entry: {} },
|
|
108
168
|
build: { entry: {} },
|
|
109
169
|
build2lib: { entry: {} },
|
|
110
170
|
build2esm: {
|
|
111
171
|
input: resolve('src/main.js'),
|
|
112
|
-
fileName: 'index'
|
|
113
|
-
}
|
|
114
|
-
...
|
|
172
|
+
fileName: 'index'
|
|
173
|
+
}
|
|
115
174
|
}
|
|
116
175
|
```
|
|
117
176
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
177
|
+
#### 3. 文件解析配置
|
|
178
|
+
|
|
179
|
+
配置模块解析的文件扩展名:
|
|
180
|
+
|
|
181
|
+
> 详情参考 [Webpack resolve.extensions 文档](https://www.webpackjs.com/configuration/resolve/#resolve-extensions)
|
|
182
|
+
|
|
183
|
+
```javascript
|
|
121
184
|
module.exports = {
|
|
122
|
-
...
|
|
123
185
|
webpack: {
|
|
124
186
|
resolve: {
|
|
125
|
-
extensions: ['.js', '.jsx', '.vue', 'json']
|
|
187
|
+
extensions: ['.js', '.jsx', '.vue', '.json']
|
|
126
188
|
}
|
|
127
|
-
}
|
|
128
|
-
...
|
|
189
|
+
}
|
|
129
190
|
}
|
|
130
191
|
```
|
|
131
192
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
193
|
+
#### 4. 路径别名配置
|
|
194
|
+
|
|
195
|
+
配置模块路径别名,简化导入路径:
|
|
196
|
+
|
|
197
|
+
> 详情参考 [Webpack resolve.alias 文档](https://www.webpackjs.com/configuration/resolve/#resolve-alias)
|
|
198
|
+
|
|
199
|
+
```javascript
|
|
135
200
|
module.exports = {
|
|
136
|
-
...
|
|
137
201
|
webpack: {
|
|
138
202
|
resolve: {
|
|
139
|
-
alias: {
|
|
203
|
+
alias: {
|
|
204
|
+
'@': resolve('src'),
|
|
205
|
+
'components': resolve('src/components')
|
|
206
|
+
}
|
|
140
207
|
}
|
|
141
|
-
}
|
|
142
|
-
...
|
|
208
|
+
}
|
|
143
209
|
}
|
|
144
210
|
```
|
|
145
211
|
|
|
146
|
-
|
|
147
|
-
|
|
212
|
+
#### 5. 页面模板与样式资源
|
|
213
|
+
|
|
214
|
+
```javascript
|
|
148
215
|
module.exports = {
|
|
149
|
-
...
|
|
150
216
|
webpack: {
|
|
151
|
-
template: '',
|
|
152
|
-
sassResources: [
|
|
217
|
+
template: '', // 自定义页面模板路径
|
|
218
|
+
sassResources: [ // 为每个 .scss 文件注入公共 SASS(变量、mixin、function 等)
|
|
219
|
+
resolve('src/assets/css/mixin.scss'),
|
|
220
|
+
resolve('src/assets/css/variables.scss')
|
|
221
|
+
]
|
|
153
222
|
}
|
|
154
|
-
...
|
|
155
223
|
}
|
|
156
224
|
```
|
|
157
225
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
226
|
+
#### 6. 依赖打包策略
|
|
227
|
+
|
|
228
|
+
控制是否忽略 `node_modules` 中的依赖,减少打包体积:
|
|
229
|
+
|
|
230
|
+
```javascript
|
|
161
231
|
module.exports = {
|
|
162
|
-
...
|
|
163
232
|
webpack: {
|
|
164
|
-
ignoreNodeModules: true,
|
|
165
|
-
allowList: [
|
|
233
|
+
ignoreNodeModules: true, // 是否忽略 node_modules 中的依赖文件
|
|
234
|
+
allowList: [ // 配置需要注入 bundle 的依赖包(ignoreNodeModules 为 true 时生效)
|
|
235
|
+
'lodash',
|
|
236
|
+
'axios'
|
|
237
|
+
]
|
|
166
238
|
}
|
|
167
|
-
...
|
|
168
239
|
}
|
|
169
240
|
```
|
|
170
241
|
|
|
171
|
-
|
|
172
|
-
|
|
242
|
+
#### 7. TypeScript 配置
|
|
243
|
+
|
|
244
|
+
```javascript
|
|
173
245
|
module.exports = {
|
|
174
|
-
...
|
|
175
246
|
webpack: {
|
|
176
|
-
createDeclaration: true,
|
|
177
|
-
projectDir: ['./src']
|
|
247
|
+
createDeclaration: true, // 是否生成 TypeScript 声明文件
|
|
248
|
+
projectDir: ['./src'] // 可配置多个目录,用于提升工程执行效率
|
|
178
249
|
}
|
|
179
|
-
...
|
|
180
250
|
}
|
|
181
251
|
```
|
|
182
252
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
253
|
+
#### 8. 环境变量替换
|
|
254
|
+
|
|
255
|
+
基于 [params-replace-loader](https://www.npmjs.com/package/params-replace-loader) 实现环境变量批量替换:
|
|
256
|
+
|
|
257
|
+
> 详情参考 [params-replace-loader 使用文档](https://www.npmjs.com/package/params-replace-loader)
|
|
258
|
+
|
|
259
|
+
```javascript
|
|
186
260
|
module.exports = {
|
|
187
|
-
...
|
|
188
261
|
envParams: {
|
|
189
|
-
common: {
|
|
190
|
-
'#version#': '20200810.1'
|
|
262
|
+
common: { // 通用参数
|
|
263
|
+
'#version#': '20200810.1'
|
|
191
264
|
},
|
|
192
|
-
local: {
|
|
193
|
-
'#dataApiBase#': 'http://localhost:1024',
|
|
265
|
+
local: { // 本地开发环境
|
|
266
|
+
'#dataApiBase#': 'http://localhost:1024', // 数据接口根地址
|
|
194
267
|
'#assetsPublicPath#': 'http://localhost:1024', // 静态资源根地址
|
|
195
|
-
'#routeBasePath#': '/'
|
|
196
|
-
}
|
|
268
|
+
'#routeBasePath#': '/' // 路由根地址
|
|
269
|
+
}
|
|
197
270
|
}
|
|
198
|
-
...
|
|
199
271
|
}
|
|
200
272
|
```
|
|
201
273
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
274
|
+
---
|
|
275
|
+
|
|
276
|
+
### 开发配置
|
|
277
|
+
|
|
278
|
+
#### 开发服务器配置
|
|
279
|
+
|
|
280
|
+
配置开发服务器的端口、代理、资源路径等:
|
|
281
|
+
|
|
282
|
+
> 关于 proxyTable 的配置方法,参考 [Webpack DevServer Proxy 文档](https://www.webpackjs.com/configuration/dev-server/#devserver-proxy)
|
|
283
|
+
|
|
284
|
+
```javascript
|
|
205
285
|
module.exports = {
|
|
206
|
-
...
|
|
207
286
|
dev: {
|
|
208
|
-
NODE_ENV: 'development',
|
|
209
|
-
port: 80,
|
|
210
|
-
autoOpenBrowser: true,
|
|
211
|
-
assetsPublicPath: '/',
|
|
212
|
-
assetsSubDirectory: '',
|
|
213
|
-
hostname: 'localhost',
|
|
214
|
-
proxyTable: {
|
|
287
|
+
NODE_ENV: 'development', // development 模式,不会启动 UglifyJsPlugin
|
|
288
|
+
port: 80, // 启动 server 服务的端口
|
|
289
|
+
autoOpenBrowser: true, // 是否自动打开页面
|
|
290
|
+
assetsPublicPath: '/', // 设置静态资源的引用路径(根域名+路径)
|
|
291
|
+
assetsSubDirectory: '', // 资源引用二级路径
|
|
292
|
+
hostname: 'localhost', // 自动打开的页面主机
|
|
293
|
+
proxyTable: { // 接口代理配置
|
|
215
294
|
'/apiTest': {
|
|
216
|
-
target: 'http://api-test.com.cn',
|
|
217
|
-
ws: true,
|
|
218
|
-
changeOrigin: true
|
|
295
|
+
target: 'http://api-test.com.cn', // 不支持跨域的接口根地址
|
|
296
|
+
ws: true, // 启用 WebSocket
|
|
297
|
+
changeOrigin: true // 改变请求头中的 origin
|
|
219
298
|
}
|
|
220
299
|
},
|
|
221
|
-
cssSourceMap: false,
|
|
222
|
-
|
|
223
|
-
|
|
300
|
+
cssSourceMap: false, // CSS Source Map
|
|
301
|
+
https: false // 是否启用 HTTPS(见下方 HTTPS 配置说明)
|
|
302
|
+
}
|
|
224
303
|
}
|
|
225
304
|
```
|
|
226
305
|
|
|
227
|
-
|
|
228
|
-
|
|
306
|
+
#### 本地 HTTPS
|
|
307
|
+
|
|
308
|
+
启用本地 HTTPS 开发服务:
|
|
309
|
+
|
|
310
|
+
> 使用 `https://localhost/index.html` 访问当前项目
|
|
311
|
+
|
|
312
|
+
```javascript
|
|
313
|
+
module.exports = {
|
|
314
|
+
dev: {
|
|
315
|
+
https: true // 默认不开启
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
**注意事项**: akfun 使用自签名证书开启 HTTPS 服务,浏览器会提示安全性问题。需要进行如下设置:
|
|
321
|
+
|
|
322
|
+
- **Chrome**: 浏览器打开 `chrome://flags/#allow-insecure-localhost` 后将其设置为 `Enabled`
|
|
323
|
+
- **其他浏览器**: 类似设置允许本地不安全的 localhost 连接
|
|
324
|
+
|
|
325
|
+
---
|
|
326
|
+
|
|
327
|
+
### 构建配置
|
|
328
|
+
|
|
329
|
+
#### 生产环境构建
|
|
330
|
+
|
|
331
|
+
配置生产构建的输出路径、资源路径、压缩优化等:
|
|
332
|
+
|
|
333
|
+
```javascript
|
|
229
334
|
module.exports = {
|
|
230
|
-
...
|
|
231
335
|
build: {
|
|
232
|
-
NODE_ENV: 'production',
|
|
233
|
-
assetsRoot: resolve('./dist'),
|
|
234
|
-
assetsPublicPath: '/',
|
|
235
|
-
assetsSubDirectory: '',
|
|
236
|
-
productionSourceMap: false,
|
|
237
|
-
productionGzip: false,
|
|
238
|
-
productionGzipExtensions: ['js', 'css', 'json'],
|
|
239
|
-
bundleAnalyzerReport: false
|
|
336
|
+
NODE_ENV: 'production', // production 模式,会启动 UglifyJsPlugin
|
|
337
|
+
assetsRoot: resolve('./dist'), // 打包后的文件绝对路径(物理路径)
|
|
338
|
+
assetsPublicPath: '/', // 设置静态资源的引用路径(根域名+路径)
|
|
339
|
+
assetsSubDirectory: '', // 资源引用二级路径
|
|
340
|
+
productionSourceMap: false, // 是否生成 Source Map
|
|
341
|
+
productionGzip: false, // 是否开启 Gzip 压缩
|
|
342
|
+
productionGzipExtensions: ['js', 'css', 'json'], // Gzip 识别的文件后缀
|
|
343
|
+
bundleAnalyzerReport: false // 是否开启打包分析功能
|
|
240
344
|
}
|
|
241
|
-
...
|
|
242
345
|
}
|
|
243
346
|
```
|
|
244
347
|
|
|
245
|
-
|
|
246
|
-
|
|
348
|
+
#### 库构建(UMD)
|
|
349
|
+
|
|
350
|
+
构建 UMD 格式的库,适用于通过 `<script>` 标签或 CommonJS/AMD 方式引入:
|
|
351
|
+
|
|
352
|
+
```javascript
|
|
247
353
|
module.exports = {
|
|
248
|
-
...
|
|
249
354
|
build2lib: {
|
|
250
|
-
NODE_ENV: 'production',
|
|
251
|
-
libraryName: '',
|
|
252
|
-
assetsRoot: resolve('dist'),
|
|
253
|
-
assetsPublicPath: '/',
|
|
254
|
-
assetsSubDirectory: '',
|
|
255
|
-
productionSourceMap: false,
|
|
256
|
-
productionGzip: false,
|
|
257
|
-
productionGzipExtensions: ['js', 'css', 'json'],
|
|
258
|
-
bundleAnalyzerReport: false
|
|
259
|
-
}
|
|
260
|
-
...
|
|
355
|
+
NODE_ENV: 'production', // production 模式
|
|
356
|
+
libraryName: 'MyLibrary', // 构建第三方功能包时最后导出的引用变量名
|
|
357
|
+
assetsRoot: resolve('dist'), // 编译完成的文件存放路径
|
|
358
|
+
assetsPublicPath: '/', // 设置静态资源的引用路径
|
|
359
|
+
assetsSubDirectory: '', // 资源引用二级路径
|
|
360
|
+
productionSourceMap: false, // 是否生成 Source Map
|
|
361
|
+
productionGzip: false, // 是否开启 Gzip 压缩
|
|
362
|
+
productionGzipExtensions: ['js', 'css', 'json'], // Gzip 识别的文件后缀
|
|
363
|
+
bundleAnalyzerReport: false // 是否开启打包分析功能
|
|
364
|
+
}
|
|
261
365
|
}
|
|
262
366
|
```
|
|
263
367
|
|
|
264
|
-
|
|
265
|
-
|
|
368
|
+
#### 库构建(ESM)
|
|
369
|
+
|
|
370
|
+
构建 ESM 格式的库,适用于现代模块系统:
|
|
371
|
+
|
|
372
|
+
```javascript
|
|
266
373
|
module.exports = {
|
|
267
|
-
...
|
|
268
374
|
build2esm: {
|
|
269
|
-
input: resolve('src/main.js'),
|
|
270
|
-
fileName: 'index',
|
|
271
|
-
svgDir: 'src/icons/**'
|
|
272
|
-
}
|
|
273
|
-
...
|
|
375
|
+
input: resolve('src/main.js'), // 入口文件
|
|
376
|
+
fileName: 'index', // 输出的文件名称
|
|
377
|
+
svgDir: 'src/icons/**' // 用于设置当前项目的 icon 所在目录,避免被 @rollup/plugin-image 编译成 base64 格式
|
|
378
|
+
}
|
|
274
379
|
}
|
|
275
380
|
```
|
|
276
381
|
|
|
277
|
-
|
|
278
|
-
|
|
382
|
+
---
|
|
383
|
+
|
|
384
|
+
### 高级配置
|
|
385
|
+
|
|
386
|
+
#### 自定义 Loader / Plugin / Babel Plugins
|
|
387
|
+
|
|
388
|
+
扩展 Webpack 的 Loader、Plugin 和 Babel 插件:
|
|
389
|
+
|
|
390
|
+
```javascript
|
|
279
391
|
module.exports = {
|
|
280
392
|
webpack: {
|
|
281
|
-
moduleRules: [],
|
|
282
|
-
plugins: [],
|
|
283
|
-
babelPlugins: [
|
|
393
|
+
moduleRules: [], // 用于添加自定义 loaders
|
|
394
|
+
plugins: [], // 用于添加自定义 plugins
|
|
395
|
+
babelPlugins: [ // 用于添加自定义 Babel plugins
|
|
284
396
|
[
|
|
285
397
|
'component',
|
|
286
|
-
{
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
398
|
+
{
|
|
399
|
+
libraryName: 'element-ui',
|
|
400
|
+
styleLibraryName: 'theme-chalk'
|
|
401
|
+
}
|
|
402
|
+
]
|
|
403
|
+
]
|
|
404
|
+
}
|
|
290
405
|
}
|
|
291
406
|
```
|
|
292
|
-
备注: 以上自定义 babelPlugins 用于实现 [element-ui 组件按需引入](https://element.eleme.cn/#/zh-CN/component/quickstart#an-xu-yin-ru)。
|
|
293
407
|
|
|
294
|
-
|
|
295
|
-
|
|
408
|
+
**示例**: 以上自定义 `babelPlugins` 用于实现 [element-ui 组件按需引入](https://element.eleme.cn/#/zh-CN/component/quickstart#an-xu-yin-ru)
|
|
409
|
+
|
|
410
|
+
**函数形式**: 也支持以函数形式动态调整内置 Babel Plugins:
|
|
411
|
+
|
|
412
|
+
```javascript
|
|
296
413
|
module.exports = {
|
|
297
414
|
webpack: {
|
|
298
415
|
babelPlugins: (curBabelPlugins) => {
|
|
299
416
|
curBabelPlugins.push(/* your plugin */)
|
|
300
417
|
return curBabelPlugins
|
|
301
|
-
}
|
|
302
|
-
}
|
|
418
|
+
}
|
|
419
|
+
}
|
|
303
420
|
}
|
|
304
421
|
```
|
|
305
422
|
|
|
306
|
-
|
|
307
|
-
|
|
423
|
+
#### 自定义 CSS Loader / PostCSS Loader
|
|
424
|
+
|
|
425
|
+
自定义 CSS 和 PostCSS 的处理配置:
|
|
426
|
+
|
|
427
|
+
```javascript
|
|
308
428
|
module.exports = {
|
|
309
|
-
...
|
|
310
429
|
webpack: {
|
|
311
430
|
cssLoaderOption: {
|
|
312
|
-
import: false
|
|
431
|
+
import: false // 启用/禁用 @import 解析
|
|
313
432
|
},
|
|
314
|
-
postCssLoaderOption: {
|
|
433
|
+
postCssLoaderOption: { // 自定义 postcss-loader 的配置
|
|
315
434
|
postcssOptions: {
|
|
316
435
|
plugins: [
|
|
317
|
-
require('postcss-pxtorem')({
|
|
318
|
-
rootValue: 16,
|
|
319
|
-
propList: ['*']
|
|
320
|
-
})
|
|
321
|
-
]
|
|
436
|
+
require('postcss-pxtorem')({ // 用于将 px 自动转化为 rem
|
|
437
|
+
rootValue: 16, // 1rem 等于 16px
|
|
438
|
+
propList: ['*'] // 所有属性都转换
|
|
439
|
+
})
|
|
440
|
+
]
|
|
322
441
|
}
|
|
323
442
|
}
|
|
324
443
|
}
|
|
325
|
-
...
|
|
326
444
|
}
|
|
327
445
|
```
|
|
328
446
|
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
447
|
+
---
|
|
448
|
+
|
|
449
|
+
## 其他说明
|
|
450
|
+
|
|
451
|
+
### 多页面与模板
|
|
452
|
+
|
|
453
|
+
- **自动扫描入口**: 当 `entry` 仅配置一个且对应文件不存在时,会自动从 `src/pages` 扫描以 `.ts/.tsx/.js/.jsx` 结尾的文件作为入口,匹配同名 HTML 作为模板(对应正则 `/\.[tj]sx?$/`)
|
|
454
|
+
|
|
455
|
+
- **模板使用范围**: 仅 `dev` 和 `build` 使用页面模板;`build2lib` 不向页面注入打包产物
|
|
456
|
+
|
|
457
|
+
- **模板优先级**:
|
|
458
|
+
1. 优先使用 `./src/index.html`
|
|
459
|
+
2. 不存在时使用内置默认模板
|
|
460
|
+
3. 多页面时,若 `pages` 下存在同名 HTML,将其作为页面模板
|
|
461
|
+
|
|
462
|
+
---
|
|
463
|
+
|
|
464
|
+
## 相关链接
|
|
465
|
+
|
|
466
|
+
- [Webpack 官方文档](https://webpack.js.org/)
|
|
467
|
+
- [Rollup 官方文档](https://rollupjs.org/)
|
|
468
|
+
- [params-replace-loader](https://www.npmjs.com/package/params-replace-loader)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "akfun",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "6.0.0",
|
|
4
4
|
"description": "前端脚手架:支持Vue技术栈和react技术栈",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"前端工程",
|
|
@@ -62,21 +62,21 @@
|
|
|
62
62
|
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
|
|
63
63
|
"@babel/plugin-syntax-import-meta": "^7.10.4",
|
|
64
64
|
"@babel/plugin-transform-runtime": "^7.27.1",
|
|
65
|
-
"@babel/polyfill": "^7.10.1",
|
|
66
65
|
"@babel/runtime": "^7.27.1",
|
|
67
66
|
"@babel/preset-env": "^7.16.11",
|
|
68
67
|
"@babel/preset-react": "^7.16.7",
|
|
69
68
|
"@babel/preset-typescript": "^7.16.7",
|
|
70
69
|
"@babel/register": "^7.17.0",
|
|
71
70
|
"@mapbox/stylelint-processor-arbitrary-tags": "^0.4.0",
|
|
72
|
-
"@rollup/plugin-alias": "^
|
|
73
|
-
"@rollup/plugin-babel": "^
|
|
74
|
-
"@rollup/plugin-commonjs": "^
|
|
75
|
-
"@rollup/plugin-image": "^
|
|
71
|
+
"@rollup/plugin-alias": "^6.0.0",
|
|
72
|
+
"@rollup/plugin-babel": "^6.1.0",
|
|
73
|
+
"@rollup/plugin-commonjs": "^29.0.0",
|
|
74
|
+
"@rollup/plugin-image": "^3.0.3",
|
|
76
75
|
"@svgr/rollup": "^8.1.0",
|
|
77
|
-
"@rollup/plugin-json": "^
|
|
78
|
-
"@rollup/plugin-node-resolve": "^
|
|
79
|
-
"@rollup/plugin-typescript": "^
|
|
76
|
+
"@rollup/plugin-json": "^6.1.0",
|
|
77
|
+
"@rollup/plugin-node-resolve": "^16.0.3",
|
|
78
|
+
"@rollup/plugin-typescript": "^12.3.0",
|
|
79
|
+
"@rollup/plugin-terser": "^0.4.4",
|
|
80
80
|
"@svgr/webpack": "^6.2.1",
|
|
81
81
|
"@typescript-eslint/eslint-plugin": "^5.10.2",
|
|
82
82
|
"@typescript-eslint/parser": "^5.10.2",
|
|
@@ -88,6 +88,7 @@
|
|
|
88
88
|
"chalk": "^4.0.0",
|
|
89
89
|
"compression-webpack-plugin": "^9.2.0",
|
|
90
90
|
"connect-history-api-fallback": "^2.0.0",
|
|
91
|
+
"core-js": "^3.47.0",
|
|
91
92
|
"copy-webpack-plugin": "^10.2.4",
|
|
92
93
|
"css-loader": "^6.6.0",
|
|
93
94
|
"css-minimizer-webpack-plugin": "^3.4.1",
|
|
@@ -129,12 +130,11 @@
|
|
|
129
130
|
"progress-bar-webpack-plugin": "^2.1.0",
|
|
130
131
|
"qs": "^6.10.3",
|
|
131
132
|
"rimraf": "^3.0.2",
|
|
132
|
-
"rollup": "^
|
|
133
|
-
"rollup-plugin-node-externals": "^
|
|
133
|
+
"rollup": "^4.53.3",
|
|
134
|
+
"rollup-plugin-node-externals": "^8.1.2",
|
|
134
135
|
"rollup-plugin-postcss": "^4.0.2",
|
|
135
|
-
"rollup-plugin-terser": "^7.0.2",
|
|
136
136
|
"rollup-plugin-vue": "^6.0.0",
|
|
137
|
-
"sass": "^1.
|
|
137
|
+
"sass": "^1.94.2",
|
|
138
138
|
"sass-loader": "^12.4.0",
|
|
139
139
|
"less": "^4.1.3",
|
|
140
140
|
"less-loader": "^11.0.0",
|
|
@@ -175,8 +175,8 @@
|
|
|
175
175
|
"prettier": "^2.5.1"
|
|
176
176
|
},
|
|
177
177
|
"engines": {
|
|
178
|
-
"node": ">=
|
|
179
|
-
"npm": ">=
|
|
178
|
+
"node": ">= 16.0.0",
|
|
179
|
+
"npm": ">= 8.0.0"
|
|
180
180
|
},
|
|
181
181
|
"browserslist": [
|
|
182
182
|
"> 1%",
|
package/src/build2esm.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const ora = require('ora');
|
|
2
2
|
const rollup = require('rollup');
|
|
3
|
-
const { terser } = require('rollup
|
|
3
|
+
const { terser } = require('@rollup/plugin-terser'); // 压缩
|
|
4
4
|
const projectConfig = require('./config/index'); // 引入当前项目配置文件
|
|
5
5
|
const defaultConfig = require('./config/default.config');
|
|
6
6
|
const rollupConfig = require('./config/rollup.config'); // rollup的配置文件
|
|
@@ -12,18 +12,20 @@ async function build2esmFunc(options, curConfig) {
|
|
|
12
12
|
// create a bundle
|
|
13
13
|
const bundle = await rollup.rollup({
|
|
14
14
|
input: options.input,
|
|
15
|
-
external: options.externals,
|
|
15
|
+
external: options.external || options.externals, // 兼容新旧两种写法
|
|
16
16
|
plugins: options.plugins
|
|
17
17
|
});
|
|
18
18
|
|
|
19
19
|
if (isArray(options.output)) {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
});
|
|
20
|
+
// 等待所有输出完成
|
|
21
|
+
await Promise.all(options.output.map((outputItem) => bundle.write(outputItem)));
|
|
23
22
|
} else if (isObject(options.output)) {
|
|
24
23
|
// or write the bundle to disk
|
|
25
24
|
await bundle.write(options.output);
|
|
26
25
|
}
|
|
26
|
+
|
|
27
|
+
// 关闭 bundle 以释放资源
|
|
28
|
+
await bundle.close();
|
|
27
29
|
}
|
|
28
30
|
|
|
29
31
|
// 构建脚本:一般用于构建生产环境的代码
|
|
@@ -60,8 +62,8 @@ module.exports = function (fileName, akfunConfig, _consoleTag) {
|
|
|
60
62
|
externals = externals.concat(Object.keys(build2esmExternal));
|
|
61
63
|
}
|
|
62
64
|
|
|
63
|
-
// 添加到 rollup
|
|
64
|
-
curRollupConfig.
|
|
65
|
+
// 添加到 rollup 配置中(rollup 使用 external 而不是 externals)
|
|
66
|
+
curRollupConfig.external = externals;
|
|
65
67
|
|
|
66
68
|
if (build2esm && build2esm.output) {
|
|
67
69
|
curRollupConfig.output = build2esm.output;
|
|
@@ -5,6 +5,8 @@ module.exports = {
|
|
|
5
5
|
{
|
|
6
6
|
loose: true,
|
|
7
7
|
modules: false, // 是否启用将ES6模块语法转换为其他模块类型的功能,当前设置为false,以便webpack进行tree shaking。
|
|
8
|
+
useBuiltIns: 'usage', // 按需引入 polyfill,替代 @babel/polyfill
|
|
9
|
+
corejs: 3, // 使用 core-js 3.x 版本
|
|
8
10
|
targets: {
|
|
9
11
|
browsers: ['> 1%', 'last 2 versions', 'not ie <= 8']
|
|
10
12
|
}
|
package/src/config/index.js
CHANGED
|
@@ -7,7 +7,7 @@ const commonjs = require('@rollup/plugin-commonjs'); // 识别cmd模块
|
|
|
7
7
|
const vue = require('rollup-plugin-vue');
|
|
8
8
|
const json = require('@rollup/plugin-json'); // 识别json类型文件
|
|
9
9
|
const image = require('@rollup/plugin-image'); // 图片处理器
|
|
10
|
-
const { terser } = require('rollup
|
|
10
|
+
const { terser } = require('@rollup/plugin-terser'); // 压缩
|
|
11
11
|
const alias = require('@rollup/plugin-alias'); // 简写配置
|
|
12
12
|
// css相关处理器
|
|
13
13
|
const postcss = require('rollup-plugin-postcss');
|
|
@@ -57,9 +57,12 @@ module.exports = function (fileName, akfunConfig) {
|
|
|
57
57
|
input: rollupInput,
|
|
58
58
|
plugins: [
|
|
59
59
|
alias({
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
60
|
+
entries: Object.entries(curConfig.webpack.resolve.alias || {}).map(
|
|
61
|
+
([find, replacement]) => ({
|
|
62
|
+
find,
|
|
63
|
+
replacement
|
|
64
|
+
})
|
|
65
|
+
)
|
|
63
66
|
}),
|
|
64
67
|
/**
|
|
65
68
|
* excludeList(在akfun.config.js中配置)
|
|
@@ -72,6 +75,12 @@ module.exports = function (fileName, akfunConfig) {
|
|
|
72
75
|
// devDeps: false, // 不标记 devDependencies
|
|
73
76
|
// peerDeps: true, // 标记 peerDependencies
|
|
74
77
|
}),
|
|
78
|
+
/**
|
|
79
|
+
* nodeResolve 插件用于解析模块路径
|
|
80
|
+
* extensions: 默认识别的文件后缀列表
|
|
81
|
+
* 默认值(来自 webpack.resolve.extensions): ['.js', '.jsx', '.ts', '.tsx', '.vue', '.json']
|
|
82
|
+
* 如果不配置此插件,Rollup 默认只识别 .js 和 .mjs 文件
|
|
83
|
+
*/
|
|
75
84
|
nodeResolve({
|
|
76
85
|
extensions: curConfig.webpack.resolve.extensions
|
|
77
86
|
}),
|
|
@@ -55,18 +55,20 @@
|
|
|
55
55
|
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
|
|
56
56
|
"@babel/plugin-syntax-import-meta": "^7.10.4",
|
|
57
57
|
"@babel/plugin-transform-runtime": "^7.17.0",
|
|
58
|
-
"@babel/polyfill": "^7.10.1",
|
|
59
58
|
"@babel/preset-env": "^7.16.11",
|
|
60
59
|
"@babel/preset-react": "^7.16.7",
|
|
61
60
|
"@babel/preset-typescript": "^7.16.7",
|
|
62
61
|
"@babel/register": "^7.17.0",
|
|
63
62
|
"@mapbox/stylelint-processor-arbitrary-tags": "^0.4.0",
|
|
64
|
-
"@rollup/plugin-alias": "^
|
|
65
|
-
"@rollup/plugin-babel": "^
|
|
66
|
-
"@rollup/plugin-commonjs": "^
|
|
67
|
-
"@rollup/plugin-image": "^
|
|
68
|
-
"@rollup/plugin-json": "^
|
|
69
|
-
"@rollup/plugin-node-resolve": "^
|
|
63
|
+
"@rollup/plugin-alias": "^6.0.0",
|
|
64
|
+
"@rollup/plugin-babel": "^6.1.0",
|
|
65
|
+
"@rollup/plugin-commonjs": "^29.0.0",
|
|
66
|
+
"@rollup/plugin-image": "^3.0.3",
|
|
67
|
+
"@rollup/plugin-json": "^6.1.0",
|
|
68
|
+
"@rollup/plugin-node-resolve": "^16.0.3",
|
|
69
|
+
"@rollup/plugin-terser": "^0.4.4",
|
|
70
|
+
"@rollup/plugin-typescript": "^12.3.0",
|
|
71
|
+
"@svgr/rollup": "^8.1.0",
|
|
70
72
|
"@typescript-eslint/eslint-plugin": "^5.10.2",
|
|
71
73
|
"@typescript-eslint/parser": "^5.10.2",
|
|
72
74
|
"@vue/compiler-sfc": "^3.2.29",
|
|
@@ -77,6 +79,7 @@
|
|
|
77
79
|
"chalk": "^4.0.0",
|
|
78
80
|
"compression-webpack-plugin": "^9.2.0",
|
|
79
81
|
"connect-history-api-fallback": "^1.6.0",
|
|
82
|
+
"core-js": "^3.47.0",
|
|
80
83
|
"copy-webpack-plugin": "^10.2.4",
|
|
81
84
|
"css-loader": "^6.6.0",
|
|
82
85
|
"cssnano": "^5.0.16",
|
|
@@ -104,7 +107,7 @@
|
|
|
104
107
|
"http-proxy-middleware": "^2.0.2",
|
|
105
108
|
"inquirer": "^8.2.0",
|
|
106
109
|
"mini-css-extract-plugin": "^2.5.3",
|
|
107
|
-
"sass": "^1.
|
|
110
|
+
"sass": "^1.94.2",
|
|
108
111
|
"open": "^8.4.0",
|
|
109
112
|
"ora": "^4.0.4",
|
|
110
113
|
"params-replace-loader": "^1.1.6",
|
|
@@ -116,9 +119,10 @@
|
|
|
116
119
|
"progress-bar-webpack-plugin": "^2.1.0",
|
|
117
120
|
"qs": "^6.10.3",
|
|
118
121
|
"rimraf": "^3.0.2",
|
|
119
|
-
"rollup": "^
|
|
122
|
+
"rollup": "^4.53.3",
|
|
123
|
+
"rollup-plugin-jsx": "^1.0.3",
|
|
124
|
+
"rollup-plugin-node-externals": "^8.1.2",
|
|
120
125
|
"rollup-plugin-postcss": "^4.0.2",
|
|
121
|
-
"rollup-plugin-terser": "^7.0.2",
|
|
122
126
|
"rollup-plugin-vue": "^6.0.0",
|
|
123
127
|
"sass-loader": "^12.4.0",
|
|
124
128
|
"sass-resources-loader": "^2.2.4",
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
module.
|
|
1
|
+
module.exports = {
|
|
2
2
|
presets: [
|
|
3
3
|
[
|
|
4
4
|
'@babel/preset-env',
|
|
5
5
|
{
|
|
6
6
|
loose: false,
|
|
7
7
|
modules: false,
|
|
8
|
+
useBuiltIns: 'usage', // 按需引入 polyfill,替代 @babel/polyfill
|
|
9
|
+
corejs: 3, // 使用 core-js 3.x 版本
|
|
8
10
|
targets: {
|
|
9
11
|
browsers: ['> 1%', 'last 2 versions', 'not ie <= 8']
|
|
10
12
|
}
|
|
@@ -189,20 +189,20 @@ class ConfigManager {
|
|
|
189
189
|
const config = this.mergedConfig;
|
|
190
190
|
|
|
191
191
|
// 验证必需的配置项
|
|
192
|
-
if (
|
|
193
|
-
throw new Error('dev
|
|
192
|
+
if (config.dev && typeof config.dev !== 'object') {
|
|
193
|
+
throw new Error('dev 配置格式错误');
|
|
194
194
|
}
|
|
195
195
|
|
|
196
|
-
if (
|
|
197
|
-
throw new Error('build
|
|
196
|
+
if (config.build && typeof config.build !== 'object') {
|
|
197
|
+
throw new Error('build 配置格式错误');
|
|
198
198
|
}
|
|
199
199
|
|
|
200
|
-
if (
|
|
201
|
-
throw new Error('webpack
|
|
200
|
+
if (config.webpack && typeof config.webpack !== 'object') {
|
|
201
|
+
throw new Error('webpack 配置格式错误');
|
|
202
202
|
}
|
|
203
203
|
|
|
204
204
|
// 验证端口号
|
|
205
|
-
if (config.dev.port) {
|
|
205
|
+
if (config.dev && config.dev.port) {
|
|
206
206
|
const port = parseInt(config.dev.port, 10);
|
|
207
207
|
if (isNaN(port) || port < 1 || port > 65535) {
|
|
208
208
|
throw new Error('dev.port 必须是 1-65535 之间的数字');
|
|
@@ -210,7 +210,7 @@ class ConfigManager {
|
|
|
210
210
|
}
|
|
211
211
|
|
|
212
212
|
// 验证路径
|
|
213
|
-
if (config.build.assetsRoot) {
|
|
213
|
+
if (config.build && config.build.assetsRoot) {
|
|
214
214
|
const assetsRoot = config.build.assetsRoot;
|
|
215
215
|
if (typeof assetsRoot !== 'string') {
|
|
216
216
|
throw new Error('build.assetsRoot 必须是字符串类型的路径');
|
|
@@ -35,7 +35,7 @@ class ConfigValidator {
|
|
|
35
35
|
|
|
36
36
|
// 输出警告
|
|
37
37
|
if (this.warnings.length > 0) {
|
|
38
|
-
console.log(chalk.yellow('\n⚠️
|
|
38
|
+
console.log(chalk.yellow('\n⚠️ 配置异常提示:'));
|
|
39
39
|
this.warnings.forEach((warning) => {
|
|
40
40
|
console.log(chalk.yellow(` - ${warning}`));
|
|
41
41
|
});
|
|
@@ -81,23 +81,18 @@ class ConfigValidator {
|
|
|
81
81
|
* @private
|
|
82
82
|
*/
|
|
83
83
|
_validateWebpack(webpack) {
|
|
84
|
-
if (!webpack) {
|
|
85
|
-
this.errors.push('webpack 配置缺失');
|
|
86
|
-
return;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
84
|
// 验证 entry
|
|
90
|
-
if (webpack.entry !== undefined) {
|
|
85
|
+
if (webpack && webpack.entry !== undefined) {
|
|
91
86
|
this._validateEntry(webpack.entry);
|
|
92
87
|
}
|
|
93
88
|
|
|
94
89
|
// 验证 resolve
|
|
95
|
-
if (webpack.resolve) {
|
|
90
|
+
if (webpack && webpack.resolve) {
|
|
96
91
|
this._validateResolve(webpack.resolve);
|
|
97
92
|
}
|
|
98
93
|
|
|
99
94
|
// 验证 externals
|
|
100
|
-
if (webpack.externals !== undefined) {
|
|
95
|
+
if (webpack && webpack.externals !== undefined) {
|
|
101
96
|
const validTypes = ['object', 'string', 'function'];
|
|
102
97
|
if (!validTypes.includes(typeof webpack.externals)) {
|
|
103
98
|
this.errors.push('webpack.externals 类型不正确');
|
|
@@ -105,14 +100,14 @@ class ConfigValidator {
|
|
|
105
100
|
}
|
|
106
101
|
|
|
107
102
|
// 验证 sassResources
|
|
108
|
-
if (webpack.sassResources !== undefined) {
|
|
103
|
+
if (webpack && webpack.sassResources !== undefined) {
|
|
109
104
|
if (!Array.isArray(webpack.sassResources)) {
|
|
110
105
|
this.errors.push('webpack.sassResources 必须是数组');
|
|
111
106
|
}
|
|
112
107
|
}
|
|
113
108
|
|
|
114
109
|
// 验证 babelPlugins
|
|
115
|
-
if (webpack.babelPlugins !== undefined) {
|
|
110
|
+
if (webpack && webpack.babelPlugins !== undefined) {
|
|
116
111
|
const validTypes = ['function', 'object'];
|
|
117
112
|
const type = Array.isArray(webpack.babelPlugins) ? 'object' : typeof webpack.babelPlugins;
|
|
118
113
|
if (!validTypes.includes(type)) {
|
|
@@ -121,12 +116,12 @@ class ConfigValidator {
|
|
|
121
116
|
}
|
|
122
117
|
|
|
123
118
|
// 验证 moduleRules
|
|
124
|
-
if (webpack.moduleRules !== undefined && !Array.isArray(webpack.moduleRules)) {
|
|
119
|
+
if (webpack && webpack.moduleRules !== undefined && !Array.isArray(webpack.moduleRules)) {
|
|
125
120
|
this.errors.push('webpack.moduleRules 必须是数组');
|
|
126
121
|
}
|
|
127
122
|
|
|
128
123
|
// 验证 plugins
|
|
129
|
-
if (webpack.plugins !== undefined && !Array.isArray(webpack.plugins)) {
|
|
124
|
+
if (webpack && webpack.plugins !== undefined && !Array.isArray(webpack.plugins)) {
|
|
130
125
|
this.errors.push('webpack.plugins 必须是数组');
|
|
131
126
|
}
|
|
132
127
|
}
|
|
@@ -32,7 +32,7 @@ const BannerPack = new webpack.BannerPlugin({
|
|
|
32
32
|
* _curEnvConfig: 执行环境中的配置,用于记录 dev、build、build2lib 等对应的配置内容;
|
|
33
33
|
* _akfunConfig:完整的配置对象
|
|
34
34
|
*/
|
|
35
|
-
module.exports = (_curEnvConfig, _akfunConfig) => {
|
|
35
|
+
module.exports = (_curEnvConfig, _akfunConfig, buildMode = 'build') => {
|
|
36
36
|
const curEnvConfig = _curEnvConfig || {}; // 用于接收当前运行环境配置变量
|
|
37
37
|
let config = _akfunConfig || projectConfig; // 默认使用执行命令目录下的配置数据
|
|
38
38
|
// 获取当前项目配置文件中的webpack配置
|
|
@@ -49,7 +49,20 @@ module.exports = (_curEnvConfig, _akfunConfig) => {
|
|
|
49
49
|
curWebpackConfig.babelPlugins(babelConfig.plugins);
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
+
// 获取缓存目录路径
|
|
53
|
+
const cacheDirectory = resolveToCurrentRoot('./node_modules/.cache/webpack');
|
|
54
|
+
|
|
52
55
|
const webpackConfig = {
|
|
56
|
+
// Webpack 5 持久化缓存配置
|
|
57
|
+
cache: {
|
|
58
|
+
type: 'filesystem',
|
|
59
|
+
cacheDirectory: cacheDirectory,
|
|
60
|
+
buildDependencies: {
|
|
61
|
+
config: [__filename] // 当配置文件改变时,使缓存失效
|
|
62
|
+
},
|
|
63
|
+
name: `${curEnvConfig.NODE_ENV || 'development'}--${buildMode}-cache`,
|
|
64
|
+
compression: 'gzip' // 使用 gzip 压缩缓存文件以节省磁盘空间
|
|
65
|
+
},
|
|
53
66
|
stats: {
|
|
54
67
|
// cachedModules: false,
|
|
55
68
|
// providedExports: true,
|
|
@@ -96,7 +109,13 @@ module.exports = (_curEnvConfig, _akfunConfig) => {
|
|
|
96
109
|
use: [
|
|
97
110
|
{
|
|
98
111
|
loader: 'babel-loader',
|
|
99
|
-
options:
|
|
112
|
+
options: {
|
|
113
|
+
...babelConfig,
|
|
114
|
+
// Babel 缓存配置
|
|
115
|
+
cacheDirectory: true, // 启用缓存
|
|
116
|
+
cacheCompression: false, // 不压缩缓存文件以提升性能
|
|
117
|
+
cacheIdentifier: `${curEnvConfig.NODE_ENV || 'development'}--${buildMode}-babel`
|
|
118
|
+
}
|
|
100
119
|
},
|
|
101
120
|
{
|
|
102
121
|
loader: 'ts-loader',
|
|
@@ -105,7 +124,11 @@ module.exports = (_curEnvConfig, _akfunConfig) => {
|
|
|
105
124
|
compilerOptions: {
|
|
106
125
|
declaration: curWebpackConfig.createDeclaration || false,
|
|
107
126
|
outDir: curEnvConfig.assetsRoot || './dist'
|
|
108
|
-
}
|
|
127
|
+
},
|
|
128
|
+
// TypeScript 缓存配置
|
|
129
|
+
transpileOnly: true, // 只进行转译,不进行类型检查(提升性能)
|
|
130
|
+
experimentalWatchApi: true // 使用实验性的 watch API(提升性能)
|
|
131
|
+
// 注意:ts-loader 的缓存由 Webpack 5 的持久化缓存自动处理
|
|
109
132
|
}
|
|
110
133
|
}
|
|
111
134
|
],
|
|
@@ -117,7 +140,13 @@ module.exports = (_curEnvConfig, _akfunConfig) => {
|
|
|
117
140
|
use: [
|
|
118
141
|
{
|
|
119
142
|
loader: 'babel-loader',
|
|
120
|
-
options:
|
|
143
|
+
options: {
|
|
144
|
+
...babelConfig,
|
|
145
|
+
// Babel 缓存配置
|
|
146
|
+
cacheDirectory: true, // 启用缓存
|
|
147
|
+
cacheCompression: false, // 不压缩缓存文件以提升性能
|
|
148
|
+
cacheIdentifier: `${curEnvConfig.NODE_ENV || 'development'}--${buildMode}-babel`
|
|
149
|
+
}
|
|
121
150
|
}
|
|
122
151
|
],
|
|
123
152
|
// exclude: /node_modules/,
|
|
@@ -273,6 +302,9 @@ module.exports = (_curEnvConfig, _akfunConfig) => {
|
|
|
273
302
|
}
|
|
274
303
|
// 是否开启ESLint
|
|
275
304
|
if (config.settings.enableESLint) {
|
|
305
|
+
// ESLint 缓存目录
|
|
306
|
+
const eslintCacheLocation = resolveToCurrentRoot('./node_modules/.cache/eslint');
|
|
307
|
+
|
|
276
308
|
// ts类型
|
|
277
309
|
webpackConfig.plugins.push(
|
|
278
310
|
new ESLintPlugin({
|
|
@@ -280,7 +312,9 @@ module.exports = (_curEnvConfig, _akfunConfig) => {
|
|
|
280
312
|
extensions: ['ts', 'tsx'],
|
|
281
313
|
// include: curProjectDir, // [resolve('src')],
|
|
282
314
|
// exclude: 'node_modules',
|
|
283
|
-
cache: true,
|
|
315
|
+
cache: true, // 启用缓存
|
|
316
|
+
cacheLocation: path.join(eslintCacheLocation, '.eslintcache-ts'), // 指定缓存位置
|
|
317
|
+
cacheStrategy: 'metadata', // 使用元数据缓存策略(更快)
|
|
284
318
|
fix: config.settings.enableESLintFix || false,
|
|
285
319
|
formatter: require('eslint-friendly-formatter'),
|
|
286
320
|
overrideConfigFile: path.resolve(__dirname, '../config/.eslintrc.ts.js')
|
|
@@ -292,7 +326,9 @@ module.exports = (_curEnvConfig, _akfunConfig) => {
|
|
|
292
326
|
extensions: ['js', 'jsx'],
|
|
293
327
|
// include: curProjectDir, // [resolve('src')],
|
|
294
328
|
// exclude: 'node_modules',
|
|
295
|
-
cache: true,
|
|
329
|
+
cache: true, // 启用缓存
|
|
330
|
+
cacheLocation: path.join(eslintCacheLocation, '.eslintcache-js'), // 指定缓存位置
|
|
331
|
+
cacheStrategy: 'metadata', // 使用元数据缓存策略(更快)
|
|
296
332
|
fix: config.settings.enableESLintFix || false,
|
|
297
333
|
formatter: require('eslint-friendly-formatter'),
|
|
298
334
|
overrideConfigFile: path.resolve(__dirname, '../config/.eslintrc.js')
|
|
@@ -304,7 +340,9 @@ module.exports = (_curEnvConfig, _akfunConfig) => {
|
|
|
304
340
|
extensions: ['vue'],
|
|
305
341
|
// include: curProjectDir, // [resolve('src')],
|
|
306
342
|
// exclude: 'node_modules',
|
|
307
|
-
cache: true,
|
|
343
|
+
cache: true, // 启用缓存
|
|
344
|
+
cacheLocation: path.join(eslintCacheLocation, '.eslintcache-vue'), // 指定缓存位置
|
|
345
|
+
cacheStrategy: 'metadata', // 使用元数据缓存策略(更快)
|
|
308
346
|
fix: config.settings.enableESLintFix || false,
|
|
309
347
|
formatter: require('eslint-friendly-formatter'),
|
|
310
348
|
overrideConfigFile: path.resolve(__dirname, '../config/.eslintrc.vue.js')
|
|
@@ -313,6 +351,9 @@ module.exports = (_curEnvConfig, _akfunConfig) => {
|
|
|
313
351
|
}
|
|
314
352
|
// 是否开启StyleLint: 用于验证scss文件里面的style规范
|
|
315
353
|
if (config.settings.enableStyleLint) {
|
|
354
|
+
// StyleLint 缓存目录
|
|
355
|
+
const stylelintCacheLocation = resolveToCurrentRoot('./node_modules/.cache/stylelint');
|
|
356
|
+
|
|
316
357
|
const vuePagesObj = catchVuePages();
|
|
317
358
|
// 判断项目中是否有vue文件
|
|
318
359
|
if (vuePagesObj && Object.keys(vuePagesObj).length > 0) {
|
|
@@ -321,8 +362,8 @@ module.exports = (_curEnvConfig, _akfunConfig) => {
|
|
|
321
362
|
new StyleLintPlugin({
|
|
322
363
|
files: ['src/**/*.vue'],
|
|
323
364
|
// quiet: true,
|
|
324
|
-
cache: true,
|
|
325
|
-
cacheLocation:
|
|
365
|
+
cache: true, // 启用缓存
|
|
366
|
+
cacheLocation: path.join(stylelintCacheLocation, '.stylelintcache-vue'), // 统一缓存位置
|
|
326
367
|
fix: config.settings.enableStyleLintFix,
|
|
327
368
|
configFile: path.resolve(__dirname, '../config/.stylelintrc-vue')
|
|
328
369
|
})
|
|
@@ -333,8 +374,8 @@ module.exports = (_curEnvConfig, _akfunConfig) => {
|
|
|
333
374
|
new StyleLintPlugin({
|
|
334
375
|
files: 'src/**/*.s?(a|c)ss',
|
|
335
376
|
// quiet: true,
|
|
336
|
-
cache: true,
|
|
337
|
-
cacheLocation:
|
|
377
|
+
cache: true, // 启用缓存
|
|
378
|
+
cacheLocation: path.join(stylelintCacheLocation, '.stylelintcache-scss'), // 统一缓存位置
|
|
338
379
|
fix: config.settings.enableStyleLintFix,
|
|
339
380
|
configFile: path.resolve(__dirname, '../config/.stylelintrc')
|
|
340
381
|
})
|
|
@@ -13,7 +13,7 @@ module.exports = (akfunConfig) => {
|
|
|
13
13
|
let config = akfunConfig || projectConfig; // 默认使用执行命令目录下的配置数据
|
|
14
14
|
const curEnvConfig = config.dev || {}; // 当前执行环境配置
|
|
15
15
|
// 获取webpack基本配置
|
|
16
|
-
const baseWebpackConfig = getBaseWebpackConfig(curEnvConfig, config);
|
|
16
|
+
const baseWebpackConfig = getBaseWebpackConfig(curEnvConfig, config, 'dev');
|
|
17
17
|
|
|
18
18
|
// 获取页面模板地址
|
|
19
19
|
let curHtmlTemplate = path.resolve(__dirname, '../initData/template/index.html');
|
|
@@ -19,7 +19,7 @@ module.exports = (akfunConfig) => {
|
|
|
19
19
|
let config = akfunConfig || projectConfig; // 默认使用执行命令目录下的配置数据
|
|
20
20
|
const curEnvConfig = config.build2lib || {}; // 当前执行环境配置
|
|
21
21
|
// 获取webpack基本配置
|
|
22
|
-
const baseWebpackConfig = getBaseWebpackConfig(curEnvConfig, config);
|
|
22
|
+
const baseWebpackConfig = getBaseWebpackConfig(curEnvConfig, config, 'build2lib');
|
|
23
23
|
|
|
24
24
|
let curTarget = ['web', 'es5'];
|
|
25
25
|
if (config.webpack.target) {
|
|
@@ -24,7 +24,7 @@ module.exports = (akfunConfig) => {
|
|
|
24
24
|
let config = akfunConfig || projectConfig; // 默认使用执行命令目录下的配置数据
|
|
25
25
|
const curEnvConfig = config.build || {}; // 当前执行环境配置
|
|
26
26
|
// 获取webpack基本配置
|
|
27
|
-
const baseWebpackConfig = getBaseWebpackConfig(curEnvConfig, config);
|
|
27
|
+
const baseWebpackConfig = getBaseWebpackConfig(curEnvConfig, config, 'build');
|
|
28
28
|
// 获取页面模板地址
|
|
29
29
|
let curHtmlTemplate = path.resolve(__dirname, '../initData/template/index.html');
|
|
30
30
|
if (config.webpack.template) {
|