hw-weapp-compiler 1.0.9 → 1.0.11
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/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/isSubpackage.js +17 -13
- package/build/webpack.config.js +19 -16
- package/index.js +8 -2
- package/package.json +6 -5
|
@@ -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,11 @@ 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
|
+
const entries = await getEntries();
|
|
27
28
|
|
|
28
29
|
const assetsName = (resourcePath) => {
|
|
29
30
|
if (PATTERNS.NODE_MODULES.test(resourcePath)) {
|
|
@@ -309,20 +310,22 @@ module.exports = (options, { analyzer, quiet } = {}) => {
|
|
|
309
310
|
test: /\.(js)$/i,
|
|
310
311
|
use: [
|
|
311
312
|
{
|
|
312
|
-
loader: '
|
|
313
|
+
loader: require.resolve('swc-loader'),
|
|
313
314
|
options: {
|
|
314
315
|
cacheDirectory: true,
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
316
|
+
// 用 env 模式按 chrome 53 降级,等价原 babel preset-env targets.chrome53。
|
|
317
|
+
// 关闭 externalHelpers:helper 内联进每个使用文件,不 require("@swc/helpers"),
|
|
318
|
+
// 也不产 regeneratorRuntime(chrome 53 原生支持 function*)。
|
|
319
|
+
// 绝不能开 externalHelpers —— @swc/helpers 是 ESM 形态 `export { ... as _ }`,
|
|
320
|
+
// 经 webpack 转 CJS 后小程序 appservice 模块加载器对 exports key `_` 用
|
|
321
|
+
// Object.defineProperty 且不可重定义,会抛 `Cannot redefine property: _`。
|
|
322
|
+
env: {
|
|
323
|
+
targets: { chrome: '53' },
|
|
324
|
+
},
|
|
325
|
+
jsc: {
|
|
326
|
+
parser: { syntax: 'ecmascript' },
|
|
327
|
+
},
|
|
328
|
+
module: { type: 'commonjs' },
|
|
326
329
|
},
|
|
327
330
|
},
|
|
328
331
|
{
|
|
@@ -345,4 +348,4 @@ module.exports = (options, { analyzer, quiet } = {}) => {
|
|
|
345
348
|
},
|
|
346
349
|
options,
|
|
347
350
|
);
|
|
348
|
-
};
|
|
351
|
+
};
|
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.11",
|
|
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",
|