@dimina/compiler 1.0.14-beta.0 → 1.0.14
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/dist/bin/index.cjs +16 -17
- package/dist/bin/index.js +16 -17
- package/dist/compatibility-B_5UilxZ.js +165 -0
- package/dist/compatibility-DCnJNS-s.cjs +183 -0
- package/dist/core/logic-compiler.cjs +166 -82
- package/dist/core/logic-compiler.js +166 -81
- package/dist/core/view-compiler.cjs +200 -122
- package/dist/core/view-compiler.js +199 -118
- package/dist/index.cjs +30 -7
- package/dist/index.js +31 -8
- package/package.json +12 -14
|
@@ -1,20 +1,19 @@
|
|
|
1
1
|
import { _ as tagWhiteList, a as getContentByPath, d as resetStoreInfo, h as getAbsolutePath, i as getComponent, l as getTargetPath, m as collectAssets, n as getAppId, u as getWorkPath, v as transformRpx } from "../env-DgCLbrQb.js";
|
|
2
|
+
import { t as checkTemplateCompatibility } from "../compatibility-B_5UilxZ.js";
|
|
2
3
|
import path from "node:path";
|
|
3
4
|
import { isMainThread, parentPort } from "node:worker_threads";
|
|
4
5
|
import fs from "node:fs";
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
import generate from "@babel/generator";
|
|
6
|
+
import { parseSync } from "oxc-parser";
|
|
7
|
+
import { walk } from "oxc-walker";
|
|
8
|
+
import MagicString from "magic-string";
|
|
9
9
|
import { compileTemplate } from "@vue/compiler-sfc";
|
|
10
10
|
import * as cheerio from "cheerio";
|
|
11
11
|
import { transform } from "esbuild";
|
|
12
12
|
import * as htmlparser2 from "htmlparser2";
|
|
13
13
|
//#region src/common/expression-parser.js
|
|
14
14
|
/**
|
|
15
|
-
* 表达式解析器 - 使用
|
|
15
|
+
* 表达式解析器 - 使用 Oxc AST 解析器提取依赖
|
|
16
16
|
*/
|
|
17
|
-
var traverse$1 = _traverse.default ? _traverse.default : _traverse;
|
|
18
17
|
var KEYWORDS = new Set([
|
|
19
18
|
"true",
|
|
20
19
|
"false",
|
|
@@ -48,7 +47,7 @@ var KEYWORDS = new Set([
|
|
|
48
47
|
]);
|
|
49
48
|
/**
|
|
50
49
|
* 提取表达式中的所有变量依赖路径
|
|
51
|
-
* 使用
|
|
50
|
+
* 使用 Oxc AST 解析器进行精确分析
|
|
52
51
|
* @param {string} expression - 表达式字符串,如 "count || defaultValue" 或 "item.name"
|
|
53
52
|
* @returns {Array<string>} - 依赖的变量名数组,如 ["count", "defaultValue"] 或 ["item"]
|
|
54
53
|
*/
|
|
@@ -56,36 +55,42 @@ function extractDependencies(expression) {
|
|
|
56
55
|
if (!expression || typeof expression !== "string") return [];
|
|
57
56
|
const dependencies = /* @__PURE__ */ new Set();
|
|
58
57
|
try {
|
|
59
|
-
const
|
|
60
|
-
traverse$1(babel.parseSync(code, {
|
|
58
|
+
const ast = parseSync("expression.js", `(${expression})`, {
|
|
61
59
|
sourceType: "module",
|
|
62
|
-
|
|
63
|
-
})
|
|
64
|
-
|
|
65
|
-
const name = path.node.name;
|
|
66
|
-
if (KEYWORDS.has(name)) return;
|
|
67
|
-
const parent = path.parent;
|
|
68
|
-
if (parent.type === "MemberExpression" && parent.property === path.node && !parent.computed) return;
|
|
69
|
-
if (parent.type === "CallExpression" && parent.callee === path.node) {
|
|
70
|
-
dependencies.add(name);
|
|
71
|
-
return;
|
|
72
|
-
}
|
|
73
|
-
if (parent.type === "ObjectProperty" && parent.key === path.node && !parent.computed) return;
|
|
74
|
-
dependencies.add(name);
|
|
75
|
-
},
|
|
76
|
-
MemberExpression(path) {
|
|
77
|
-
let root = path.node.object;
|
|
78
|
-
while (root.type === "MemberExpression") root = root.object;
|
|
79
|
-
if (root.type === "Identifier" && !KEYWORDS.has(root.name)) dependencies.add(root.name);
|
|
80
|
-
path.skip();
|
|
81
|
-
}
|
|
82
|
-
});
|
|
60
|
+
lang: "js"
|
|
61
|
+
}).program;
|
|
62
|
+
visitExpressionAst(ast, null, dependencies);
|
|
83
63
|
} catch (error) {
|
|
84
64
|
console.warn("[expression-parser] AST 解析失败,表达式:", expression, "错误:", error.message);
|
|
85
65
|
return [];
|
|
86
66
|
}
|
|
87
67
|
return Array.from(dependencies);
|
|
88
68
|
}
|
|
69
|
+
function visitExpressionAst(node, parent, dependencies) {
|
|
70
|
+
if (!node || typeof node !== "object") return;
|
|
71
|
+
if (node.type === "Identifier") {
|
|
72
|
+
collectIdentifier(node, parent, dependencies);
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
if (node.type === "MemberExpression") {
|
|
76
|
+
let root = node.object;
|
|
77
|
+
while (root?.type === "MemberExpression" || root?.type === "ChainExpression") root = root.type === "ChainExpression" ? root.expression : root.object;
|
|
78
|
+
if (root?.type === "Identifier" && !KEYWORDS.has(root.name)) dependencies.add(root.name);
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
for (const [key, value] of Object.entries(node)) {
|
|
82
|
+
if (key === "type" || key === "start" || key === "end" || key === "loc") continue;
|
|
83
|
+
if (Array.isArray(value)) for (const child of value) visitExpressionAst(child, node, dependencies);
|
|
84
|
+
else visitExpressionAst(value, node, dependencies);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
function collectIdentifier(node, parent, dependencies) {
|
|
88
|
+
const name = node.name;
|
|
89
|
+
if (KEYWORDS.has(name)) return;
|
|
90
|
+
if (parent?.type === "MemberExpression" && parent.property === node && !parent.computed) return;
|
|
91
|
+
if (parent?.type === "Property" && parent.key === node && !parent.computed && !parent.shorthand) return;
|
|
92
|
+
dependencies.add(name);
|
|
93
|
+
}
|
|
89
94
|
/**
|
|
90
95
|
* 解析表达式并生成依赖路径信息
|
|
91
96
|
* @param {string} expression - 表达式字符串
|
|
@@ -118,20 +123,53 @@ function parseBindings(bindings) {
|
|
|
118
123
|
}
|
|
119
124
|
//#endregion
|
|
120
125
|
//#region src/core/view-compiler.js
|
|
121
|
-
var traverse = _traverse.default ? _traverse.default : _traverse;
|
|
122
|
-
var generateCode = generate.default ? generate.default : generate;
|
|
123
126
|
var fileType = [".wxml", ".ddml"];
|
|
124
127
|
/**
|
|
125
|
-
*
|
|
126
|
-
* @param {
|
|
127
|
-
* @
|
|
128
|
+
* 解析 JavaScript 代码
|
|
129
|
+
* @param {string} code
|
|
130
|
+
* @param {string} filename
|
|
131
|
+
* @param {'module'|'script'} sourceType
|
|
132
|
+
* @returns {*} Oxc Program AST
|
|
128
133
|
*/
|
|
129
|
-
function
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
}
|
|
134
|
-
|
|
134
|
+
function parseJs(code, filename = "view-compiler.js", sourceType = "module") {
|
|
135
|
+
return parseSync(filename, code, {
|
|
136
|
+
sourceType,
|
|
137
|
+
lang: "js"
|
|
138
|
+
}).program;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* 如果顶层是单个表达式语句,则只返回表达式源码
|
|
142
|
+
* @param {string} code
|
|
143
|
+
* @param {*} ast - Oxc Program AST
|
|
144
|
+
* @returns {string} Program code or the source of the single top-level expression.
|
|
145
|
+
*/
|
|
146
|
+
function getProgramCode(code, ast) {
|
|
147
|
+
const statement = ast.body?.[0];
|
|
148
|
+
if (ast.body?.length === 1 && statement?.type === "ExpressionStatement") return code.slice(statement.expression.start, statement.expression.end);
|
|
149
|
+
return code;
|
|
150
|
+
}
|
|
151
|
+
function isStringLiteral(node) {
|
|
152
|
+
return node?.type === "StringLiteral" || node?.type === "Literal" && typeof node.value === "string";
|
|
153
|
+
}
|
|
154
|
+
function getStringLiteralRawValue(node) {
|
|
155
|
+
if (!isStringLiteral(node)) return "";
|
|
156
|
+
if (typeof node.raw === "string") return node.raw.slice(1, -1);
|
|
157
|
+
return String(node.value);
|
|
158
|
+
}
|
|
159
|
+
function getSource(code, node) {
|
|
160
|
+
return code.slice(node.start, node.end);
|
|
161
|
+
}
|
|
162
|
+
function applyCodeReplacements(source, replacements) {
|
|
163
|
+
if (replacements.length === 0) return source;
|
|
164
|
+
const selected = [];
|
|
165
|
+
const byLargestRange = [...replacements].sort((a, b) => {
|
|
166
|
+
return b.end - b.start - (a.end - a.start) || b.start - a.start;
|
|
167
|
+
});
|
|
168
|
+
for (const replacement of byLargestRange) if (!selected.some((item) => replacement.start < item.end && item.start < replacement.end)) selected.push(replacement);
|
|
169
|
+
const s = new MagicString(source);
|
|
170
|
+
for (const replacement of selected.sort((a, b) => b.start - a.start)) if (replacement.type === "insert") s.appendLeft(replacement.start, replacement.value);
|
|
171
|
+
else s.overwrite(replacement.start, replacement.end, replacement.value);
|
|
172
|
+
return s.toString();
|
|
135
173
|
}
|
|
136
174
|
/**
|
|
137
175
|
* 为模板表达式中的成员访问补充空值保护,避免生成的 render 函数直接访问 null/undefined 属性
|
|
@@ -142,12 +180,30 @@ function generateCodeFromAst(ast) {
|
|
|
142
180
|
function addOptionalChaining(expression) {
|
|
143
181
|
if (!expression || typeof expression !== "string") return expression;
|
|
144
182
|
try {
|
|
145
|
-
const
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
183
|
+
const code = `(${expression})`;
|
|
184
|
+
const ast = parseJs(code);
|
|
185
|
+
const insertions = [];
|
|
186
|
+
walk(ast, { enter(node) {
|
|
187
|
+
if (node.type !== "MemberExpression" || node.optional) return;
|
|
188
|
+
if (node.computed) {
|
|
189
|
+
const bracketIndex = code.lastIndexOf("[", node.property.start);
|
|
190
|
+
if (bracketIndex >= 0) insertions.push({
|
|
191
|
+
type: "insert",
|
|
192
|
+
start: bracketIndex,
|
|
193
|
+
end: bracketIndex,
|
|
194
|
+
value: "?."
|
|
195
|
+
});
|
|
196
|
+
} else {
|
|
197
|
+
const dotIndex = code.lastIndexOf(".", node.property.start);
|
|
198
|
+
if (dotIndex >= 0) insertions.push({
|
|
199
|
+
type: "insert",
|
|
200
|
+
start: dotIndex,
|
|
201
|
+
end: dotIndex,
|
|
202
|
+
value: "?"
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
} });
|
|
206
|
+
return applyCodeReplacements(code, insertions).slice(1, -1);
|
|
151
207
|
} catch (error) {
|
|
152
208
|
return expression;
|
|
153
209
|
}
|
|
@@ -385,15 +441,11 @@ function compileModule(module, isComponent, scriptRes, options = {}) {
|
|
|
385
441
|
inline: true
|
|
386
442
|
}
|
|
387
443
|
});
|
|
388
|
-
|
|
389
|
-
insertWxsToRenderAst(ast, compileInstruction.scriptModule, scriptRes);
|
|
390
|
-
code = generateCodeFromAst(ast);
|
|
444
|
+
code = insertWxsToRenderCode(code, compileInstruction.scriptModule, scriptRes, tm.path);
|
|
391
445
|
tplComponents += `'${tm.path}':${code},`;
|
|
392
446
|
}
|
|
393
447
|
tplComponents += "}";
|
|
394
|
-
const
|
|
395
|
-
insertWxsToRenderAst(tplAst, compileInstruction.scriptModule, scriptRes);
|
|
396
|
-
const transCode = generateCodeFromAst(tplAst);
|
|
448
|
+
const transCode = insertWxsToRenderCode(tplCode.code, compileInstruction.scriptModule, scriptRes, module.path);
|
|
397
449
|
const code = `Module({
|
|
398
450
|
path: '${module.path}',
|
|
399
451
|
id: '${module.id}',
|
|
@@ -430,44 +482,42 @@ function compileModule(module, isComponent, scriptRes, options = {}) {
|
|
|
430
482
|
function processWxsContent(wxsContent, wxsFilePath, scriptModule, workPath, filePath) {
|
|
431
483
|
let wxsAst;
|
|
432
484
|
try {
|
|
433
|
-
wxsAst =
|
|
485
|
+
wxsAst = parseJs(wxsContent, wxsFilePath || "inline.wxs", "script");
|
|
434
486
|
} catch (error) {
|
|
435
487
|
console.error(`[view] 解析 wxs 文件失败: ${wxsFilePath}`, error.message);
|
|
436
488
|
return wxsContent;
|
|
437
489
|
}
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
490
|
+
const replacements = [];
|
|
491
|
+
walk(wxsAst, { enter(node) {
|
|
492
|
+
if (node.type === "CallExpression") {
|
|
493
|
+
const calleeName = node.callee?.name;
|
|
441
494
|
if (calleeName === "getRegExp") {
|
|
442
|
-
const args =
|
|
443
|
-
if (args.length > 0) if (args[0]
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
const flagArg = args[1];
|
|
452
|
-
if (flagArg.extra && flagArg.extra.raw) flags = flagArg.extra.raw.slice(1, -1);
|
|
453
|
-
else if (flagArg.value !== void 0) flags = flagArg.value;
|
|
454
|
-
else flags = "";
|
|
455
|
-
}
|
|
456
|
-
const regexLiteral = types.regExpLiteral(pattern, flags);
|
|
457
|
-
astPath.replaceWith(regexLiteral);
|
|
495
|
+
const args = node.arguments;
|
|
496
|
+
if (args.length > 0) if (isStringLiteral(args[0]) && (!args[1] || isStringLiteral(args[1]))) {
|
|
497
|
+
const pattern = getStringLiteralRawValue(args[0]);
|
|
498
|
+
const flags = args.length > 1 ? getStringLiteralRawValue(args[1]) : "";
|
|
499
|
+
replacements.push({
|
|
500
|
+
start: node.start,
|
|
501
|
+
end: node.end,
|
|
502
|
+
value: `/${pattern}/${flags}`
|
|
503
|
+
});
|
|
458
504
|
} else {
|
|
459
|
-
const newRegExpArgs =
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
505
|
+
const newRegExpArgs = args.map((arg) => getSource(wxsContent, arg)).join(", ");
|
|
506
|
+
replacements.push({
|
|
507
|
+
start: node.start,
|
|
508
|
+
end: node.end,
|
|
509
|
+
value: `new RegExp(${newRegExpArgs})`
|
|
510
|
+
});
|
|
463
511
|
}
|
|
464
512
|
} else if (calleeName === "getDate") {
|
|
465
|
-
const args =
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
513
|
+
const args = node.arguments.map((arg) => getSource(wxsContent, arg)).join(", ");
|
|
514
|
+
replacements.push({
|
|
515
|
+
start: node.start,
|
|
516
|
+
end: node.end,
|
|
517
|
+
value: `new Date(${args})`
|
|
518
|
+
});
|
|
519
|
+
} else if (calleeName === "require" && node.arguments.length > 0 && wxsFilePath) {
|
|
520
|
+
const requirePath = node.arguments[0].value;
|
|
471
521
|
if (requirePath && typeof requirePath === "string") {
|
|
472
522
|
let resolvedWxsPath;
|
|
473
523
|
if (filePath && filePath.includes("/miniprogram_npm/")) {
|
|
@@ -475,25 +525,37 @@ function processWxsContent(wxsContent, wxsFilePath, scriptModule, workPath, file
|
|
|
475
525
|
resolvedWxsPath = path.resolve(currentWxsDir, requirePath);
|
|
476
526
|
const moduleName = resolvedWxsPath.replace(workPath, "").replace(/\.wxs$/, "").replace(/[\/\\@\-]/g, "_").replace(/^_/, "");
|
|
477
527
|
processWxsDependency(resolvedWxsPath, moduleName, scriptModule, workPath, filePath);
|
|
478
|
-
|
|
528
|
+
replacements.push({
|
|
529
|
+
start: node.arguments[0].start,
|
|
530
|
+
end: node.arguments[0].end,
|
|
531
|
+
value: JSON.stringify(moduleName)
|
|
532
|
+
});
|
|
479
533
|
} else {
|
|
480
534
|
const currentWxsDir = path.dirname(wxsFilePath);
|
|
481
535
|
resolvedWxsPath = path.resolve(currentWxsDir, requirePath);
|
|
482
536
|
const depModuleName = resolvedWxsPath.replace(workPath, "").replace(/\.wxs$/, "").replace(/[\/\\@\-]/g, "_").replace(/^_/, "");
|
|
483
537
|
processWxsDependency(resolvedWxsPath, depModuleName, scriptModule, workPath, filePath);
|
|
484
|
-
|
|
538
|
+
replacements.push({
|
|
539
|
+
start: node.arguments[0].start,
|
|
540
|
+
end: node.arguments[0].end,
|
|
541
|
+
value: JSON.stringify(depModuleName)
|
|
542
|
+
});
|
|
485
543
|
}
|
|
486
544
|
}
|
|
487
545
|
}
|
|
488
|
-
}
|
|
489
|
-
MemberExpression
|
|
490
|
-
if (
|
|
491
|
-
const
|
|
492
|
-
|
|
546
|
+
}
|
|
547
|
+
if (node.type === "MemberExpression") {
|
|
548
|
+
if (node.property?.name === "constructor" && !node.computed) {
|
|
549
|
+
const objectCode = getSource(wxsContent, node.object);
|
|
550
|
+
replacements.push({
|
|
551
|
+
start: node.start,
|
|
552
|
+
end: node.end,
|
|
553
|
+
value: `Object.prototype.toString.call(${objectCode}).slice(8, -1)`
|
|
554
|
+
});
|
|
493
555
|
}
|
|
494
556
|
}
|
|
495
|
-
});
|
|
496
|
-
return
|
|
557
|
+
} });
|
|
558
|
+
return applyCodeReplacements(wxsContent, replacements);
|
|
497
559
|
}
|
|
498
560
|
/**
|
|
499
561
|
* 通过代码内容判断是否为 wxs 模块
|
|
@@ -523,9 +585,9 @@ function processWxsDependency(wxsFilePath, moduleName, scriptModule, workPath, f
|
|
|
523
585
|
}
|
|
524
586
|
/**
|
|
525
587
|
* 重新编译模块,包含所有收集到的 wxs 模块
|
|
526
|
-
* @param {*} module
|
|
527
|
-
* @param {*} scriptRes
|
|
528
|
-
* @param {*} allScriptModules
|
|
588
|
+
* @param {*} module
|
|
589
|
+
* @param {*} scriptRes
|
|
590
|
+
* @param {*} allScriptModules
|
|
529
591
|
*/
|
|
530
592
|
function compileModuleWithAllWxs(module, scriptRes, allScriptModules) {
|
|
531
593
|
const { tpl, instruction } = toCompileTemplate(false, module.path, module.usingComponents, module.componentPlaceholder);
|
|
@@ -564,15 +626,11 @@ function compileModuleWithAllWxs(module, scriptRes, allScriptModules) {
|
|
|
564
626
|
inline: true
|
|
565
627
|
}
|
|
566
628
|
});
|
|
567
|
-
|
|
568
|
-
insertWxsToRenderAst(ast, allScriptModules, scriptRes);
|
|
569
|
-
code = generateCodeFromAst(ast);
|
|
629
|
+
code = insertWxsToRenderCode(code, allScriptModules, scriptRes, tm.path);
|
|
570
630
|
tplComponents += `'${tm.path}':${code},`;
|
|
571
631
|
}
|
|
572
632
|
tplComponents += "}";
|
|
573
|
-
const
|
|
574
|
-
insertWxsToRenderAst(tplAst, allScriptModules, scriptRes);
|
|
575
|
-
const transCode = generateCodeFromAst(tplAst);
|
|
633
|
+
const transCode = insertWxsToRenderCode(tplCode.code, allScriptModules, scriptRes, module.path);
|
|
576
634
|
const code = `Module({
|
|
577
635
|
path: '${module.path}',
|
|
578
636
|
id: '${module.id}',
|
|
@@ -659,13 +717,17 @@ function toCompileTemplate(isComponent, path, components, componentPlaceholder,
|
|
|
659
717
|
const workPath = getWorkPath();
|
|
660
718
|
const fullPath = getViewPath(workPath, path);
|
|
661
719
|
if (!fullPath) return { tpl: void 0 };
|
|
720
|
+
const diagnosticSource = fullPath.startsWith(workPath) ? fullPath.slice(workPath.length) : path;
|
|
662
721
|
let content = getContentByPath(fullPath).trim();
|
|
663
722
|
if (!content) content = "<block></block>";
|
|
664
|
-
else
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
723
|
+
else {
|
|
724
|
+
checkTemplateCompatibility(content, diagnosticSource, components);
|
|
725
|
+
if (isComponent) content = `<wrapper name="${path}">${content}</wrapper>`;
|
|
726
|
+
else if (cheerio.load(content, {
|
|
727
|
+
xmlMode: true,
|
|
728
|
+
decodeEntities: false
|
|
729
|
+
}).root().children().toArray().filter((node) => node.type !== "comment").length > 1) content = `<view>${content}</view>`;
|
|
730
|
+
}
|
|
669
731
|
const templateModule = [];
|
|
670
732
|
const scriptModule = [];
|
|
671
733
|
const $ = cheerio.load(content, {
|
|
@@ -680,9 +742,11 @@ function toCompileTemplate(isComponent, path, components, componentPlaceholder,
|
|
|
680
742
|
if (src) {
|
|
681
743
|
const includeFullPath = getAbsolutePath(workPath, path, src);
|
|
682
744
|
let includePath = includeFullPath.replace(workPath, "").replace(/\.(wxml|ddml)$/, "");
|
|
745
|
+
const includeDiagnosticSource = includeFullPath.startsWith(workPath) ? includeFullPath.slice(workPath.length) : includePath;
|
|
683
746
|
if (!includePath.startsWith("/")) includePath = "/" + includePath;
|
|
684
747
|
const includeContent = getContentByPath(includeFullPath).trim();
|
|
685
748
|
if (includeContent) {
|
|
749
|
+
checkTemplateCompatibility(includeContent, includeDiagnosticSource, components);
|
|
686
750
|
const $includeContent = cheerio.load(includeContent, {
|
|
687
751
|
xmlMode: true,
|
|
688
752
|
decodeEntities: false
|
|
@@ -706,9 +770,11 @@ function toCompileTemplate(isComponent, path, components, componentPlaceholder,
|
|
|
706
770
|
if (src) {
|
|
707
771
|
const importFullPath = getAbsolutePath(workPath, path, src);
|
|
708
772
|
let importPath = importFullPath.replace(workPath, "").replace(/\.(wxml|ddml)$/, "");
|
|
773
|
+
const importDiagnosticSource = importFullPath.startsWith(workPath) ? importFullPath.slice(workPath.length) : importPath;
|
|
709
774
|
if (!importPath.startsWith("/")) importPath = "/" + importPath;
|
|
710
775
|
const importContent = getContentByPath(importFullPath).trim();
|
|
711
776
|
if (importContent) {
|
|
777
|
+
checkTemplateCompatibility(importContent, importDiagnosticSource, components);
|
|
712
778
|
const $$ = cheerio.load(importContent, {
|
|
713
779
|
xmlMode: true,
|
|
714
780
|
decodeEntities: false
|
|
@@ -826,7 +892,7 @@ function transTag(opts) {
|
|
|
826
892
|
}
|
|
827
893
|
/**
|
|
828
894
|
* 处理动态slot指令生成,比如 slot="{{xxx}}"
|
|
829
|
-
*
|
|
895
|
+
*
|
|
830
896
|
* @param {string} slotValue - slot属性值
|
|
831
897
|
* @returns {string} 生成的slot指令
|
|
832
898
|
*/
|
|
@@ -1241,28 +1307,43 @@ function extractWxsDependencies(moduleCode) {
|
|
|
1241
1307
|
}
|
|
1242
1308
|
return dependencies;
|
|
1243
1309
|
}
|
|
1244
|
-
function
|
|
1245
|
-
const
|
|
1310
|
+
function insertWxsToRenderCode(code, scriptModule, scriptRes, filename = "render.js") {
|
|
1311
|
+
const wxsBindings = [];
|
|
1312
|
+
const codeReplacements = [];
|
|
1313
|
+
const ast = parseJs(code, filename);
|
|
1314
|
+
const statement = ast.body?.[0];
|
|
1315
|
+
const renderBody = (statement?.type === "ExpressionStatement" ? statement.expression : null)?.body;
|
|
1316
|
+
const declarations = [];
|
|
1246
1317
|
for (const [index, sm] of scriptModule.entries()) {
|
|
1247
1318
|
if (!scriptRes.has(sm.path)) scriptRes.set(sm.path, sm.code);
|
|
1248
1319
|
const templatePropertyName = sm.originalName || sm.path;
|
|
1249
1320
|
const requireModuleName = sm.path;
|
|
1250
1321
|
const localIdentifier = `__wxs_${index}`;
|
|
1251
|
-
|
|
1322
|
+
wxsBindings.push({
|
|
1252
1323
|
localIdentifier,
|
|
1253
1324
|
templatePropertyName
|
|
1254
1325
|
});
|
|
1255
|
-
|
|
1256
|
-
ast.program.body[0].expression.body.body.unshift(variableDeclaration);
|
|
1326
|
+
declarations.push(`const ${localIdentifier} = require(${JSON.stringify(requireModuleName)});`);
|
|
1257
1327
|
}
|
|
1258
|
-
if (
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1328
|
+
if (wxsBindings.length === 0) return getProgramCode(code, ast);
|
|
1329
|
+
if (renderBody?.type === "BlockStatement") codeReplacements.push({
|
|
1330
|
+
type: "insert",
|
|
1331
|
+
start: renderBody.start + 1,
|
|
1332
|
+
end: renderBody.start + 1,
|
|
1333
|
+
value: `\n${declarations.join("\n")}`
|
|
1334
|
+
});
|
|
1335
|
+
walk(ast, { enter(node) {
|
|
1336
|
+
if (node.type === "MemberExpression" && node.object?.type === "Identifier" && node.object.name === "_ctx" && !node.computed && node.property?.type === "Identifier") {
|
|
1337
|
+
const replacement = wxsBindings.find((item) => item.templatePropertyName === node.property.name);
|
|
1338
|
+
if (replacement) codeReplacements.push({
|
|
1339
|
+
start: node.start,
|
|
1340
|
+
end: node.end,
|
|
1341
|
+
value: replacement.localIdentifier
|
|
1342
|
+
});
|
|
1264
1343
|
}
|
|
1265
1344
|
} });
|
|
1345
|
+
const transformed = applyCodeReplacements(code, codeReplacements);
|
|
1346
|
+
return getProgramCode(transformed, parseJs(transformed, filename));
|
|
1266
1347
|
}
|
|
1267
1348
|
//#endregion
|
|
1268
1349
|
export { compileML, generateSlotDirective, generateVModelTemplate, parseBraceExp, parseClassRules, parseKeyExpression, parseTemplateDataExp, processIncludeConditionalAttrs, processWxsContent, splitWithBraces };
|
package/dist/index.cjs
CHANGED
|
@@ -274,12 +274,33 @@ var NpmBuilder = class {
|
|
|
274
274
|
//#endregion
|
|
275
275
|
//#region src/core/config-compiler.js
|
|
276
276
|
/**
|
|
277
|
+
* 处理 tabBar.list 中的 iconPath / selectedIconPath。
|
|
278
|
+
* 视为相对小程序根目录的资源,复用 collectAssets 拷贝到 main/static/,
|
|
279
|
+
* 并把 list 中的路径改写成产物 URL,避免容器侧再做特殊解析。
|
|
280
|
+
*
|
|
281
|
+
* 注意:会在原 app 配置上原地修改,不影响后续输出(compileConfig 是
|
|
282
|
+
* 整个流水线最后才走到的环节,不会被再次读取)。
|
|
283
|
+
*/
|
|
284
|
+
function processTabBarIcons(app) {
|
|
285
|
+
const list = app?.tabBar?.list;
|
|
286
|
+
if (!Array.isArray(list) || list.length === 0) return;
|
|
287
|
+
const workPath = require_env.getWorkPath();
|
|
288
|
+
const targetPath = require_env.getTargetPath();
|
|
289
|
+
const appId = require_env.getAppId();
|
|
290
|
+
for (const item of list) {
|
|
291
|
+
if (item.iconPath) item.iconPath = require_env.collectAssets(workPath, "", item.iconPath, targetPath, appId);
|
|
292
|
+
if (item.selectedIconPath) item.selectedIconPath = require_env.collectAssets(workPath, "", item.selectedIconPath, targetPath, appId);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
277
296
|
*
|
|
278
297
|
* 编译项目配置文件 app-config.json
|
|
279
298
|
*/
|
|
280
299
|
function compileConfig() {
|
|
300
|
+
const app = require_env.getAppConfigInfo();
|
|
301
|
+
processTabBarIcons(app);
|
|
281
302
|
const compileResInfo = {
|
|
282
|
-
app
|
|
303
|
+
app,
|
|
283
304
|
modules: require_env.getPageConfigInfo(),
|
|
284
305
|
projectName: require_env.getAppName()
|
|
285
306
|
};
|
|
@@ -297,7 +318,8 @@ var isPrinted = false;
|
|
|
297
318
|
* @param {string} workPath 编译工作目录
|
|
298
319
|
* @param {boolean} useAppIdDir 产物根目录是否包含appId
|
|
299
320
|
*/
|
|
300
|
-
async function build(targetPath, workPath, useAppIdDir = true) {
|
|
321
|
+
async function build(targetPath, workPath, useAppIdDir = true, options = {}) {
|
|
322
|
+
const { sourcemap = false } = options;
|
|
301
323
|
if (!isPrinted) {
|
|
302
324
|
require_env.art_default();
|
|
303
325
|
isPrinted = true;
|
|
@@ -341,13 +363,13 @@ async function build(targetPath, workPath, useAppIdDir = true) {
|
|
|
341
363
|
{
|
|
342
364
|
title: "编译页面文件",
|
|
343
365
|
task: async (ctx, task) => {
|
|
344
|
-
return runCompileInWorker("view", ctx, task);
|
|
366
|
+
return runCompileInWorker("view", ctx, task, { sourcemap });
|
|
345
367
|
}
|
|
346
368
|
},
|
|
347
369
|
{
|
|
348
370
|
title: "编译页面逻辑",
|
|
349
371
|
task: async (ctx, task) => {
|
|
350
|
-
return runCompileInWorker("logic", ctx, task);
|
|
372
|
+
return runCompileInWorker("logic", ctx, task, { sourcemap });
|
|
351
373
|
}
|
|
352
374
|
},
|
|
353
375
|
{
|
|
@@ -357,7 +379,7 @@ async function build(targetPath, workPath, useAppIdDir = true) {
|
|
|
357
379
|
path: "app",
|
|
358
380
|
id: ""
|
|
359
381
|
});
|
|
360
|
-
return runCompileInWorker("style", ctx, task);
|
|
382
|
+
return runCompileInWorker("style", ctx, task, { sourcemap });
|
|
361
383
|
}
|
|
362
384
|
}
|
|
363
385
|
], { concurrent: true });
|
|
@@ -381,7 +403,7 @@ async function build(targetPath, workPath, useAppIdDir = true) {
|
|
|
381
403
|
console.error(`${workPath} 编译出错: ${e.message}\n${e.stack}`);
|
|
382
404
|
}
|
|
383
405
|
}
|
|
384
|
-
function runCompileInWorker(script, ctx, task) {
|
|
406
|
+
function runCompileInWorker(script, ctx, task, options = {}) {
|
|
385
407
|
return workerPool.runWorker(() => new Promise((resolve, reject) => {
|
|
386
408
|
const worker = new node_worker_threads.Worker(node_path.default.join(node_path.default.dirname((0, node_url.fileURLToPath)(require("url").pathToFileURL(__filename).href)), `core/${script}-compiler.js`), workerPool.getWorkerOptions());
|
|
387
409
|
const totalTasks = Object.keys(ctx.pages.mainPages).length + Object.values(ctx.pages.subPages).reduce((sum, item) => sum + item.info.length, 0);
|
|
@@ -395,7 +417,8 @@ function runCompileInWorker(script, ctx, task) {
|
|
|
395
417
|
};
|
|
396
418
|
worker.postMessage({
|
|
397
419
|
pages: ctx.pages,
|
|
398
|
-
storeInfo: ctx.storeInfo
|
|
420
|
+
storeInfo: ctx.storeInfo,
|
|
421
|
+
sourcemap: !!options.sourcemap
|
|
399
422
|
});
|
|
400
423
|
worker.on("message", (message) => {
|
|
401
424
|
try {
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { c as getPages, l as getTargetPath, n as getAppId, p as storeInfo, r as getAppName, s as getPageConfigInfo, t as getAppConfigInfo, u as getWorkPath, y as art_default } from "./env-DgCLbrQb.js";
|
|
1
|
+
import { c as getPages, l as getTargetPath, m as collectAssets, n as getAppId, p as storeInfo, r as getAppName, s as getPageConfigInfo, t as getAppConfigInfo, u as getWorkPath, y as art_default } from "./env-DgCLbrQb.js";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
4
|
import { Worker } from "node:worker_threads";
|
|
@@ -270,12 +270,33 @@ var NpmBuilder = class {
|
|
|
270
270
|
//#endregion
|
|
271
271
|
//#region src/core/config-compiler.js
|
|
272
272
|
/**
|
|
273
|
+
* 处理 tabBar.list 中的 iconPath / selectedIconPath。
|
|
274
|
+
* 视为相对小程序根目录的资源,复用 collectAssets 拷贝到 main/static/,
|
|
275
|
+
* 并把 list 中的路径改写成产物 URL,避免容器侧再做特殊解析。
|
|
276
|
+
*
|
|
277
|
+
* 注意:会在原 app 配置上原地修改,不影响后续输出(compileConfig 是
|
|
278
|
+
* 整个流水线最后才走到的环节,不会被再次读取)。
|
|
279
|
+
*/
|
|
280
|
+
function processTabBarIcons(app) {
|
|
281
|
+
const list = app?.tabBar?.list;
|
|
282
|
+
if (!Array.isArray(list) || list.length === 0) return;
|
|
283
|
+
const workPath = getWorkPath();
|
|
284
|
+
const targetPath = getTargetPath();
|
|
285
|
+
const appId = getAppId();
|
|
286
|
+
for (const item of list) {
|
|
287
|
+
if (item.iconPath) item.iconPath = collectAssets(workPath, "", item.iconPath, targetPath, appId);
|
|
288
|
+
if (item.selectedIconPath) item.selectedIconPath = collectAssets(workPath, "", item.selectedIconPath, targetPath, appId);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
273
292
|
*
|
|
274
293
|
* 编译项目配置文件 app-config.json
|
|
275
294
|
*/
|
|
276
295
|
function compileConfig() {
|
|
296
|
+
const app = getAppConfigInfo();
|
|
297
|
+
processTabBarIcons(app);
|
|
277
298
|
const compileResInfo = {
|
|
278
|
-
app
|
|
299
|
+
app,
|
|
279
300
|
modules: getPageConfigInfo(),
|
|
280
301
|
projectName: getAppName()
|
|
281
302
|
};
|
|
@@ -293,7 +314,8 @@ var isPrinted = false;
|
|
|
293
314
|
* @param {string} workPath 编译工作目录
|
|
294
315
|
* @param {boolean} useAppIdDir 产物根目录是否包含appId
|
|
295
316
|
*/
|
|
296
|
-
async function build(targetPath, workPath, useAppIdDir = true) {
|
|
317
|
+
async function build(targetPath, workPath, useAppIdDir = true, options = {}) {
|
|
318
|
+
const { sourcemap = false } = options;
|
|
297
319
|
if (!isPrinted) {
|
|
298
320
|
art_default();
|
|
299
321
|
isPrinted = true;
|
|
@@ -337,13 +359,13 @@ async function build(targetPath, workPath, useAppIdDir = true) {
|
|
|
337
359
|
{
|
|
338
360
|
title: "编译页面文件",
|
|
339
361
|
task: async (ctx, task) => {
|
|
340
|
-
return runCompileInWorker("view", ctx, task);
|
|
362
|
+
return runCompileInWorker("view", ctx, task, { sourcemap });
|
|
341
363
|
}
|
|
342
364
|
},
|
|
343
365
|
{
|
|
344
366
|
title: "编译页面逻辑",
|
|
345
367
|
task: async (ctx, task) => {
|
|
346
|
-
return runCompileInWorker("logic", ctx, task);
|
|
368
|
+
return runCompileInWorker("logic", ctx, task, { sourcemap });
|
|
347
369
|
}
|
|
348
370
|
},
|
|
349
371
|
{
|
|
@@ -353,7 +375,7 @@ async function build(targetPath, workPath, useAppIdDir = true) {
|
|
|
353
375
|
path: "app",
|
|
354
376
|
id: ""
|
|
355
377
|
});
|
|
356
|
-
return runCompileInWorker("style", ctx, task);
|
|
378
|
+
return runCompileInWorker("style", ctx, task, { sourcemap });
|
|
357
379
|
}
|
|
358
380
|
}
|
|
359
381
|
], { concurrent: true });
|
|
@@ -377,7 +399,7 @@ async function build(targetPath, workPath, useAppIdDir = true) {
|
|
|
377
399
|
console.error(`${workPath} 编译出错: ${e.message}\n${e.stack}`);
|
|
378
400
|
}
|
|
379
401
|
}
|
|
380
|
-
function runCompileInWorker(script, ctx, task) {
|
|
402
|
+
function runCompileInWorker(script, ctx, task, options = {}) {
|
|
381
403
|
return workerPool.runWorker(() => new Promise((resolve, reject) => {
|
|
382
404
|
const worker = new Worker(path.join(path.dirname(fileURLToPath(import.meta.url)), `core/${script}-compiler.js`), workerPool.getWorkerOptions());
|
|
383
405
|
const totalTasks = Object.keys(ctx.pages.mainPages).length + Object.values(ctx.pages.subPages).reduce((sum, item) => sum + item.info.length, 0);
|
|
@@ -391,7 +413,8 @@ function runCompileInWorker(script, ctx, task) {
|
|
|
391
413
|
};
|
|
392
414
|
worker.postMessage({
|
|
393
415
|
pages: ctx.pages,
|
|
394
|
-
storeInfo: ctx.storeInfo
|
|
416
|
+
storeInfo: ctx.storeInfo,
|
|
417
|
+
sourcemap: !!options.sourcemap
|
|
395
418
|
});
|
|
396
419
|
worker.on("message", (message) => {
|
|
397
420
|
try {
|