hw-weapp-compiler 1.0.8 → 1.0.10
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 +6 -6
- package/build/config/getEntries.js +111 -82
- package/build/dev.js +26 -16
- package/build/loader/js-loader.js +2 -2
- package/build/loader/wxs-loader.js +63 -6
- package/build/plugin/index.js +11 -3
- package/build/prod.js +12 -3
- package/build/utils/createCompilerHandler.js +2 -0
- package/build/utils/isSubpackage.js +17 -13
- package/build/webpack.config.js +24 -16
- package/index.js +8 -2
- package/package.json +6 -5
package/README.md
CHANGED
|
@@ -16,14 +16,14 @@ npm i weapp-compiler@2.x -D
|
|
|
16
16
|
|
|
17
17
|
```bash
|
|
18
18
|
# 开发调试
|
|
19
|
-
npm run dev
|
|
20
|
-
npm run dev
|
|
21
|
-
npm run dev
|
|
19
|
+
npm run dev # 测试环境
|
|
20
|
+
npm run dev -s # 预发环境
|
|
21
|
+
npm run dev -p # 生产环境
|
|
22
22
|
|
|
23
23
|
# 生产发布
|
|
24
|
-
npm run build
|
|
25
|
-
npm run build
|
|
26
|
-
npm run build
|
|
24
|
+
npm run build -d # 测试环境
|
|
25
|
+
npm run build -s # 预发环境
|
|
26
|
+
npm run build # 生产环境
|
|
27
27
|
```
|
|
28
28
|
|
|
29
29
|
## 配置
|
|
@@ -4,110 +4,139 @@ const { addNodeModulesUsingComponent } = require('../utils/isNodeModulesUsingCom
|
|
|
4
4
|
const { compatiblePath } = require('../utils/compatiblePath');
|
|
5
5
|
const { getAppConfig } = require('./getAppConfig');
|
|
6
6
|
const { PATTERNS, SRC_DIR } = require('./constants');
|
|
7
|
-
const appConfig = getAppConfig();
|
|
8
7
|
|
|
9
|
-
const
|
|
10
|
-
app: path.resolve(SRC_DIR, 'app'),
|
|
11
|
-
};
|
|
12
|
-
const visitedJsonFiles = new Set();
|
|
13
|
-
const entryFiles = [entries.app];
|
|
8
|
+
const appConfig = getAppConfig();
|
|
14
9
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
};
|
|
10
|
+
// 惰性异步初始化:entry / usingComponents 收集改为 Promise.all 并发读 json,
|
|
11
|
+
// 避免在 webpack 启动前对深组件树做同步串行 readJSONSync/existsSync/require.resolve。
|
|
12
|
+
let entriesPromise = null;
|
|
19
13
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
let filePath = components[key];
|
|
14
|
+
function buildBaseEntries() {
|
|
15
|
+
const entries = { app: path.resolve(SRC_DIR, 'app') };
|
|
16
|
+
const entryFiles = [entries.app];
|
|
24
17
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
18
|
+
const addEntry = (entryKey, filePath) => {
|
|
19
|
+
entries[compatiblePath(entryKey)] = filePath;
|
|
20
|
+
entryFiles.push(filePath);
|
|
21
|
+
};
|
|
29
22
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
filePath = require.resolve(filePath);
|
|
35
|
-
filePath = filePath.replace(PATTERNS.JS_EXT, '');
|
|
36
|
-
} catch (error) {
|
|
37
|
-
throw new Error(
|
|
38
|
-
`解析 usingComponents "${key}" 的组件路径 "${originalFilePath}" 失败,父级目录:${parent}\n${error.message}`,
|
|
39
|
-
);
|
|
40
|
-
}
|
|
41
|
-
}
|
|
23
|
+
// pages
|
|
24
|
+
(appConfig.pages || []).forEach((page) => {
|
|
25
|
+
addEntry(page, path.resolve(SRC_DIR, page));
|
|
26
|
+
});
|
|
42
27
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
28
|
+
// tabbar
|
|
29
|
+
if (fse.existsSync(path.resolve(SRC_DIR, 'custom-tab-bar/index.js'))) {
|
|
30
|
+
addEntry('custom-tab-bar/index', path.resolve(SRC_DIR, 'custom-tab-bar/index'));
|
|
31
|
+
}
|
|
47
32
|
|
|
48
|
-
|
|
33
|
+
// subpackages
|
|
34
|
+
(appConfig.subpackages || []).forEach((pkg) => {
|
|
35
|
+
(pkg.pages || []).forEach((page) => {
|
|
36
|
+
addEntry(path.join(pkg.root, page), path.resolve(SRC_DIR, pkg.root, page));
|
|
37
|
+
});
|
|
38
|
+
});
|
|
49
39
|
|
|
50
|
-
|
|
51
|
-
|
|
40
|
+
return { entries, entryFiles };
|
|
41
|
+
}
|
|
52
42
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
}
|
|
43
|
+
function resolveUsingComponentPath(componentKey, componentPath, parent) {
|
|
44
|
+
let filePath = componentPath;
|
|
45
|
+
const originalFilePath = componentPath;
|
|
57
46
|
|
|
58
|
-
|
|
47
|
+
if (!PATTERNS.PLUGIN_PATH.test(filePath)) {
|
|
48
|
+
if (PATTERNS.ABSOLUTE_PATH.test(filePath)) {
|
|
49
|
+
filePath = path.resolve(SRC_DIR, filePath.replace(PATTERNS.ABSOLUTE_PATH, ''));
|
|
50
|
+
}
|
|
59
51
|
|
|
60
|
-
|
|
52
|
+
if (fse.existsSync(`${path.resolve(parent, filePath)}.js`)) {
|
|
53
|
+
filePath = path.resolve(parent, filePath);
|
|
54
|
+
} else {
|
|
55
|
+
try {
|
|
56
|
+
filePath = require.resolve(filePath);
|
|
57
|
+
filePath = filePath.replace(PATTERNS.JS_EXT, '');
|
|
58
|
+
} catch (error) {
|
|
59
|
+
throw new Error(
|
|
60
|
+
`解析 usingComponents "${componentKey}" 的组件路径 "${originalFilePath}" 失败,父级目录:${parent}\n${error.message}`,
|
|
61
|
+
);
|
|
62
|
+
}
|
|
61
63
|
}
|
|
62
|
-
});
|
|
63
|
-
};
|
|
64
|
-
const readUsingComponents = (file) => {
|
|
65
|
-
const jsonFile = path.resolve(file);
|
|
66
64
|
|
|
67
|
-
|
|
68
|
-
return;
|
|
65
|
+
return filePath;
|
|
69
66
|
}
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
70
69
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
const
|
|
70
|
+
async function collectUsingComponents(entryFiles, entries) {
|
|
71
|
+
const visitedJsonFiles = new Set();
|
|
72
|
+
const jsonQueue = [];
|
|
74
73
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
74
|
+
entryFiles.forEach((filePath) => {
|
|
75
|
+
const jsonFile = `${filePath}.json`;
|
|
76
|
+
if (fse.existsSync(jsonFile)) {
|
|
77
|
+
jsonQueue.push(jsonFile);
|
|
78
|
+
}
|
|
79
|
+
});
|
|
81
80
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
81
|
+
// 并发读 json,结果中新的 usingComponents 继续入队,直到队列空
|
|
82
|
+
while (jsonQueue.length > 0) {
|
|
83
|
+
const batch = jsonQueue.splice(0);
|
|
84
|
+
const results = await Promise.all(
|
|
85
|
+
batch.map(async (file) => {
|
|
86
|
+
const jsonFile = path.resolve(file);
|
|
87
|
+
if (visitedJsonFiles.has(jsonFile)) {
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
visitedJsonFiles.add(jsonFile);
|
|
91
|
+
const json = await fse.readJSON(jsonFile);
|
|
92
|
+
return { dir: path.parse(jsonFile).dir, usingComponents: json.usingComponents || {} };
|
|
93
|
+
}),
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
const newComponents = [];
|
|
97
|
+
results.filter(Boolean).forEach(({ dir, usingComponents }) => {
|
|
98
|
+
Object.keys(usingComponents).forEach((key) => {
|
|
99
|
+
newComponents.push({ key, value: usingComponents[key], dir });
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
// 同步解析路径(existsSync/require.resolve 不宜并发但单 round 内串行,正是被批处理掉的是 readJSON)
|
|
104
|
+
newComponents.forEach(({ key, value, dir }) => {
|
|
105
|
+
const resolved = resolveUsingComponentPath(key, value, dir);
|
|
106
|
+
if (!resolved) {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
86
109
|
|
|
87
|
-
|
|
88
|
-
(
|
|
89
|
-
|
|
90
|
-
});
|
|
110
|
+
if (fse.existsSync(`${resolved}.json`)) {
|
|
111
|
+
jsonQueue.push(`${resolved}.json`);
|
|
112
|
+
}
|
|
91
113
|
|
|
92
|
-
|
|
93
|
-
if (
|
|
94
|
-
|
|
114
|
+
let entryKey;
|
|
115
|
+
if (PATTERNS.NODE_MODULES.test(resolved)) {
|
|
116
|
+
entryKey = compatiblePath(resolved).split('/node_modules/')[1];
|
|
117
|
+
addNodeModulesUsingComponent(entryKey);
|
|
118
|
+
} else {
|
|
119
|
+
entryKey = path.relative(SRC_DIR, resolved);
|
|
120
|
+
}
|
|
121
|
+
entryKey = compatiblePath(entryKey);
|
|
122
|
+
entries[entryKey] = resolved;
|
|
123
|
+
});
|
|
124
|
+
}
|
|
95
125
|
}
|
|
96
126
|
|
|
97
|
-
// subpackages
|
|
98
|
-
(appConfig.subpackages || []).forEach((pkg) => {
|
|
99
|
-
(pkg.pages || []).forEach((page) => {
|
|
100
|
-
addEntry(path.join(pkg.root, page), path.resolve(SRC_DIR, pkg.root, page));
|
|
101
|
-
});
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
// usingComponents
|
|
105
|
-
entryFiles.forEach((filePath) => {
|
|
106
|
-
readEntryUsingComponents(filePath);
|
|
107
|
-
});
|
|
108
|
-
|
|
109
127
|
function getEntries() {
|
|
110
|
-
|
|
128
|
+
if (!entriesPromise) {
|
|
129
|
+
const { entries, entryFiles } = buildBaseEntries();
|
|
130
|
+
// 收集失败时清空缓存,允许下次 getEntries() 重新尝试,
|
|
131
|
+
// 避免模块级单例永久持有 rejected promise 导致整个进程卡死。
|
|
132
|
+
entriesPromise = collectUsingComponents(entryFiles, entries)
|
|
133
|
+
.then(() => entries)
|
|
134
|
+
.catch((error) => {
|
|
135
|
+
entriesPromise = null;
|
|
136
|
+
throw error;
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
return entriesPromise;
|
|
111
140
|
}
|
|
112
141
|
|
|
113
142
|
module.exports = {
|
package/build/dev.js
CHANGED
|
@@ -1,28 +1,38 @@
|
|
|
1
1
|
const path = require('path');
|
|
2
|
-
const fse = require('fs-extra');
|
|
3
2
|
const webpack = require('webpack');
|
|
4
|
-
const { ENV
|
|
3
|
+
const { ENV } = require('./config/constants');
|
|
5
4
|
const webpackConfig = require('./webpack.config');
|
|
6
5
|
const { createCompilerHandler } = require('./utils/createCompilerHandler');
|
|
7
6
|
|
|
8
|
-
module.exports = (opts) => {
|
|
9
|
-
//
|
|
10
|
-
if (fse.existsSync(DIST_DIR)) {
|
|
11
|
-
const files = fse.readdirSync(DIST_DIR);
|
|
12
|
-
files.forEach((item) => {
|
|
13
|
-
if (!/^(project\.config\.json|weapp\.env\.json)$/.test(item)) {
|
|
14
|
-
fse.removeSync(path.resolve(DIST_DIR, item));
|
|
15
|
-
}
|
|
16
|
-
});
|
|
17
|
-
} else {
|
|
18
|
-
fse.mkdirSync(DIST_DIR);
|
|
19
|
-
}
|
|
20
|
-
|
|
7
|
+
module.exports = async (opts) => {
|
|
8
|
+
// dev 同样启用 filesystem cache,watch 重建复用缓存,二次启动显著提速
|
|
21
9
|
const compiler = webpack(
|
|
22
|
-
webpackConfig(
|
|
10
|
+
await webpackConfig(
|
|
23
11
|
{
|
|
24
12
|
mode: ENV.DEV,
|
|
25
13
|
devtool: 'cheap-module-source-map',
|
|
14
|
+
output: {
|
|
15
|
+
clean: {
|
|
16
|
+
keep: /^(project\.config\.json|weapp\.env\.json)$/,
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
cache: {
|
|
20
|
+
type: 'filesystem',
|
|
21
|
+
cacheDirectory: path.resolve(process.cwd(), 'node_modules/.cache/webpack'),
|
|
22
|
+
buildDependencies: {
|
|
23
|
+
// webpack.config.js 及其 require 的 getEntries.js / loader / plugin 都作为
|
|
24
|
+
// 缓存依赖,本编译器自身代码改动后即时整体失效,避免复用旧 loader 输出。
|
|
25
|
+
config: [
|
|
26
|
+
path.resolve(__dirname, 'webpack.config.js'),
|
|
27
|
+
path.resolve(__dirname, 'config/getEntries.js'),
|
|
28
|
+
path.resolve(__dirname, 'plugin/index.js'),
|
|
29
|
+
path.resolve(__dirname, 'loader/js-loader.js'),
|
|
30
|
+
path.resolve(__dirname, 'loader/wxs-loader.js'),
|
|
31
|
+
path.resolve(__dirname, 'loader/wxml-loader.js'),
|
|
32
|
+
],
|
|
33
|
+
},
|
|
34
|
+
name: `dev-${process.version.slice(0, 6)}`,
|
|
35
|
+
},
|
|
26
36
|
},
|
|
27
37
|
opts || {},
|
|
28
38
|
),
|
|
@@ -9,8 +9,6 @@ const fse = require('fs-extra');
|
|
|
9
9
|
const { getEntries } = require('../config/getEntries');
|
|
10
10
|
const { loadModule } = require('../utils/loadModule');
|
|
11
11
|
|
|
12
|
-
const entries = getEntries();
|
|
13
|
-
|
|
14
12
|
module.exports = async function loader(source) {
|
|
15
13
|
this.cacheable(true);
|
|
16
14
|
const filePath = this.resourcePath;
|
|
@@ -19,6 +17,8 @@ module.exports = async function loader(source) {
|
|
|
19
17
|
|
|
20
18
|
const imports = [sourceStr];
|
|
21
19
|
|
|
20
|
+
const entries = await getEntries();
|
|
21
|
+
|
|
22
22
|
if (Object.values(entries).indexOf(path.resolve(fileInfo.dir, fileInfo.name)) !== -1) {
|
|
23
23
|
const exts = ['.less', '.wxss', '.css', '.json', '.wxml'];
|
|
24
24
|
const checks = await Promise.all(
|
|
@@ -3,24 +3,81 @@
|
|
|
3
3
|
*
|
|
4
4
|
* 解析 wxs 文件中的 require 调用,将被引用的模块加入 webpack 依赖图,
|
|
5
5
|
* 确保构建时 wxs 的依赖被正确追踪。
|
|
6
|
+
*
|
|
7
|
+
* 实现说明:用 acorn 做 AST 解析后再遍历 CallExpression,仅收集 require 的
|
|
8
|
+
* 字面量参数。相比原先的正则 `require\(("|').*?("|')\)`,可避免误匹配注释、
|
|
9
|
+
* 字符串里的 require(...),也不受跨行/模板字符串影响。
|
|
10
|
+
*
|
|
11
|
+
* 注意:wxs 以 script 语法解析,若含 import/export 等 module 语法 parse 会失败 ——
|
|
12
|
+
* 此时不能直接丢依赖(会静默让运行时找不到模块),必须回退到正则兜底,并 emitWarning
|
|
13
|
+
* 暴露问题,绝不静默吞掉。
|
|
6
14
|
*/
|
|
7
15
|
const path = require('path');
|
|
16
|
+
const acorn = require('acorn');
|
|
17
|
+
const walk = require('acorn-walk');
|
|
8
18
|
const { loadModule } = require('../utils/loadModule');
|
|
9
19
|
|
|
20
|
+
const REQUIRE_RE = /require\(("|')(.*?)\1\)/g;
|
|
21
|
+
|
|
22
|
+
function collectStaticRequires(content) {
|
|
23
|
+
const requires = [];
|
|
24
|
+
let ast;
|
|
25
|
+
let parseError = null;
|
|
26
|
+
try {
|
|
27
|
+
ast = acorn.parse(content, { ecmaVersion: 'latest', sourceType: 'script' });
|
|
28
|
+
} catch (error) {
|
|
29
|
+
parseError = error;
|
|
30
|
+
return { requires, parseError };
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
walk.simple(ast, {
|
|
34
|
+
CallExpression(node) {
|
|
35
|
+
if (node.callee.type !== 'Identifier' || node.callee.name !== 'require') {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
const arg = node.arguments[0];
|
|
39
|
+
if (arg && arg.type === 'Literal' && typeof arg.value === 'string') {
|
|
40
|
+
requires.push(arg.value);
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
return { requires, parseError };
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function collectRequiresByRegex(content) {
|
|
49
|
+
const result = [];
|
|
50
|
+
let match;
|
|
51
|
+
// eslint-disable-next-line no-cond-assign
|
|
52
|
+
while ((match = REQUIRE_RE.exec(content)) !== null) {
|
|
53
|
+
result.push(match[2]);
|
|
54
|
+
}
|
|
55
|
+
return result;
|
|
56
|
+
}
|
|
57
|
+
|
|
10
58
|
module.exports = async function loader(source) {
|
|
11
59
|
this.cacheable(true);
|
|
12
60
|
const filePath = this.resourcePath;
|
|
13
61
|
const content = source.toString();
|
|
14
62
|
const fileInfo = path.parse(filePath);
|
|
15
63
|
|
|
16
|
-
|
|
64
|
+
let { requires, parseError } = collectStaticRequires(content);
|
|
65
|
+
if (parseError) {
|
|
66
|
+
// AST 解析失败(如含 module 语法),回退正则兜底,避免静默丢依赖致运行时缺模块。
|
|
67
|
+
this.emitWarning(
|
|
68
|
+
new Error(
|
|
69
|
+
`wxs-loader: AST 解析失败,已回退正则匹配 require。建议改写为合法 script 语法。\n文件:${filePath}\n原因:${parseError.message}`,
|
|
70
|
+
),
|
|
71
|
+
);
|
|
72
|
+
requires = collectRequiresByRegex(content);
|
|
73
|
+
} else if (requires.length === 0) {
|
|
74
|
+
// AST 未收集到任何 require(极少见但稳妥),同样正则兜底一次。
|
|
75
|
+
requires = collectRequiresByRegex(content);
|
|
76
|
+
}
|
|
17
77
|
|
|
18
78
|
await Promise.all(
|
|
19
|
-
requires.map(async (
|
|
20
|
-
const file = path.resolve(
|
|
21
|
-
fileInfo.dir,
|
|
22
|
-
item.replace(/^((require\(')|(require\("))/g, '').replace(/(('\))|("\)))$/g, ''),
|
|
23
|
-
);
|
|
79
|
+
requires.map(async (reqPath) => {
|
|
80
|
+
const file = path.resolve(fileInfo.dir, reqPath);
|
|
24
81
|
await loadModule.call(this, file);
|
|
25
82
|
}),
|
|
26
83
|
);
|
package/build/plugin/index.js
CHANGED
|
@@ -198,6 +198,11 @@ class WeappPlugin {
|
|
|
198
198
|
|
|
199
199
|
const { flags, subpackages } = detectCommonModules(items);
|
|
200
200
|
|
|
201
|
+
// 注入逻辑必须对每个 JS/WXSS chunk 都跑(每个 chunk 都要 `var self = global`,
|
|
202
|
+
// 分包内 chunk 都要 `require(subpackage_common)`,app.js 的公共引用序等);
|
|
203
|
+
// 这些注入依赖每次从干净的 webpack module source 重做,不能按 changedAssets 增量跳过,
|
|
204
|
+
// 否则增量 rebuild 后会漏注入。
|
|
205
|
+
// 优化点:比较注入前后内容,仅在确实变化时才 updateAsset,减少无谓的 asset 重写与下游 hash 抖动。
|
|
201
206
|
await Promise.all(
|
|
202
207
|
items.map(async (asset) => {
|
|
203
208
|
const assetName = compatiblePath(asset.name);
|
|
@@ -207,10 +212,13 @@ class WeappPlugin {
|
|
|
207
212
|
content = content.toString();
|
|
208
213
|
}
|
|
209
214
|
|
|
210
|
-
|
|
211
|
-
|
|
215
|
+
const before = content;
|
|
216
|
+
const after = injectGlobalModules(content, assetName, flags);
|
|
217
|
+
const finalContent = injectSubpackageRequires(after, assetName, subpackages);
|
|
212
218
|
|
|
213
|
-
|
|
219
|
+
if (finalContent !== before) {
|
|
220
|
+
compilation.updateAsset(asset.name, new RawSource(finalContent));
|
|
221
|
+
}
|
|
214
222
|
}),
|
|
215
223
|
);
|
|
216
224
|
},
|
package/build/prod.js
CHANGED
|
@@ -7,9 +7,9 @@ const webpackConfig = require('./webpack.config');
|
|
|
7
7
|
const { createCompilerHandler } = require('./utils/createCompilerHandler');
|
|
8
8
|
const { getBuildEnv } = require('./utils/buildEnv');
|
|
9
9
|
|
|
10
|
-
module.exports = (opts) => {
|
|
10
|
+
module.exports = async (opts) => {
|
|
11
11
|
const compiler = webpack(
|
|
12
|
-
webpackConfig(
|
|
12
|
+
await webpackConfig(
|
|
13
13
|
{
|
|
14
14
|
mode: ENV.PROD,
|
|
15
15
|
devtool: false,
|
|
@@ -32,7 +32,16 @@ module.exports = (opts) => {
|
|
|
32
32
|
type: 'filesystem',
|
|
33
33
|
cacheDirectory: path.resolve(process.cwd(), 'node_modules/.cache/webpack'),
|
|
34
34
|
buildDependencies: {
|
|
35
|
-
|
|
35
|
+
// webpack.config.js 及其 require 的 getEntries.js / loader / plugin 都作为
|
|
36
|
+
// 缓存依赖,本编译器自身代码改动后即时整体失效,避免复用旧 loader 输出。
|
|
37
|
+
config: [
|
|
38
|
+
path.resolve(__dirname, 'webpack.config.js'),
|
|
39
|
+
path.resolve(__dirname, 'config/getEntries.js'),
|
|
40
|
+
path.resolve(__dirname, 'plugin/index.js'),
|
|
41
|
+
path.resolve(__dirname, 'loader/js-loader.js'),
|
|
42
|
+
path.resolve(__dirname, 'loader/wxs-loader.js'),
|
|
43
|
+
path.resolve(__dirname, 'loader/wxml-loader.js'),
|
|
44
|
+
],
|
|
36
45
|
},
|
|
37
46
|
name: `${getBuildEnv()}-${process.version.slice(0, 6)}`,
|
|
38
47
|
},
|
|
@@ -3,21 +3,25 @@ const { getAppConfig } = require('../config/getAppConfig');
|
|
|
3
3
|
|
|
4
4
|
const appConfig = getAppConfig();
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}
|
|
6
|
+
// 预归一化分包 root 为带尾斜杠的相对路径集合,让 isSubpackage 退化为 O(subpackages) 前缀判断
|
|
7
|
+
// (splitChunks 的 cacheGroup.test 会对每个 module 调用,原实现线性扫描且每次重新 normalize)。
|
|
8
|
+
// root 为空视为「不分包」,跳过该 pkg,否则 '' 会被归一化成 '/',导致所有主包文件被误判为子包。
|
|
9
|
+
const subpackageRoots = (appConfig.subpackages || [])
|
|
10
|
+
.map((pkg) => pkg.root || '')
|
|
11
|
+
.filter(Boolean)
|
|
12
|
+
.map((root) => {
|
|
13
|
+
const normalized = compatiblePath(root);
|
|
14
|
+
return normalized.endsWith('/') ? normalized : `${normalized}/`;
|
|
15
|
+
});
|
|
15
16
|
|
|
16
|
-
|
|
17
|
-
|
|
17
|
+
function isSubpackage(file) {
|
|
18
|
+
const f = compatiblePath(file);
|
|
19
|
+
for (let i = 0; i < subpackageRoots.length; i += 1) {
|
|
20
|
+
if (subpackageRoots[i] && f.indexOf(subpackageRoots[i]) === 0) {
|
|
21
|
+
return true;
|
|
18
22
|
}
|
|
19
|
-
}
|
|
20
|
-
return
|
|
23
|
+
}
|
|
24
|
+
return false;
|
|
21
25
|
}
|
|
22
26
|
module.exports = {
|
|
23
27
|
isSubpackage,
|
package/build/webpack.config.js
CHANGED
|
@@ -20,10 +20,15 @@ const { ENV, PATTERNS, ASSET_EXT_PATTERN, SRC_DIR, DIST_DIR, ASSETS_DIR } = requ
|
|
|
20
20
|
|
|
21
21
|
const defaultCopyFiles = ['project.config.json', 'sitemap.json'];
|
|
22
22
|
|
|
23
|
-
module.exports = (options, { analyzer, quiet } = {}) => {
|
|
23
|
+
module.exports = async (options, { analyzer, quiet } = {}) => {
|
|
24
24
|
const appConfig = getAppConfig();
|
|
25
|
-
const { alias, publicPath = 'auto', copyFiles = [] } = getConfig();
|
|
26
|
-
|
|
25
|
+
const { alias = {}, publicPath = 'auto', copyFiles = [] } = getConfig();
|
|
26
|
+
|
|
27
|
+
// swc externalHelpers 产物里有 require("@swc/helpers/..."),本包作为编译器被 npm 安装到
|
|
28
|
+
// 用户项目时,@swc/helpers 通常落在本包内层 node_modules 而非用户项目顶层,用户源码
|
|
29
|
+
// 所在目录向上解析不到 → 构建直接 Module not found。固定指到本包内的绝对路径。
|
|
30
|
+
alias['@swc/helpers'] = path.dirname(require.resolve('@swc/helpers/package.json'));
|
|
31
|
+
const entries = await getEntries();
|
|
27
32
|
|
|
28
33
|
const assetsName = (resourcePath) => {
|
|
29
34
|
if (PATTERNS.NODE_MODULES.test(resourcePath)) {
|
|
@@ -206,6 +211,9 @@ module.exports = (options, { analyzer, quiet } = {}) => {
|
|
|
206
211
|
stats: {
|
|
207
212
|
errorDetails: true,
|
|
208
213
|
},
|
|
214
|
+
performance: {
|
|
215
|
+
hints: false,
|
|
216
|
+
},
|
|
209
217
|
output: {
|
|
210
218
|
path: DIST_DIR,
|
|
211
219
|
publicPath,
|
|
@@ -306,20 +314,20 @@ module.exports = (options, { analyzer, quiet } = {}) => {
|
|
|
306
314
|
test: /\.(js)$/i,
|
|
307
315
|
use: [
|
|
308
316
|
{
|
|
309
|
-
loader: '
|
|
317
|
+
loader: require.resolve('swc-loader'),
|
|
310
318
|
options: {
|
|
311
319
|
cacheDirectory: true,
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
320
|
+
// 用 env 模式按 chrome 53 降级,等价原 babel preset-env targets.chrome53。
|
|
321
|
+
// swc 不再产出 regeneratorRuntime,而是 require("@swc/helpers/...") 配原生生
|
|
322
|
+
// 成器(chrome 53 原生支持 function*),由上方 resolve.alias 固定解析到本包内。
|
|
323
|
+
env: {
|
|
324
|
+
targets: { chrome: '53' },
|
|
325
|
+
},
|
|
326
|
+
jsc: {
|
|
327
|
+
parser: { syntax: 'ecmascript' },
|
|
328
|
+
externalHelpers: true,
|
|
329
|
+
},
|
|
330
|
+
module: { type: 'commonjs' },
|
|
323
331
|
},
|
|
324
332
|
},
|
|
325
333
|
{
|
|
@@ -342,4 +350,4 @@ module.exports = (options, { analyzer, quiet } = {}) => {
|
|
|
342
350
|
},
|
|
343
351
|
options,
|
|
344
352
|
);
|
|
345
|
-
};
|
|
353
|
+
};
|
package/index.js
CHANGED
|
@@ -34,14 +34,20 @@ program.command('dev').action(() => {
|
|
|
34
34
|
mode: ENV.DEV,
|
|
35
35
|
...program.opts(),
|
|
36
36
|
});
|
|
37
|
-
compiler.dev(program.opts())
|
|
37
|
+
compiler.dev(program.opts()).catch((err) => {
|
|
38
|
+
console.error(err);
|
|
39
|
+
process.exitCode = 1;
|
|
40
|
+
});
|
|
38
41
|
});
|
|
39
42
|
program.command('build').action(() => {
|
|
40
43
|
setBuildEnv({
|
|
41
44
|
mode: ENV.PROD,
|
|
42
45
|
...program.opts(),
|
|
43
46
|
});
|
|
44
|
-
compiler.prod(program.opts())
|
|
47
|
+
compiler.prod(program.opts()).catch((err) => {
|
|
48
|
+
console.error(err);
|
|
49
|
+
process.exitCode = 1;
|
|
50
|
+
});
|
|
45
51
|
});
|
|
46
52
|
|
|
47
53
|
program.parse(process.argv);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hw-weapp-compiler",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.10",
|
|
4
4
|
"description": "基于 webpack5 的小程序构建工具,兼容 Node.js 14~24",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -15,12 +15,12 @@
|
|
|
15
15
|
"node": ">=14.17.1"
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@
|
|
19
|
-
"@
|
|
20
|
-
"
|
|
18
|
+
"@swc/core": "^1.15.43",
|
|
19
|
+
"@swc/helpers": "^0.5.23",
|
|
20
|
+
"acorn": "^8.17.0",
|
|
21
|
+
"acorn-walk": "^8.3.5",
|
|
21
22
|
"ali-oss": "^6.15.2",
|
|
22
23
|
"autoprefixer": "^10.3.4",
|
|
23
|
-
"babel-loader": "^8.2.2",
|
|
24
24
|
"chalk": "^4.1.0",
|
|
25
25
|
"commander": "^7.2.0",
|
|
26
26
|
"copy-webpack-plugin": "^8.1.0",
|
|
@@ -37,6 +37,7 @@
|
|
|
37
37
|
"postcss-loader": "^5.2.0",
|
|
38
38
|
"postcss-preset-env": "^9.6.0",
|
|
39
39
|
"progress": "^2.0.3",
|
|
40
|
+
"swc-loader": "^0.2.7",
|
|
40
41
|
"terser-webpack-plugin": "^5.6.1",
|
|
41
42
|
"throttle-debounce": "^3.0.1",
|
|
42
43
|
"url-loader": "^4.1.1",
|