akfun 5.2.11 → 5.2.13
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
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# AKFun 前端脚手架
|
|
2
2
|
|
|
3
|
-
AKFun 是一个基于 Webpack 与 Rollup 的多场景前端打包工具,支持 Vue、React、React+TS 技术栈,致力于提供"零配置、开箱即用"
|
|
3
|
+
AKFun 是一个基于 Webpack 与 Rollup 的多场景前端打包工具,支持 Vue、React、React+TS 技术栈,致力于提供"零配置、开箱即用"的前端工程能力,让开发者专注于业务开发。
|
|
4
4
|
|
|
5
5
|
## 目录
|
|
6
6
|
|
|
@@ -20,10 +20,10 @@ AKFun 是一个基于 Webpack 与 Rollup 的多场景前端打包工具,支持
|
|
|
20
20
|
|
|
21
21
|
## 主要特性
|
|
22
22
|
|
|
23
|
-
- **零配置**:
|
|
24
|
-
-
|
|
25
|
-
-
|
|
26
|
-
- **灵活可配**:
|
|
23
|
+
- **零配置**: 内置默认配置(前端工程最佳实践),开箱可用
|
|
24
|
+
- **多技术体系支持**: 支持 Vue、React、React+TS 的调试与构建
|
|
25
|
+
- **多种构建类型**: 本地开发(含热更新/代理)、生产构建、库构建(UMD/ESM)、Node 模块构建
|
|
26
|
+
- **灵活可配**: 支持入口、别名、代理、公共样式注入、ESLint/StyleLint、Babel/Loader/Plugin 扩展等配置
|
|
27
27
|
- **样式与规范**: 集成 Autoprefixer、Sass、PostCSS、ESLint、StyleLint
|
|
28
28
|
- **参数替换**: 支持基于 [params-replace-loader](https://www.npmjs.com/package/params-replace-loader) 的环境变量批量替换
|
|
29
29
|
- **模板支持**: 提供完整的 Vue/React 项目模板
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "akfun",
|
|
3
|
-
"version": "5.2.
|
|
3
|
+
"version": "5.2.13",
|
|
4
4
|
"description": "前端脚手架:支持Vue技术栈和react技术栈",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"前端工程",
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"author": "wibetter",
|
|
14
14
|
"license": "MIT",
|
|
15
15
|
"bin": {
|
|
16
|
-
"akfun": "
|
|
16
|
+
"akfun": "bin/akfun.js"
|
|
17
17
|
},
|
|
18
18
|
"main": "module/main.js",
|
|
19
19
|
"scripts": {
|
|
@@ -5,8 +5,26 @@
|
|
|
5
5
|
* - 在构建 React 组件时,自动为组件的根元素添加 data-scope 属性
|
|
6
6
|
* - 支持函数组件和类组件
|
|
7
7
|
* - 如果组件返回 Fragment 或数组,会在 Fragment 的第一个子元素或数组的第一个元素上添加
|
|
8
|
+
* - data-scope 的值默认为当前组件所在文件目录的名称
|
|
8
9
|
*/
|
|
10
|
+
const path = require('path');
|
|
11
|
+
|
|
9
12
|
module.exports = function ({ types: t }) {
|
|
13
|
+
/**
|
|
14
|
+
* 获取文件所在目录的名称
|
|
15
|
+
*/
|
|
16
|
+
function getDirectoryName(filePath) {
|
|
17
|
+
if (!filePath) {
|
|
18
|
+
return '';
|
|
19
|
+
}
|
|
20
|
+
try {
|
|
21
|
+
const dirPath = path.dirname(filePath);
|
|
22
|
+
const dirName = path.basename(dirPath);
|
|
23
|
+
return dirName || '';
|
|
24
|
+
} catch (e) {
|
|
25
|
+
return '';
|
|
26
|
+
}
|
|
27
|
+
}
|
|
10
28
|
/**
|
|
11
29
|
* 检查函数是否返回 JSX(用于判断是否是 React 组件)
|
|
12
30
|
*/
|
|
@@ -39,8 +57,10 @@ module.exports = function ({ types: t }) {
|
|
|
39
57
|
|
|
40
58
|
/**
|
|
41
59
|
* 在 JSX 元素上添加 data-scope 属性
|
|
60
|
+
* @param {Object} jsxElement - JSX 元素节点
|
|
61
|
+
* @param {string} scopeValue - data-scope 的值,默认为空字符串
|
|
42
62
|
*/
|
|
43
|
-
function addDataScopeAttribute(jsxElement) {
|
|
63
|
+
function addDataScopeAttribute(jsxElement, scopeValue = '') {
|
|
44
64
|
const openingElement = jsxElement.openingElement;
|
|
45
65
|
const attributes = openingElement.attributes;
|
|
46
66
|
|
|
@@ -50,8 +70,11 @@ module.exports = function ({ types: t }) {
|
|
|
50
70
|
);
|
|
51
71
|
|
|
52
72
|
if (!hasDataScope) {
|
|
53
|
-
// 创建 data-scope
|
|
54
|
-
const dataScopeAttr = t.jsxAttribute(
|
|
73
|
+
// 创建 data-scope 属性,值为目录名
|
|
74
|
+
const dataScopeAttr = t.jsxAttribute(
|
|
75
|
+
t.jsxIdentifier('data-scope'),
|
|
76
|
+
t.stringLiteral(scopeValue)
|
|
77
|
+
);
|
|
55
78
|
// 添加到属性列表的开头
|
|
56
79
|
attributes.unshift(dataScopeAttr);
|
|
57
80
|
}
|
|
@@ -59,8 +82,10 @@ module.exports = function ({ types: t }) {
|
|
|
59
82
|
|
|
60
83
|
/**
|
|
61
84
|
* 处理返回语句中的 JSX
|
|
85
|
+
* @param {Object} path - Babel path 对象
|
|
86
|
+
* @param {string} scopeValue - data-scope 的值
|
|
62
87
|
*/
|
|
63
|
-
function processReturnStatement(path) {
|
|
88
|
+
function processReturnStatement(path, scopeValue) {
|
|
64
89
|
const argument = path.get('argument');
|
|
65
90
|
|
|
66
91
|
if (!argument.node) {
|
|
@@ -69,7 +94,7 @@ module.exports = function ({ types: t }) {
|
|
|
69
94
|
|
|
70
95
|
// 处理 JSX 元素
|
|
71
96
|
if (argument.isJSXElement()) {
|
|
72
|
-
addDataScopeAttribute(argument.node);
|
|
97
|
+
addDataScopeAttribute(argument.node, scopeValue);
|
|
73
98
|
return;
|
|
74
99
|
}
|
|
75
100
|
|
|
@@ -79,12 +104,12 @@ module.exports = function ({ types: t }) {
|
|
|
79
104
|
// 找到第一个 JSX 元素子节点
|
|
80
105
|
for (const child of children) {
|
|
81
106
|
if (child.isJSXElement()) {
|
|
82
|
-
addDataScopeAttribute(child.node);
|
|
107
|
+
addDataScopeAttribute(child.node, scopeValue);
|
|
83
108
|
return;
|
|
84
109
|
}
|
|
85
110
|
// 如果子节点是 Fragment,递归处理
|
|
86
111
|
if (child.isJSXFragment()) {
|
|
87
|
-
processReturnStatement(child);
|
|
112
|
+
processReturnStatement(child, scopeValue);
|
|
88
113
|
return;
|
|
89
114
|
}
|
|
90
115
|
}
|
|
@@ -96,7 +121,12 @@ module.exports = function ({ types: t }) {
|
|
|
96
121
|
// 找到第一个 JSX 元素
|
|
97
122
|
for (const element of elements) {
|
|
98
123
|
if (element.isJSXElement()) {
|
|
99
|
-
addDataScopeAttribute(element.node);
|
|
124
|
+
addDataScopeAttribute(element.node, scopeValue);
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
// 如果元素是 Fragment,递归处理
|
|
128
|
+
if (element.isJSXFragment()) {
|
|
129
|
+
processReturnStatement(element, scopeValue);
|
|
100
130
|
return;
|
|
101
131
|
}
|
|
102
132
|
}
|
|
@@ -107,27 +137,37 @@ module.exports = function ({ types: t }) {
|
|
|
107
137
|
// 处理 true 分支
|
|
108
138
|
const consequent = argument.get('consequent');
|
|
109
139
|
if (consequent.isJSXElement()) {
|
|
110
|
-
addDataScopeAttribute(consequent.node);
|
|
140
|
+
addDataScopeAttribute(consequent.node, scopeValue);
|
|
111
141
|
} else if (consequent.isJSXFragment() || consequent.isArrayExpression()) {
|
|
112
|
-
processReturnStatement(consequent);
|
|
142
|
+
processReturnStatement(consequent, scopeValue);
|
|
113
143
|
}
|
|
114
144
|
|
|
115
145
|
// 处理 false 分支
|
|
116
146
|
const alternate = argument.get('alternate');
|
|
117
147
|
if (alternate.isJSXElement()) {
|
|
118
|
-
addDataScopeAttribute(alternate.node);
|
|
148
|
+
addDataScopeAttribute(alternate.node, scopeValue);
|
|
119
149
|
} else if (alternate.isJSXFragment() || alternate.isArrayExpression()) {
|
|
120
|
-
processReturnStatement(alternate);
|
|
150
|
+
processReturnStatement(alternate, scopeValue);
|
|
121
151
|
}
|
|
122
152
|
}
|
|
123
153
|
|
|
124
154
|
// 处理逻辑表达式(&& 或 ||)
|
|
125
155
|
if (argument.isLogicalExpression()) {
|
|
156
|
+
const left = argument.get('left');
|
|
126
157
|
const right = argument.get('right');
|
|
158
|
+
|
|
159
|
+
// 处理左侧(可能是 JSX)
|
|
160
|
+
if (left.isJSXElement()) {
|
|
161
|
+
addDataScopeAttribute(left.node, scopeValue);
|
|
162
|
+
} else if (left.isJSXFragment() || left.isArrayExpression()) {
|
|
163
|
+
processReturnStatement(left, scopeValue);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// 处理右侧(可能是 JSX)
|
|
127
167
|
if (right.isJSXElement()) {
|
|
128
|
-
addDataScopeAttribute(right.node);
|
|
168
|
+
addDataScopeAttribute(right.node, scopeValue);
|
|
129
169
|
} else if (right.isJSXFragment() || right.isArrayExpression()) {
|
|
130
|
-
processReturnStatement(right);
|
|
170
|
+
processReturnStatement(right, scopeValue);
|
|
131
171
|
}
|
|
132
172
|
}
|
|
133
173
|
}
|
|
@@ -135,30 +175,39 @@ module.exports = function ({ types: t }) {
|
|
|
135
175
|
return {
|
|
136
176
|
visitor: {
|
|
137
177
|
// 处理函数组件和箭头函数组件
|
|
138
|
-
Function(
|
|
178
|
+
Function(functionPath) {
|
|
139
179
|
// 只处理返回 JSX 的函数(即 React 组件)
|
|
140
|
-
if (!returnsJSX(
|
|
180
|
+
if (!returnsJSX(functionPath)) {
|
|
141
181
|
return;
|
|
142
182
|
}
|
|
143
183
|
|
|
144
|
-
|
|
184
|
+
// 获取当前文件路径并提取目录名
|
|
185
|
+
const filePath = functionPath.hub?.file?.opts?.filename || '';
|
|
186
|
+
const scopeValue = getDirectoryName(filePath);
|
|
187
|
+
|
|
188
|
+
const body = functionPath.get('body');
|
|
145
189
|
|
|
146
190
|
// 处理函数体中的返回语句
|
|
147
191
|
if (body.isBlockStatement()) {
|
|
148
192
|
body.traverse({
|
|
149
193
|
ReturnStatement(returnPath) {
|
|
150
|
-
processReturnStatement(returnPath);
|
|
194
|
+
processReturnStatement(returnPath, scopeValue);
|
|
151
195
|
}
|
|
152
196
|
});
|
|
153
197
|
} else if (body.isJSXElement()) {
|
|
154
198
|
// 箭头函数直接返回 JSX
|
|
155
|
-
addDataScopeAttribute(body.node);
|
|
199
|
+
addDataScopeAttribute(body.node, scopeValue);
|
|
156
200
|
} else if (body.isJSXFragment()) {
|
|
157
201
|
// 箭头函数直接返回 Fragment
|
|
158
202
|
const children = body.get('children');
|
|
159
203
|
for (const child of children) {
|
|
160
204
|
if (child.isJSXElement()) {
|
|
161
|
-
addDataScopeAttribute(child.node);
|
|
205
|
+
addDataScopeAttribute(child.node, scopeValue);
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
// 如果子节点是 Fragment,递归处理
|
|
209
|
+
if (child.isJSXFragment()) {
|
|
210
|
+
processReturnStatement(child, scopeValue);
|
|
162
211
|
return;
|
|
163
212
|
}
|
|
164
213
|
}
|
|
@@ -166,13 +215,17 @@ module.exports = function ({ types: t }) {
|
|
|
166
215
|
},
|
|
167
216
|
|
|
168
217
|
// 处理类组件的 render 方法
|
|
169
|
-
ClassMethod(
|
|
170
|
-
if (
|
|
171
|
-
|
|
218
|
+
ClassMethod(classMethodPath) {
|
|
219
|
+
if (classMethodPath.node.kind === 'method' && classMethodPath.node.key.name === 'render') {
|
|
220
|
+
// 获取当前文件路径并提取目录名
|
|
221
|
+
const filePath = classMethodPath.hub?.file?.opts?.filename || '';
|
|
222
|
+
const scopeValue = getDirectoryName(filePath);
|
|
223
|
+
|
|
224
|
+
const body = classMethodPath.get('body');
|
|
172
225
|
if (body.isBlockStatement()) {
|
|
173
226
|
body.traverse({
|
|
174
227
|
ReturnStatement(returnPath) {
|
|
175
|
-
processReturnStatement(returnPath);
|
|
228
|
+
processReturnStatement(returnPath, scopeValue);
|
|
176
229
|
}
|
|
177
230
|
});
|
|
178
231
|
}
|
|
@@ -106,7 +106,10 @@ module.exports = function (curConfig, curEnvConfig) {
|
|
|
106
106
|
declarationDir: curEnvConfig.declarationDir || './dist/types'
|
|
107
107
|
})
|
|
108
108
|
: undefined,
|
|
109
|
-
babel(
|
|
109
|
+
babel({
|
|
110
|
+
extensions: ['.js', '.jsx', '.ts', '.tsx'],
|
|
111
|
+
...babelConfig
|
|
112
|
+
}), // 备注,需要先babel()再commjs()
|
|
110
113
|
buildType === 'ts' ? undefined : jsx({ factory: 'React.createElement' }),
|
|
111
114
|
vue(),
|
|
112
115
|
commonjs({
|
|
@@ -44,9 +44,6 @@ module.exports = (_curEnvConfig, _akfunConfig, buildMode = 'build') => {
|
|
|
44
44
|
...babelConfig
|
|
45
45
|
};
|
|
46
46
|
|
|
47
|
-
// 剔除掉 babel-loader 不需要的配置
|
|
48
|
-
delete curBabelConfig.extensions;
|
|
49
|
-
|
|
50
47
|
// 判断是否有自定义 Babel plugins
|
|
51
48
|
if (isArray(curWebpackConfig.babelPlugins)) {
|
|
52
49
|
// 添加自定义babel插件
|