@weapp-vite/web 1.3.4 → 1.3.6
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/index-w9xxIH-l.d.mts +1229 -0
- package/dist/index.d.mts +3 -11316
- package/dist/index.mjs +2 -7798
- package/dist/plugin-CsqbKOh1.mjs +1555 -0
- package/dist/plugin-DP2iPVmw.d.mts +96 -0
- package/dist/plugin.d.mts +2 -10085
- package/dist/plugin.mjs +1 -1554
- package/dist/runtime/index.d.mts +2 -1229
- package/dist/runtime/index.mjs +1 -6250
- package/dist/runtime-xs_hRUwz.mjs +6247 -0
- package/dist/slugify-B4l45KNs.mjs +6 -0
- package/package.json +4 -4
package/dist/plugin.mjs
CHANGED
|
@@ -1,1555 +1,2 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { dirname, extname, join, normalize, posix, relative, resolve } from "pathe";
|
|
3
|
-
import { readFileSync } from "node:fs";
|
|
4
|
-
import { parseDocument } from "htmlparser2";
|
|
5
|
-
import fs from "fs-extra";
|
|
6
|
-
import { parse } from "@babel/parser";
|
|
7
|
-
import _babelTraverse from "@babel/traverse";
|
|
8
|
-
import * as t from "@babel/types";
|
|
9
|
-
import MagicString from "magic-string";
|
|
10
|
-
import { bundleRequire } from "rolldown-require";
|
|
11
|
-
//#region src/compiler/wxml/dependency.ts
|
|
12
|
-
function createDependencyContext() {
|
|
13
|
-
return {
|
|
14
|
-
warnings: [],
|
|
15
|
-
dependencies: [],
|
|
16
|
-
dependencySet: /* @__PURE__ */ new Set(),
|
|
17
|
-
visited: /* @__PURE__ */ new Set(),
|
|
18
|
-
active: /* @__PURE__ */ new Set(),
|
|
19
|
-
circularWarnings: /* @__PURE__ */ new Set()
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
|
-
function addDependency(value, context, direct) {
|
|
23
|
-
if (!context.dependencySet.has(value)) {
|
|
24
|
-
context.dependencySet.add(value);
|
|
25
|
-
context.dependencies.push(value);
|
|
26
|
-
direct?.push(value);
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
function warnReadTemplate(context, target) {
|
|
30
|
-
context.warnings.push(`[web] 无法读取模板依赖: ${target}`);
|
|
31
|
-
}
|
|
32
|
-
function warnCircularTemplate(context, from, target) {
|
|
33
|
-
const key = `${from}=>${target}`;
|
|
34
|
-
if (context.circularWarnings.has(key)) return;
|
|
35
|
-
context.circularWarnings.add(key);
|
|
36
|
-
context.warnings.push(`[web] WXML 循环引用: ${from} -> ${target}`);
|
|
37
|
-
}
|
|
38
|
-
//#endregion
|
|
39
|
-
//#region src/compiler/wxml/navigation.ts
|
|
40
|
-
const NAVIGATION_BAR_ATTRS = new Set([
|
|
41
|
-
"title",
|
|
42
|
-
"background-color",
|
|
43
|
-
"text-style",
|
|
44
|
-
"front-color",
|
|
45
|
-
"loading"
|
|
46
|
-
]);
|
|
47
|
-
function stripPageMetaNodes(nodes) {
|
|
48
|
-
const stripped = [];
|
|
49
|
-
for (const node of nodes) {
|
|
50
|
-
if (node.type === "element" && node.name === "page-meta") continue;
|
|
51
|
-
if (node.type === "element" && node.children?.length) {
|
|
52
|
-
const nextChildren = stripPageMetaNodes(node.children);
|
|
53
|
-
if (nextChildren !== node.children) {
|
|
54
|
-
stripped.push({
|
|
55
|
-
...node,
|
|
56
|
-
children: nextChildren
|
|
57
|
-
});
|
|
58
|
-
continue;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
stripped.push(node);
|
|
62
|
-
}
|
|
63
|
-
return stripped;
|
|
64
|
-
}
|
|
65
|
-
function pickNavigationBarAttrs(attribs) {
|
|
66
|
-
if (!attribs) return;
|
|
67
|
-
const picked = {};
|
|
68
|
-
for (const [key, value] of Object.entries(attribs)) if (NAVIGATION_BAR_ATTRS.has(key)) picked[key] = value;
|
|
69
|
-
return Object.keys(picked).length > 0 ? picked : void 0;
|
|
70
|
-
}
|
|
71
|
-
function findNavigationBarInPageMeta(node) {
|
|
72
|
-
const children = node.children ?? [];
|
|
73
|
-
for (const child of children) if (child.type === "element" && child.name === "navigation-bar") return child;
|
|
74
|
-
}
|
|
75
|
-
function extractNavigationBarFromPageMeta(nodes) {
|
|
76
|
-
let pageMetaIndex = -1;
|
|
77
|
-
let navigationBar;
|
|
78
|
-
for (let i = 0; i < nodes.length; i += 1) {
|
|
79
|
-
const node = nodes[i];
|
|
80
|
-
if (node.type === "element" && node.name === "page-meta") {
|
|
81
|
-
if (pageMetaIndex === -1) pageMetaIndex = i;
|
|
82
|
-
if (!navigationBar) navigationBar = findNavigationBarInPageMeta(node);
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
const warnings = [];
|
|
86
|
-
if (pageMetaIndex > 0) warnings.push("[web] page-meta 需要作为页面第一个节点,已忽略其位置约束。");
|
|
87
|
-
return {
|
|
88
|
-
nodes: pageMetaIndex === -1 ? nodes : stripPageMetaNodes(nodes),
|
|
89
|
-
attrs: navigationBar ? pickNavigationBarAttrs(navigationBar.attribs) : void 0,
|
|
90
|
-
warnings
|
|
91
|
-
};
|
|
92
|
-
}
|
|
93
|
-
function toAttributeValue(value) {
|
|
94
|
-
if (value == null) return;
|
|
95
|
-
if (typeof value === "string") return value;
|
|
96
|
-
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
97
|
-
}
|
|
98
|
-
function buildNavigationBarAttrs(config, overrides) {
|
|
99
|
-
const attrs = {};
|
|
100
|
-
if (config?.title !== void 0) {
|
|
101
|
-
const value = toAttributeValue(config.title);
|
|
102
|
-
if (value !== void 0) attrs.title = value;
|
|
103
|
-
}
|
|
104
|
-
if (config?.backgroundColor !== void 0) {
|
|
105
|
-
const value = toAttributeValue(config.backgroundColor);
|
|
106
|
-
if (value !== void 0) attrs["background-color"] = value;
|
|
107
|
-
}
|
|
108
|
-
if (config?.textStyle !== void 0) {
|
|
109
|
-
const value = toAttributeValue(config.textStyle);
|
|
110
|
-
if (value !== void 0) attrs["text-style"] = value;
|
|
111
|
-
}
|
|
112
|
-
if (config?.frontColor !== void 0) {
|
|
113
|
-
const value = toAttributeValue(config.frontColor);
|
|
114
|
-
if (value !== void 0) attrs["front-color"] = value;
|
|
115
|
-
}
|
|
116
|
-
if (config?.loading) attrs.loading = "true";
|
|
117
|
-
if (overrides) for (const [key, value] of Object.entries(overrides)) attrs[key] = value;
|
|
118
|
-
return attrs;
|
|
119
|
-
}
|
|
120
|
-
//#endregion
|
|
121
|
-
//#region src/compiler/wxml/parser.ts
|
|
122
|
-
function isRenderableNode(node) {
|
|
123
|
-
if (node.type === "directive" || node.type === "comment") return false;
|
|
124
|
-
if (node.type === "text") return (node.data ?? "").trim().length > 0;
|
|
125
|
-
return true;
|
|
126
|
-
}
|
|
127
|
-
function hasChildren(node) {
|
|
128
|
-
return Array.isArray(node.children);
|
|
129
|
-
}
|
|
130
|
-
function toRenderNode(node, children) {
|
|
131
|
-
if (node.type === "text") return {
|
|
132
|
-
type: "text",
|
|
133
|
-
data: node.data ?? ""
|
|
134
|
-
};
|
|
135
|
-
if (node.type === "tag" || node.type === "script" || node.type === "style") {
|
|
136
|
-
const element = node;
|
|
137
|
-
return {
|
|
138
|
-
type: "element",
|
|
139
|
-
name: element.name,
|
|
140
|
-
attribs: element.attribs ?? {},
|
|
141
|
-
children
|
|
142
|
-
};
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
function convertNode(node) {
|
|
146
|
-
if (!isRenderableNode(node)) return;
|
|
147
|
-
return toRenderNode(node, hasChildren(node) && node.children.length > 0 ? node.children.map((child) => convertNode(child)).filter((child) => Boolean(child)) : void 0);
|
|
148
|
-
}
|
|
149
|
-
function parseWxml(source) {
|
|
150
|
-
return (parseDocument(source, {
|
|
151
|
-
xmlMode: true,
|
|
152
|
-
decodeEntities: true,
|
|
153
|
-
recognizeSelfClosing: true
|
|
154
|
-
}).children ?? []).filter(isRenderableNode).map((node) => convertNode(node)).filter((node) => Boolean(node));
|
|
155
|
-
}
|
|
156
|
-
//#endregion
|
|
157
|
-
//#region src/shared/wxml.ts
|
|
158
|
-
const CONTROL_ATTRS = new Set([
|
|
159
|
-
"wx:if",
|
|
160
|
-
"wx:elif",
|
|
161
|
-
"wx:else",
|
|
162
|
-
"wx:for",
|
|
163
|
-
"wx:for-item",
|
|
164
|
-
"wx:for-index",
|
|
165
|
-
"wx:key"
|
|
166
|
-
]);
|
|
167
|
-
const EVENT_PREFIX_RE = /^(?:bind|catch|mut-bind|capture-bind|capture-catch)([\w-]+)$/;
|
|
168
|
-
const EVENT_KIND_ALIAS = { tap: "click" };
|
|
169
|
-
const SELF_CLOSING_TAGS = new Set([
|
|
170
|
-
"area",
|
|
171
|
-
"base",
|
|
172
|
-
"br",
|
|
173
|
-
"col",
|
|
174
|
-
"embed",
|
|
175
|
-
"hr",
|
|
176
|
-
"img",
|
|
177
|
-
"image",
|
|
178
|
-
"input",
|
|
179
|
-
"link",
|
|
180
|
-
"meta",
|
|
181
|
-
"param",
|
|
182
|
-
"source",
|
|
183
|
-
"track",
|
|
184
|
-
"wbr"
|
|
185
|
-
]);
|
|
186
|
-
function normalizeTagName(name) {
|
|
187
|
-
switch (name) {
|
|
188
|
-
case "view":
|
|
189
|
-
case "cover-view":
|
|
190
|
-
case "navigator":
|
|
191
|
-
case "scroll-view":
|
|
192
|
-
case "swiper":
|
|
193
|
-
case "swiper-item":
|
|
194
|
-
case "movable-area":
|
|
195
|
-
case "movable-view":
|
|
196
|
-
case "cover-image": return "div";
|
|
197
|
-
case "text":
|
|
198
|
-
case "icon": return "span";
|
|
199
|
-
case "image": return "img";
|
|
200
|
-
case "button": return "weapp-button";
|
|
201
|
-
case "input": return "input";
|
|
202
|
-
case "textarea": return "textarea";
|
|
203
|
-
case "form": return "form";
|
|
204
|
-
case "label": return "label";
|
|
205
|
-
case "picker":
|
|
206
|
-
case "picker-view": return "select";
|
|
207
|
-
case "block": return "#fragment";
|
|
208
|
-
case "slot": return "slot";
|
|
209
|
-
default: return name || "div";
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
function normalizeAttributeName(name) {
|
|
213
|
-
if (name === "class" || name === "style" || name.startsWith("data-")) return name;
|
|
214
|
-
if (name === "hover-class") return "data-hover-class";
|
|
215
|
-
return name.replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`);
|
|
216
|
-
}
|
|
217
|
-
//#endregion
|
|
218
|
-
//#region src/compiler/wxml/interpolation.ts
|
|
219
|
-
function parseInterpolations(value) {
|
|
220
|
-
const parts = [];
|
|
221
|
-
if (!value.includes("{{")) return [{
|
|
222
|
-
type: "text",
|
|
223
|
-
value
|
|
224
|
-
}];
|
|
225
|
-
let cursor = 0;
|
|
226
|
-
while (cursor < value.length) {
|
|
227
|
-
const start = value.indexOf("{{", cursor);
|
|
228
|
-
if (start === -1) {
|
|
229
|
-
parts.push({
|
|
230
|
-
type: "text",
|
|
231
|
-
value: value.slice(cursor)
|
|
232
|
-
});
|
|
233
|
-
break;
|
|
234
|
-
}
|
|
235
|
-
if (start > cursor) parts.push({
|
|
236
|
-
type: "text",
|
|
237
|
-
value: value.slice(cursor, start)
|
|
238
|
-
});
|
|
239
|
-
const end = value.indexOf("}}", start + 2);
|
|
240
|
-
if (end === -1) {
|
|
241
|
-
parts.push({
|
|
242
|
-
type: "text",
|
|
243
|
-
value: value.slice(start)
|
|
244
|
-
});
|
|
245
|
-
break;
|
|
246
|
-
}
|
|
247
|
-
const expr = value.slice(start + 2, end).trim();
|
|
248
|
-
if (expr) parts.push({
|
|
249
|
-
type: "expr",
|
|
250
|
-
value: expr
|
|
251
|
-
});
|
|
252
|
-
cursor = end + 2;
|
|
253
|
-
}
|
|
254
|
-
return parts;
|
|
255
|
-
}
|
|
256
|
-
function buildExpression(parts, scopeVar, wxsVar) {
|
|
257
|
-
if (parts.length === 0) return "\"\"";
|
|
258
|
-
if (parts.length === 1 && parts[0]?.type === "text") return JSON.stringify(parts[0].value);
|
|
259
|
-
if (parts.length === 1 && parts[0]?.type === "expr") return `ctx.eval(${JSON.stringify(parts[0].value)}, ${scopeVar}, ${wxsVar})`;
|
|
260
|
-
return `(${parts.map((part) => {
|
|
261
|
-
if (part.type === "text") return JSON.stringify(part.value);
|
|
262
|
-
return `ctx.eval(${JSON.stringify(part.value)}, ${scopeVar}, ${wxsVar})`;
|
|
263
|
-
}).join(" + ")})`;
|
|
264
|
-
}
|
|
265
|
-
function hasTopLevelColon(expression) {
|
|
266
|
-
let depth = 0;
|
|
267
|
-
let inSingleQuote = false;
|
|
268
|
-
let inDoubleQuote = false;
|
|
269
|
-
let inTemplate = false;
|
|
270
|
-
let escaped = false;
|
|
271
|
-
let sawTopLevelQuestion = false;
|
|
272
|
-
for (let index = 0; index < expression.length; index += 1) {
|
|
273
|
-
const char = expression[index];
|
|
274
|
-
if (inSingleQuote) {
|
|
275
|
-
if (escaped) {
|
|
276
|
-
escaped = false;
|
|
277
|
-
continue;
|
|
278
|
-
}
|
|
279
|
-
if (char === "\\") {
|
|
280
|
-
escaped = true;
|
|
281
|
-
continue;
|
|
282
|
-
}
|
|
283
|
-
if (char === "'") inSingleQuote = false;
|
|
284
|
-
continue;
|
|
285
|
-
}
|
|
286
|
-
if (inDoubleQuote) {
|
|
287
|
-
if (escaped) {
|
|
288
|
-
escaped = false;
|
|
289
|
-
continue;
|
|
290
|
-
}
|
|
291
|
-
if (char === "\\") {
|
|
292
|
-
escaped = true;
|
|
293
|
-
continue;
|
|
294
|
-
}
|
|
295
|
-
if (char === "\"") inDoubleQuote = false;
|
|
296
|
-
continue;
|
|
297
|
-
}
|
|
298
|
-
if (inTemplate) {
|
|
299
|
-
if (escaped) {
|
|
300
|
-
escaped = false;
|
|
301
|
-
continue;
|
|
302
|
-
}
|
|
303
|
-
if (char === "\\") {
|
|
304
|
-
escaped = true;
|
|
305
|
-
continue;
|
|
306
|
-
}
|
|
307
|
-
if (char === "`") inTemplate = false;
|
|
308
|
-
continue;
|
|
309
|
-
}
|
|
310
|
-
if (char === "'") {
|
|
311
|
-
inSingleQuote = true;
|
|
312
|
-
continue;
|
|
313
|
-
}
|
|
314
|
-
if (char === "\"") {
|
|
315
|
-
inDoubleQuote = true;
|
|
316
|
-
continue;
|
|
317
|
-
}
|
|
318
|
-
if (char === "`") {
|
|
319
|
-
inTemplate = true;
|
|
320
|
-
continue;
|
|
321
|
-
}
|
|
322
|
-
if (char === "(" || char === "[" || char === "{") {
|
|
323
|
-
depth += 1;
|
|
324
|
-
continue;
|
|
325
|
-
}
|
|
326
|
-
if (char === ")" || char === "]" || char === "}") {
|
|
327
|
-
depth = Math.max(0, depth - 1);
|
|
328
|
-
continue;
|
|
329
|
-
}
|
|
330
|
-
if (depth !== 0) continue;
|
|
331
|
-
if (char === "?") {
|
|
332
|
-
sawTopLevelQuestion = true;
|
|
333
|
-
continue;
|
|
334
|
-
}
|
|
335
|
-
if (char === ":") return !sawTopLevelQuestion;
|
|
336
|
-
}
|
|
337
|
-
return false;
|
|
338
|
-
}
|
|
339
|
-
function shouldWrapShorthandObject(expression) {
|
|
340
|
-
const trimmed = expression.trim();
|
|
341
|
-
if (!trimmed) return false;
|
|
342
|
-
if (trimmed.startsWith("{") || trimmed.startsWith("[") || trimmed.startsWith("(")) return false;
|
|
343
|
-
return hasTopLevelColon(trimmed);
|
|
344
|
-
}
|
|
345
|
-
function buildTemplateDataExpression(raw, scopeVar, wxsVar) {
|
|
346
|
-
const parts = parseInterpolations(raw.trim());
|
|
347
|
-
if (parts.length === 1 && parts[0]?.type === "expr") {
|
|
348
|
-
const expr = parts[0].value.trim();
|
|
349
|
-
if (expr) return buildExpression([{
|
|
350
|
-
type: "expr",
|
|
351
|
-
value: shouldWrapShorthandObject(expr) ? `{ ${expr} }` : expr
|
|
352
|
-
}], scopeVar, wxsVar);
|
|
353
|
-
}
|
|
354
|
-
return buildExpression(parseInterpolations(raw), scopeVar, wxsVar);
|
|
355
|
-
}
|
|
356
|
-
//#endregion
|
|
357
|
-
//#region src/compiler/wxml/attributes.ts
|
|
358
|
-
function extractFor(attribs) {
|
|
359
|
-
const expr = attribs["wx:for"];
|
|
360
|
-
const itemName = attribs["wx:for-item"]?.trim() || "item";
|
|
361
|
-
let indexName = attribs["wx:for-index"]?.trim() || "index";
|
|
362
|
-
const key = attribs["wx:key"];
|
|
363
|
-
const restAttribs = {};
|
|
364
|
-
for (const [name, value] of Object.entries(attribs)) {
|
|
365
|
-
if (CONTROL_ATTRS.has(name)) continue;
|
|
366
|
-
restAttribs[name] = value;
|
|
367
|
-
}
|
|
368
|
-
if (itemName === indexName) indexName = `${indexName}Index`;
|
|
369
|
-
return {
|
|
370
|
-
expr,
|
|
371
|
-
itemName,
|
|
372
|
-
indexName,
|
|
373
|
-
key,
|
|
374
|
-
restAttribs
|
|
375
|
-
};
|
|
376
|
-
}
|
|
377
|
-
function isConditionalElement(node) {
|
|
378
|
-
if (node.type !== "element") return false;
|
|
379
|
-
const attribs = node.attribs ?? {};
|
|
380
|
-
return "wx:if" in attribs || "wx:elif" in attribs || "wx:else" in attribs;
|
|
381
|
-
}
|
|
382
|
-
function stripControlAttributes(attribs) {
|
|
383
|
-
const result = {};
|
|
384
|
-
for (const [name, value] of Object.entries(attribs)) if (!CONTROL_ATTRS.has(name)) result[name] = value;
|
|
385
|
-
return result;
|
|
386
|
-
}
|
|
387
|
-
function parseEventAttribute(name) {
|
|
388
|
-
if (name.includes(":")) {
|
|
389
|
-
const [prefix, rawEvent] = name.split(":", 2);
|
|
390
|
-
return {
|
|
391
|
-
prefix,
|
|
392
|
-
rawEvent
|
|
393
|
-
};
|
|
394
|
-
}
|
|
395
|
-
const match = EVENT_PREFIX_RE.exec(name);
|
|
396
|
-
if (!match) return;
|
|
397
|
-
return {
|
|
398
|
-
prefix: name.slice(0, name.length - match[1].length),
|
|
399
|
-
rawEvent: match[1]
|
|
400
|
-
};
|
|
401
|
-
}
|
|
402
|
-
function resolveComponentTagName(name, componentTags) {
|
|
403
|
-
if (!componentTags) return;
|
|
404
|
-
return componentTags[name] ?? componentTags[name.toLowerCase()];
|
|
405
|
-
}
|
|
406
|
-
const PROPERTY_BIND_EXCLUSIONS = new Set([
|
|
407
|
-
"class",
|
|
408
|
-
"style",
|
|
409
|
-
"id",
|
|
410
|
-
"slot"
|
|
411
|
-
]);
|
|
412
|
-
function shouldBindAsProperty(name) {
|
|
413
|
-
if (PROPERTY_BIND_EXCLUSIONS.has(name)) return false;
|
|
414
|
-
if (name.startsWith("data-") || name.startsWith("aria-")) return false;
|
|
415
|
-
return true;
|
|
416
|
-
}
|
|
417
|
-
function normalizePropertyName(name) {
|
|
418
|
-
return name.replace(/-([a-z])/g, (_, char) => char.toUpperCase());
|
|
419
|
-
}
|
|
420
|
-
function renderAttributes(attribs, scopeVar, wxsVar, options) {
|
|
421
|
-
let buffer = "";
|
|
422
|
-
for (const [rawName, rawValue] of Object.entries(attribs)) {
|
|
423
|
-
if (options?.skipControl && CONTROL_ATTRS.has(rawName)) continue;
|
|
424
|
-
const eventInfo = parseEventAttribute(rawName);
|
|
425
|
-
if (eventInfo) {
|
|
426
|
-
const event = eventInfo.rawEvent.toLowerCase();
|
|
427
|
-
const handlerExpr = buildExpression(parseInterpolations(rawValue ?? ""), scopeVar, wxsVar);
|
|
428
|
-
const domEvent = EVENT_KIND_ALIAS[event] ?? event;
|
|
429
|
-
const flags = {
|
|
430
|
-
catch: eventInfo.prefix.includes("catch"),
|
|
431
|
-
capture: eventInfo.prefix.includes("capture")
|
|
432
|
-
};
|
|
433
|
-
buffer += ` @${domEvent}=\${ctx.event(${JSON.stringify(event)}, ${handlerExpr}, ${scopeVar}, ${wxsVar}, ${JSON.stringify(flags)})}`;
|
|
434
|
-
continue;
|
|
435
|
-
}
|
|
436
|
-
const useProperty = options?.preferProperty && shouldBindAsProperty(rawName);
|
|
437
|
-
const name = useProperty ? normalizePropertyName(rawName) : normalizeAttributeName(rawName);
|
|
438
|
-
const expr = buildExpression(parseInterpolations(rawValue ?? ""), scopeVar, wxsVar);
|
|
439
|
-
buffer += ` ${useProperty ? "." : ""}${name}=\${${expr}}`;
|
|
440
|
-
}
|
|
441
|
-
return buffer;
|
|
442
|
-
}
|
|
443
|
-
//#endregion
|
|
444
|
-
//#region src/compiler/wxml/renderer.ts
|
|
445
|
-
var Renderer = class {
|
|
446
|
-
renderNodes(nodes, scopeVar, wxsVar, componentTags) {
|
|
447
|
-
const parts = [];
|
|
448
|
-
for (let index = 0; index < nodes.length; index += 1) {
|
|
449
|
-
const node = nodes[index];
|
|
450
|
-
if (isConditionalElement(node)) {
|
|
451
|
-
const { rendered, endIndex } = this.renderConditionalSequence(nodes, index, scopeVar, wxsVar, componentTags);
|
|
452
|
-
parts.push(rendered);
|
|
453
|
-
index = endIndex;
|
|
454
|
-
continue;
|
|
455
|
-
}
|
|
456
|
-
parts.push(this.renderNode(node, scopeVar, wxsVar, componentTags));
|
|
457
|
-
}
|
|
458
|
-
if (parts.length === 0) return "\"\"";
|
|
459
|
-
if (parts.length === 1) return parts[0];
|
|
460
|
-
return `[${parts.join(", ")}]`;
|
|
461
|
-
}
|
|
462
|
-
renderConditionalSequence(nodes, startIndex, scopeVar, wxsVar, componentTags) {
|
|
463
|
-
const branches = [];
|
|
464
|
-
let cursor = startIndex;
|
|
465
|
-
while (cursor < nodes.length) {
|
|
466
|
-
const candidate = nodes[cursor];
|
|
467
|
-
if (!isConditionalElement(candidate)) break;
|
|
468
|
-
const attribs = candidate.attribs ?? {};
|
|
469
|
-
if (branches.length === 0 && !("wx:if" in attribs)) break;
|
|
470
|
-
if (branches.length > 0 && !("wx:elif" in attribs) && !("wx:else" in attribs)) break;
|
|
471
|
-
branches.push({
|
|
472
|
-
node: candidate,
|
|
473
|
-
attribs
|
|
474
|
-
});
|
|
475
|
-
cursor += 1;
|
|
476
|
-
if ("wx:else" in attribs) break;
|
|
477
|
-
}
|
|
478
|
-
if (!branches.length) {
|
|
479
|
-
const node = nodes[startIndex];
|
|
480
|
-
if (!node) return {
|
|
481
|
-
rendered: "\"\"",
|
|
482
|
-
endIndex: startIndex
|
|
483
|
-
};
|
|
484
|
-
return {
|
|
485
|
-
rendered: this.renderNode(node, scopeVar, wxsVar, componentTags),
|
|
486
|
-
endIndex: startIndex
|
|
487
|
-
};
|
|
488
|
-
}
|
|
489
|
-
let expr = "\"\"";
|
|
490
|
-
for (let index = branches.length - 1; index >= 0; index -= 1) {
|
|
491
|
-
const { node, attribs } = branches[index];
|
|
492
|
-
const cleanedAttribs = stripControlAttributes(attribs);
|
|
493
|
-
if ("wx:else" in attribs) {
|
|
494
|
-
expr = this.renderElement(node, scopeVar, wxsVar, componentTags, { overrideAttribs: cleanedAttribs });
|
|
495
|
-
continue;
|
|
496
|
-
}
|
|
497
|
-
const conditionExpr = attribs["wx:if"] ?? attribs["wx:elif"] ?? "";
|
|
498
|
-
const rendered = this.renderElement(node, scopeVar, wxsVar, componentTags, { overrideAttribs: cleanedAttribs });
|
|
499
|
-
expr = `(${buildExpression(parseInterpolations(conditionExpr), scopeVar, wxsVar)} ? ${rendered} : ${expr})`;
|
|
500
|
-
}
|
|
501
|
-
return {
|
|
502
|
-
rendered: expr,
|
|
503
|
-
endIndex: startIndex + branches.length - 1
|
|
504
|
-
};
|
|
505
|
-
}
|
|
506
|
-
renderNode(node, scopeVar, wxsVar, componentTags) {
|
|
507
|
-
if (node.type === "text") return buildExpression(parseInterpolations(node.data ?? ""), scopeVar, wxsVar);
|
|
508
|
-
if (node.type === "element") {
|
|
509
|
-
if (node.name === "template" && node.attribs?.is) return this.renderTemplateInvoke(node, scopeVar, wxsVar);
|
|
510
|
-
return this.renderElement(node, scopeVar, wxsVar, componentTags);
|
|
511
|
-
}
|
|
512
|
-
return "\"\"";
|
|
513
|
-
}
|
|
514
|
-
renderTemplateInvoke(node, scopeVar, wxsVar) {
|
|
515
|
-
const attribs = node.attribs ?? {};
|
|
516
|
-
const isExpr = buildExpression(parseInterpolations(attribs.is ?? ""), scopeVar, wxsVar);
|
|
517
|
-
const dataExpr = attribs.data ? buildTemplateDataExpression(attribs.data, scopeVar, wxsVar) : void 0;
|
|
518
|
-
return `ctx.renderTemplate(__templates, ${isExpr}, ${dataExpr ? `ctx.mergeScope(${scopeVar}, ${dataExpr})` : scopeVar}, ctx)`;
|
|
519
|
-
}
|
|
520
|
-
renderElement(node, scopeVar, wxsVar, componentTags, options = {}) {
|
|
521
|
-
const attribs = options.overrideAttribs ?? node.attribs ?? {};
|
|
522
|
-
if (!options.skipFor) {
|
|
523
|
-
const forInfo = extractFor(node.attribs ?? {});
|
|
524
|
-
if (forInfo.expr) {
|
|
525
|
-
const listExpr = `ctx.normalizeList(${buildExpression(parseInterpolations(forInfo.expr), scopeVar, wxsVar)})`;
|
|
526
|
-
const itemVar = forInfo.itemName;
|
|
527
|
-
const indexVar = forInfo.indexName;
|
|
528
|
-
const scopeExpr = `ctx.createScope(${scopeVar}, { ${itemVar}: ${itemVar}, ${indexVar}: ${indexVar} })`;
|
|
529
|
-
const itemRender = this.renderElement(node, "__scope", wxsVar, componentTags, {
|
|
530
|
-
skipFor: true,
|
|
531
|
-
overrideAttribs: forInfo.restAttribs
|
|
532
|
-
});
|
|
533
|
-
return `repeat(${listExpr}, (${itemVar}, ${indexVar}) => ${`ctx.key(${JSON.stringify(forInfo.key ?? "")}, ${itemVar}, ${indexVar}, ${scopeExpr}, ${wxsVar})`}, (${itemVar}, ${indexVar}) => { const __scope = ${scopeExpr}; return ${itemRender}; })`;
|
|
534
|
-
}
|
|
535
|
-
}
|
|
536
|
-
const customTag = resolveComponentTagName(node.name ?? "", componentTags);
|
|
537
|
-
const tagName = customTag ?? normalizeTagName(node.name ?? "");
|
|
538
|
-
if (tagName === "#fragment") return this.renderNodes(node.children ?? [], scopeVar, wxsVar, componentTags);
|
|
539
|
-
const attrs = renderAttributes(attribs, scopeVar, wxsVar, {
|
|
540
|
-
skipControl: true,
|
|
541
|
-
preferProperty: Boolean(customTag)
|
|
542
|
-
});
|
|
543
|
-
const childNodes = node.children ?? [];
|
|
544
|
-
const children = childNodes.map((child) => `\${${this.renderNode(child, scopeVar, wxsVar, componentTags)}}`).join("");
|
|
545
|
-
if (SELF_CLOSING_TAGS.has(tagName) && childNodes.length === 0) return `html\`<${tagName}${attrs} />\``;
|
|
546
|
-
return `html\`<${tagName}${attrs}>${children}</${tagName}>\``;
|
|
547
|
-
}
|
|
548
|
-
};
|
|
549
|
-
const renderer = new Renderer();
|
|
550
|
-
//#endregion
|
|
551
|
-
//#region src/compiler/wxml/specialNodes.ts
|
|
552
|
-
function shouldMarkWxsImport(pathname) {
|
|
553
|
-
const lower = pathname.toLowerCase();
|
|
554
|
-
if (lower.endsWith(".wxs") || lower.endsWith(".wxs.ts") || lower.endsWith(".wxs.js")) return false;
|
|
555
|
-
return lower.endsWith(".ts") || lower.endsWith(".js");
|
|
556
|
-
}
|
|
557
|
-
function collectSpecialNodes(nodes, context) {
|
|
558
|
-
const renderable = [];
|
|
559
|
-
for (const node of nodes) {
|
|
560
|
-
if (node.type === "element") {
|
|
561
|
-
const name = node.name ?? "";
|
|
562
|
-
if (name === "template" && node.attribs?.name) {
|
|
563
|
-
context.templates.push({
|
|
564
|
-
name: node.attribs.name,
|
|
565
|
-
nodes: collectSpecialNodes(node.children ?? [], context)
|
|
566
|
-
});
|
|
567
|
-
continue;
|
|
568
|
-
}
|
|
569
|
-
if ((name === "import" || name === "wx-import") && node.attribs?.src) {
|
|
570
|
-
const resolved = context.resolveTemplate(node.attribs.src);
|
|
571
|
-
if (resolved) context.imports.push({
|
|
572
|
-
id: resolved,
|
|
573
|
-
importName: `__wxml_import_${context.imports.length}`
|
|
574
|
-
});
|
|
575
|
-
else context.warnings.push(`[web] 无法解析模板依赖: ${node.attribs.src} (from ${context.sourceId})`);
|
|
576
|
-
continue;
|
|
577
|
-
}
|
|
578
|
-
if ((name === "include" || name === "wx-include") && node.attribs?.src) {
|
|
579
|
-
const resolved = context.resolveTemplate(node.attribs.src);
|
|
580
|
-
if (resolved) context.includes.push({
|
|
581
|
-
id: resolved,
|
|
582
|
-
importName: `__wxml_include_${context.includes.length}`
|
|
583
|
-
});
|
|
584
|
-
else context.warnings.push(`[web] 无法解析模板依赖: ${node.attribs.src} (from ${context.sourceId})`);
|
|
585
|
-
continue;
|
|
586
|
-
}
|
|
587
|
-
if (name === "wxs") {
|
|
588
|
-
const moduleName = node.attribs?.module?.trim();
|
|
589
|
-
if (moduleName) {
|
|
590
|
-
if (context.wxsModules.get(moduleName)) context.warnings.push(`[web] WXS 模块名重复: ${moduleName} (from ${context.sourceId})`);
|
|
591
|
-
context.wxsModules.set(moduleName, context.sourceId);
|
|
592
|
-
if (node.attribs?.src) {
|
|
593
|
-
const resolved = context.resolveWxs(node.attribs.src);
|
|
594
|
-
if (resolved) context.wxs.push({
|
|
595
|
-
module: moduleName,
|
|
596
|
-
kind: "src",
|
|
597
|
-
importName: `__wxs_${context.wxs.length}`,
|
|
598
|
-
value: resolved
|
|
599
|
-
});
|
|
600
|
-
} else {
|
|
601
|
-
const inlineCode = (node.children ?? []).filter((child) => child.type === "text").map((child) => child.data ?? "").join("");
|
|
602
|
-
context.wxs.push({
|
|
603
|
-
module: moduleName,
|
|
604
|
-
kind: "inline",
|
|
605
|
-
importName: `__wxs_${context.wxs.length}`,
|
|
606
|
-
value: inlineCode
|
|
607
|
-
});
|
|
608
|
-
}
|
|
609
|
-
}
|
|
610
|
-
continue;
|
|
611
|
-
}
|
|
612
|
-
if (node.children?.length) node.children = collectSpecialNodes(node.children, context);
|
|
613
|
-
}
|
|
614
|
-
renderable.push(node);
|
|
615
|
-
}
|
|
616
|
-
return renderable;
|
|
617
|
-
}
|
|
618
|
-
function toRelativeImport$1(from, target) {
|
|
619
|
-
const rel = relative(dirname(from), target);
|
|
620
|
-
if (!rel || rel.startsWith(".")) {
|
|
621
|
-
const fallback = normalizeTemplatePath(target).split("/").pop() ?? "";
|
|
622
|
-
return rel || `./${fallback}`;
|
|
623
|
-
}
|
|
624
|
-
return `./${rel}`;
|
|
625
|
-
}
|
|
626
|
-
function normalizeTemplatePath(pathname) {
|
|
627
|
-
return pathname.split("\\").join("/");
|
|
628
|
-
}
|
|
629
|
-
//#endregion
|
|
630
|
-
//#region src/compiler/wxml/compile.ts
|
|
631
|
-
function compileWxml(options) {
|
|
632
|
-
const dependencyContext = options.dependencyContext ?? createDependencyContext();
|
|
633
|
-
const expandDependencies = options.expandDependencies ?? !options.dependencyContext;
|
|
634
|
-
const warnings = dependencyContext.warnings;
|
|
635
|
-
const expandDependencyTree = (dependencies, importer) => {
|
|
636
|
-
for (const target of dependencies) {
|
|
637
|
-
if (!target) continue;
|
|
638
|
-
if (dependencyContext.active.has(target)) {
|
|
639
|
-
warnCircularTemplate(dependencyContext, importer, target);
|
|
640
|
-
continue;
|
|
641
|
-
}
|
|
642
|
-
if (dependencyContext.visited.has(target)) continue;
|
|
643
|
-
dependencyContext.visited.add(target);
|
|
644
|
-
dependencyContext.active.add(target);
|
|
645
|
-
let source;
|
|
646
|
-
try {
|
|
647
|
-
source = readFileSync(target, "utf8");
|
|
648
|
-
} catch {
|
|
649
|
-
warnReadTemplate(dependencyContext, target);
|
|
650
|
-
dependencyContext.active.delete(target);
|
|
651
|
-
continue;
|
|
652
|
-
}
|
|
653
|
-
try {
|
|
654
|
-
expandDependencyTree(compileWxml({
|
|
655
|
-
id: target,
|
|
656
|
-
source,
|
|
657
|
-
resolveTemplatePath: options.resolveTemplatePath,
|
|
658
|
-
resolveWxsPath: options.resolveWxsPath,
|
|
659
|
-
dependencyContext,
|
|
660
|
-
expandDependencies: false
|
|
661
|
-
}).dependencies, target);
|
|
662
|
-
} catch (error) {
|
|
663
|
-
if (error instanceof Error && error.message) warnings.push(`[web] 无法解析模板依赖: ${target} ${error.message}`);
|
|
664
|
-
}
|
|
665
|
-
dependencyContext.active.delete(target);
|
|
666
|
-
}
|
|
667
|
-
};
|
|
668
|
-
let nodes = parseWxml(options.source);
|
|
669
|
-
let navigationBarAttrs;
|
|
670
|
-
if (options.navigationBar) {
|
|
671
|
-
const extracted = extractNavigationBarFromPageMeta(nodes);
|
|
672
|
-
nodes = extracted.nodes;
|
|
673
|
-
if (extracted.warnings.length > 0) warnings.push(...extracted.warnings);
|
|
674
|
-
navigationBarAttrs = extracted.attrs;
|
|
675
|
-
}
|
|
676
|
-
const templates = [];
|
|
677
|
-
const includes = [];
|
|
678
|
-
const imports = [];
|
|
679
|
-
const wxs = [];
|
|
680
|
-
const renderNodesList = collectSpecialNodes(nodes, {
|
|
681
|
-
templates,
|
|
682
|
-
includes,
|
|
683
|
-
imports,
|
|
684
|
-
wxs,
|
|
685
|
-
wxsModules: /* @__PURE__ */ new Map(),
|
|
686
|
-
warnings,
|
|
687
|
-
sourceId: options.id,
|
|
688
|
-
resolveTemplate: (raw) => options.resolveTemplatePath(raw, options.id),
|
|
689
|
-
resolveWxs: (raw) => options.resolveWxsPath(raw, options.id)
|
|
690
|
-
});
|
|
691
|
-
if (options.navigationBar && options.navigationBar.config.navigationStyle !== "custom") {
|
|
692
|
-
const attrs = buildNavigationBarAttrs(options.navigationBar.config, navigationBarAttrs);
|
|
693
|
-
renderNodesList.unshift({
|
|
694
|
-
type: "element",
|
|
695
|
-
name: "weapp-navigation-bar",
|
|
696
|
-
attribs: attrs
|
|
697
|
-
});
|
|
698
|
-
}
|
|
699
|
-
const importLines = [`import { html } from 'lit'`, `import { repeat } from 'lit/directives/repeat.js'`];
|
|
700
|
-
const bodyLines = [];
|
|
701
|
-
const directDependencies = [];
|
|
702
|
-
for (const entry of imports) {
|
|
703
|
-
const importPath = normalizeTemplatePath(toRelativeImport$1(options.id, entry.id));
|
|
704
|
-
importLines.push(`import { templates as ${entry.importName} } from '${importPath}'`);
|
|
705
|
-
addDependency(entry.id, dependencyContext, directDependencies);
|
|
706
|
-
}
|
|
707
|
-
for (const entry of includes) {
|
|
708
|
-
const importPath = normalizeTemplatePath(toRelativeImport$1(options.id, entry.id));
|
|
709
|
-
importLines.push(`import { render as ${entry.importName} } from '${importPath}'`);
|
|
710
|
-
addDependency(entry.id, dependencyContext, directDependencies);
|
|
711
|
-
}
|
|
712
|
-
for (const entry of wxs) if (entry.kind === "src") {
|
|
713
|
-
const baseImport = normalizeTemplatePath(toRelativeImport$1(options.id, entry.value));
|
|
714
|
-
const importPath = shouldMarkWxsImport(entry.value) ? `${baseImport}?wxs` : baseImport;
|
|
715
|
-
importLines.push(`import ${entry.importName} from '${importPath}'`);
|
|
716
|
-
addDependency(entry.value, dependencyContext, directDependencies);
|
|
717
|
-
}
|
|
718
|
-
if (templates.length > 0 || imports.length > 0) {
|
|
719
|
-
const templatePairs = [];
|
|
720
|
-
for (const entry of imports) templatePairs.push(`...${entry.importName}`);
|
|
721
|
-
for (const template of templates) {
|
|
722
|
-
const rendered = renderer.renderNodes(template.nodes, "scope", "__wxs_modules", options.componentTags);
|
|
723
|
-
templatePairs.push(`${JSON.stringify(template.name)}: (scope, ctx) => ${rendered}`);
|
|
724
|
-
}
|
|
725
|
-
bodyLines.push(`const __templates = { ${templatePairs.join(", ")} }`);
|
|
726
|
-
} else bodyLines.push(`const __templates = {}`);
|
|
727
|
-
if (wxs.length > 0) {
|
|
728
|
-
bodyLines.push(`const __wxs_inline_cache = Object.create(null)`);
|
|
729
|
-
bodyLines.push(`let __wxs_modules = {}`);
|
|
730
|
-
const wxsMapEntries = [];
|
|
731
|
-
for (const entry of wxs) {
|
|
732
|
-
if (entry.kind === "inline") {
|
|
733
|
-
const inlineCode = entry.value.trim();
|
|
734
|
-
const cacheKey = JSON.stringify(entry.module);
|
|
735
|
-
if (inlineCode) {
|
|
736
|
-
bodyLines.push(`function ${entry.importName}(ctx) {`);
|
|
737
|
-
bodyLines.push(` if (!__wxs_inline_cache[${cacheKey}]) {`);
|
|
738
|
-
bodyLines.push(` __wxs_inline_cache[${cacheKey}] = ctx.createWxsModule(${JSON.stringify(inlineCode)}, ${JSON.stringify(options.id)})`);
|
|
739
|
-
bodyLines.push(` }`);
|
|
740
|
-
bodyLines.push(` return __wxs_inline_cache[${cacheKey}]`);
|
|
741
|
-
bodyLines.push(`}`);
|
|
742
|
-
} else bodyLines.push(`function ${entry.importName}() { return {} }`);
|
|
743
|
-
wxsMapEntries.push(`${JSON.stringify(entry.module)}: ${entry.importName}(ctx)`);
|
|
744
|
-
continue;
|
|
745
|
-
}
|
|
746
|
-
wxsMapEntries.push(`${JSON.stringify(entry.module)}: ${entry.importName}`);
|
|
747
|
-
}
|
|
748
|
-
bodyLines.push(`function __resolveWxsModules(ctx) {`);
|
|
749
|
-
bodyLines.push(` return { ${wxsMapEntries.join(", ")} }`);
|
|
750
|
-
bodyLines.push(`}`);
|
|
751
|
-
} else bodyLines.push(`const __wxs_modules = {}`);
|
|
752
|
-
const includesRender = includes.map((entry) => `${entry.importName}(scope, ctx)`);
|
|
753
|
-
const renderContent = renderer.renderNodes(renderNodesList, "scope", "__wxs_modules", options.componentTags);
|
|
754
|
-
const contentExpr = includesRender.length > 0 ? `[${[...includesRender, renderContent].join(", ")}]` : renderContent;
|
|
755
|
-
bodyLines.push(`export function render(scope, ctx) {`);
|
|
756
|
-
if (wxs.length > 0) bodyLines.push(` __wxs_modules = __resolveWxsModules(ctx)`);
|
|
757
|
-
bodyLines.push(` return ${contentExpr}`);
|
|
758
|
-
bodyLines.push(`}`);
|
|
759
|
-
bodyLines.push(`export const templates = __templates`);
|
|
760
|
-
bodyLines.push(`export default render`);
|
|
761
|
-
if (expandDependencies) {
|
|
762
|
-
dependencyContext.visited.add(options.id);
|
|
763
|
-
dependencyContext.active.add(options.id);
|
|
764
|
-
expandDependencyTree(directDependencies, options.id);
|
|
765
|
-
dependencyContext.active.delete(options.id);
|
|
766
|
-
}
|
|
767
|
-
return {
|
|
768
|
-
code: [
|
|
769
|
-
...importLines,
|
|
770
|
-
"",
|
|
771
|
-
...bodyLines
|
|
772
|
-
].join("\n"),
|
|
773
|
-
dependencies: expandDependencies ? dependencyContext.dependencies : directDependencies,
|
|
774
|
-
warnings: warnings.length > 0 ? warnings : void 0
|
|
775
|
-
};
|
|
776
|
-
}
|
|
777
|
-
//#endregion
|
|
778
|
-
//#region src/compiler/wxs.ts
|
|
779
|
-
const REQUIRE_RE = /require\(\s*['"]([^'"]+)['"]\s*\)/g;
|
|
780
|
-
function normalizePath$1(p) {
|
|
781
|
-
return p.split("\\\\").join("/");
|
|
782
|
-
}
|
|
783
|
-
function isPlainWxsScript(pathname) {
|
|
784
|
-
const lower = pathname.toLowerCase();
|
|
785
|
-
if (lower.endsWith(".wxs") || lower.endsWith(".wxs.ts") || lower.endsWith(".wxs.js")) return false;
|
|
786
|
-
return lower.endsWith(".ts") || lower.endsWith(".js");
|
|
787
|
-
}
|
|
788
|
-
function appendWxsQuery(pathname) {
|
|
789
|
-
if (pathname.includes("?wxs") || pathname.includes("&wxs")) return pathname;
|
|
790
|
-
return `${pathname}${pathname.includes("?") ? "&" : "?"}wxs`;
|
|
791
|
-
}
|
|
792
|
-
function isSupportedRequirePath(request) {
|
|
793
|
-
const normalized = request.replace(/\\/g, "/");
|
|
794
|
-
return normalized.startsWith(".") || normalized.startsWith("/");
|
|
795
|
-
}
|
|
796
|
-
function transformWxsToEsm(code, id, options) {
|
|
797
|
-
const dependencies = [];
|
|
798
|
-
const importLines = [];
|
|
799
|
-
const mapEntries = [];
|
|
800
|
-
const warnings = [];
|
|
801
|
-
const seen = /* @__PURE__ */ new Set();
|
|
802
|
-
while (true) {
|
|
803
|
-
const match = REQUIRE_RE.exec(code);
|
|
804
|
-
if (!match) break;
|
|
805
|
-
const request = match[1];
|
|
806
|
-
if (!request || seen.has(request)) continue;
|
|
807
|
-
seen.add(request);
|
|
808
|
-
if (!isSupportedRequirePath(request)) {
|
|
809
|
-
warnings.push(`[@weapp-vite/web] WXS require 仅支持相对或绝对路径: ${request} (from ${id})`);
|
|
810
|
-
continue;
|
|
811
|
-
}
|
|
812
|
-
const normalizedRequest = request.replace(/\\/g, "/");
|
|
813
|
-
const resolved = options.resolvePath(normalizedRequest, id);
|
|
814
|
-
if (!resolved) {
|
|
815
|
-
warnings.push(`[@weapp-vite/web] 无法解析 WXS require: ${request} (from ${id})`);
|
|
816
|
-
continue;
|
|
817
|
-
}
|
|
818
|
-
let importPath = normalizePath$1(options.toImportPath?.(resolved, id) ?? resolved);
|
|
819
|
-
if (isPlainWxsScript(resolved)) importPath = appendWxsQuery(importPath);
|
|
820
|
-
const importName = `__wxs_dep_${dependencies.length}`;
|
|
821
|
-
importLines.push(`import ${importName} from '${importPath}'`);
|
|
822
|
-
mapEntries.push(`[${JSON.stringify(request)}, ${importName}]`);
|
|
823
|
-
dependencies.push(resolved);
|
|
824
|
-
}
|
|
825
|
-
const requireMap = `const __wxs_require_map = new Map([${mapEntries.join(", ")}])`;
|
|
826
|
-
const requireFn = [
|
|
827
|
-
`const __wxs_require_warned = new Set()`,
|
|
828
|
-
`function require(id) {`,
|
|
829
|
-
` if (__wxs_require_map.has(id)) {`,
|
|
830
|
-
` return __wxs_require_map.get(id)`,
|
|
831
|
-
` }`,
|
|
832
|
-
` if (!__wxs_require_warned.has(id)) {`,
|
|
833
|
-
` __wxs_require_warned.add(id)`,
|
|
834
|
-
` if (typeof console !== 'undefined' && typeof console.warn === 'function') {`,
|
|
835
|
-
` console.warn(\`[@weapp-vite/web] WXS require 未解析: \${id}\`)`,
|
|
836
|
-
` }`,
|
|
837
|
-
` }`,
|
|
838
|
-
` return undefined`,
|
|
839
|
-
`}`
|
|
840
|
-
].join("\\n");
|
|
841
|
-
const moduleInit = `const module = { exports: {} }\\nconst exports = module.exports`;
|
|
842
|
-
const helpers = `const getRegExp = (pattern, flags) => new RegExp(pattern, flags)\\nconst getDate = (value) => (value == null ? new Date() : new Date(value))`;
|
|
843
|
-
return {
|
|
844
|
-
code: [
|
|
845
|
-
...importLines,
|
|
846
|
-
requireMap,
|
|
847
|
-
requireFn,
|
|
848
|
-
moduleInit,
|
|
849
|
-
helpers,
|
|
850
|
-
code,
|
|
851
|
-
`export default module.exports`
|
|
852
|
-
].join("\\n"),
|
|
853
|
-
dependencies,
|
|
854
|
-
warnings: warnings.length > 0 ? warnings : void 0
|
|
855
|
-
};
|
|
856
|
-
}
|
|
857
|
-
//#endregion
|
|
858
|
-
//#region src/css/wxss.ts
|
|
859
|
-
const RPX_RE = /(-?(?:\d+(?:\.\d+)?|\.\d+))rpx/gi;
|
|
860
|
-
function transformWxssToCss(source, options) {
|
|
861
|
-
const rpxVar = options?.rpxVar ?? "--rpx";
|
|
862
|
-
const useVariable = typeof options?.designWidth === "number" && Number.isFinite(options.designWidth);
|
|
863
|
-
const ratio = options?.pxPerRpx ?? .5;
|
|
864
|
-
return { css: source.replace(RPX_RE, (_, value) => {
|
|
865
|
-
const numeric = Number.parseFloat(value);
|
|
866
|
-
if (Number.isNaN(numeric)) return `${value}px`;
|
|
867
|
-
if (useVariable) return `calc(var(${rpxVar}) * ${numeric})`;
|
|
868
|
-
return `${Math.round(numeric * ratio * 1e3) / 1e3}px`;
|
|
869
|
-
}) };
|
|
870
|
-
}
|
|
871
|
-
//#endregion
|
|
872
|
-
//#region src/plugin/constants.ts
|
|
873
|
-
const SCRIPT_EXTS = [
|
|
874
|
-
".ts",
|
|
875
|
-
".tsx",
|
|
876
|
-
".js",
|
|
877
|
-
".jsx",
|
|
878
|
-
".mjs",
|
|
879
|
-
".cjs"
|
|
880
|
-
];
|
|
881
|
-
const STYLE_EXTS = [
|
|
882
|
-
".wxss",
|
|
883
|
-
".scss",
|
|
884
|
-
".less",
|
|
885
|
-
".css"
|
|
886
|
-
];
|
|
887
|
-
const TRANSFORM_STYLE_EXTS = [".wxss"];
|
|
888
|
-
const TEMPLATE_EXTS = [
|
|
889
|
-
".wxml",
|
|
890
|
-
".axml",
|
|
891
|
-
".swan",
|
|
892
|
-
".ttml",
|
|
893
|
-
".qml",
|
|
894
|
-
".ksml",
|
|
895
|
-
".xhsml",
|
|
896
|
-
".html"
|
|
897
|
-
];
|
|
898
|
-
const WXS_EXTS = [
|
|
899
|
-
".wxs",
|
|
900
|
-
".wxs.ts",
|
|
901
|
-
".wxs.js"
|
|
902
|
-
];
|
|
903
|
-
const WXS_RESOLVE_EXTS = [
|
|
904
|
-
".wxs",
|
|
905
|
-
".wxs.ts",
|
|
906
|
-
".wxs.js",
|
|
907
|
-
".ts",
|
|
908
|
-
".js"
|
|
909
|
-
];
|
|
910
|
-
const ENTRY_ID = "\0@weapp-vite/web/entry";
|
|
911
|
-
//#endregion
|
|
912
|
-
//#region src/plugin/path.ts
|
|
913
|
-
function cleanUrl(url) {
|
|
914
|
-
const queryIndex = url.indexOf("?");
|
|
915
|
-
if (queryIndex >= 0) return url.slice(0, queryIndex);
|
|
916
|
-
return url;
|
|
917
|
-
}
|
|
918
|
-
function normalizePath(p) {
|
|
919
|
-
return posix.normalize(p.split("\\").join("/"));
|
|
920
|
-
}
|
|
921
|
-
function isInsideDir(filePath, dir) {
|
|
922
|
-
const rel = relative(dir, filePath);
|
|
923
|
-
return rel === "" || !rel.startsWith("..") && !posix.isAbsolute(rel);
|
|
924
|
-
}
|
|
925
|
-
function isHtmlEntry(filePath, root) {
|
|
926
|
-
if (!filePath.toLowerCase().endsWith(".html")) return false;
|
|
927
|
-
return normalizePath(filePath) === normalizePath(resolve(root, "index.html"));
|
|
928
|
-
}
|
|
929
|
-
function toPosixId(id) {
|
|
930
|
-
return normalize(id).split("\\").join("/");
|
|
931
|
-
}
|
|
932
|
-
function toRelativeImport(from, target) {
|
|
933
|
-
const rel = relative(dirname(from), target);
|
|
934
|
-
if (!rel || rel.startsWith(".")) return normalizePath(rel || `./${posix.basename(target)}`);
|
|
935
|
-
return `./${normalizePath(rel)}`;
|
|
936
|
-
}
|
|
937
|
-
function appendInlineQuery(id) {
|
|
938
|
-
if (id.includes("?")) {
|
|
939
|
-
if (id.includes("?inline") || id.includes("&inline")) return id;
|
|
940
|
-
return `${id}&inline`;
|
|
941
|
-
}
|
|
942
|
-
return `${id}?inline`;
|
|
943
|
-
}
|
|
944
|
-
function relativeModuleId(root, absPath) {
|
|
945
|
-
return `/${normalizePath(relative(root, absPath))}`;
|
|
946
|
-
}
|
|
947
|
-
function resolveImportBase(raw, importer, srcRoot) {
|
|
948
|
-
if (!raw) return;
|
|
949
|
-
if (raw.startsWith(".")) return resolve(dirname(importer), raw);
|
|
950
|
-
if (raw.startsWith("/")) return resolve(srcRoot, raw.slice(1));
|
|
951
|
-
return resolve(srcRoot, raw);
|
|
952
|
-
}
|
|
953
|
-
function resolveFileWithExtensionsSync(basePath, extensions) {
|
|
954
|
-
if (extname(basePath) && fs.pathExistsSync(basePath)) return basePath;
|
|
955
|
-
for (const ext of extensions) {
|
|
956
|
-
const candidate = `${basePath}${ext}`;
|
|
957
|
-
if (fs.pathExistsSync(candidate)) return candidate;
|
|
958
|
-
}
|
|
959
|
-
}
|
|
960
|
-
function resolveTemplatePathSync(raw, importer, srcRoot) {
|
|
961
|
-
const base = resolveImportBase(raw, importer, srcRoot);
|
|
962
|
-
if (!base) return;
|
|
963
|
-
return resolveFileWithExtensionsSync(base, TEMPLATE_EXTS);
|
|
964
|
-
}
|
|
965
|
-
function resolveWxsPathSync(raw, importer, srcRoot) {
|
|
966
|
-
if (!raw) return;
|
|
967
|
-
let base;
|
|
968
|
-
if (raw.startsWith(".")) base = resolve(dirname(importer), raw);
|
|
969
|
-
else if (raw.startsWith("/")) base = resolve(srcRoot, raw.slice(1));
|
|
970
|
-
else return;
|
|
971
|
-
return resolveFileWithExtensionsSync(base, WXS_RESOLVE_EXTS);
|
|
972
|
-
}
|
|
973
|
-
//#endregion
|
|
974
|
-
//#region src/plugin/entry.ts
|
|
975
|
-
function generateEntryModule(result, root, wxssOptions, pluginOptions) {
|
|
976
|
-
const importLines = [`import { initializePageRoutes } from '@weapp-vite/web/runtime/polyfill'`];
|
|
977
|
-
const bodyLines = [];
|
|
978
|
-
for (const page of result.pages) importLines.push(`import '${relativeModuleId(root, page.script)}'`);
|
|
979
|
-
for (const component of result.components) importLines.push(`import '${relativeModuleId(root, component.script)}'`);
|
|
980
|
-
if (result.app) importLines.push(`import '${relativeModuleId(root, result.app)}'`);
|
|
981
|
-
const pageOrder = result.pages.map((page) => page.id);
|
|
982
|
-
const rpxConfig = wxssOptions?.designWidth ? {
|
|
983
|
-
designWidth: wxssOptions.designWidth,
|
|
984
|
-
varName: wxssOptions.rpxVar
|
|
985
|
-
} : void 0;
|
|
986
|
-
const initOptions = {};
|
|
987
|
-
if (rpxConfig) initOptions.rpx = rpxConfig;
|
|
988
|
-
if (pluginOptions?.form?.preventDefault !== void 0) initOptions.form = { preventDefault: pluginOptions.form.preventDefault };
|
|
989
|
-
const runtimeOptions = {};
|
|
990
|
-
if (pluginOptions?.runtime?.executionMode) runtimeOptions.executionMode = pluginOptions.runtime.executionMode;
|
|
991
|
-
if (pluginOptions?.runtime?.warnings) runtimeOptions.warnings = pluginOptions.runtime.warnings;
|
|
992
|
-
if (Object.keys(runtimeOptions).length > 0) initOptions.runtime = runtimeOptions;
|
|
993
|
-
const initOptionsCode = Object.keys(initOptions).length > 0 ? `, ${JSON.stringify(initOptions)}` : "";
|
|
994
|
-
bodyLines.push(`initializePageRoutes(${JSON.stringify(pageOrder)}${initOptionsCode})`);
|
|
995
|
-
return [...importLines, ...bodyLines].join("\n");
|
|
996
|
-
}
|
|
997
|
-
//#endregion
|
|
998
|
-
//#region src/plugin/register.ts
|
|
999
|
-
const traverseCandidate = (() => {
|
|
1000
|
-
const mod = _babelTraverse;
|
|
1001
|
-
if (typeof mod === "function") return mod;
|
|
1002
|
-
if (mod?.default && typeof mod.default === "function") return mod.default;
|
|
1003
|
-
if (mod?.traverse && typeof mod.traverse === "function") return mod.traverse;
|
|
1004
|
-
})();
|
|
1005
|
-
if (typeof traverseCandidate !== "function") throw new TypeError("[@weapp-vite/web] Failed to resolve @babel/traverse export.");
|
|
1006
|
-
const traverse = traverseCandidate;
|
|
1007
|
-
function mapRegisterIdentifier(kind) {
|
|
1008
|
-
if (kind === "page") return "Page";
|
|
1009
|
-
if (kind === "component") return "Component";
|
|
1010
|
-
if (kind === "app") return "App";
|
|
1011
|
-
return "";
|
|
1012
|
-
}
|
|
1013
|
-
function getRegisterName(kind) {
|
|
1014
|
-
if (kind === "page") return "registerPage";
|
|
1015
|
-
if (kind === "component") return "registerComponent";
|
|
1016
|
-
if (kind === "app") return "registerApp";
|
|
1017
|
-
}
|
|
1018
|
-
function overwriteCall(path, meta, registerName, templateIdent, styleIdent, s) {
|
|
1019
|
-
const node = path.node;
|
|
1020
|
-
const callee = node.callee;
|
|
1021
|
-
if (!t.isIdentifier(callee)) return;
|
|
1022
|
-
const insertPosition = node.end - 1;
|
|
1023
|
-
const metaParts = [`id: ${JSON.stringify(meta.id)}`];
|
|
1024
|
-
if (templateIdent) metaParts.push(`template: ${templateIdent}`);
|
|
1025
|
-
if (styleIdent) metaParts.push(`style: ${styleIdent}`);
|
|
1026
|
-
const metaCode = `{ ${metaParts.join(", ")} }`;
|
|
1027
|
-
s.overwrite(callee.start, callee.end, registerName);
|
|
1028
|
-
s.appendLeft(insertPosition, `, ${metaCode}`);
|
|
1029
|
-
}
|
|
1030
|
-
function transformScriptModule({ code, cleanId, meta, enableHmr }) {
|
|
1031
|
-
const registerName = getRegisterName(meta.kind);
|
|
1032
|
-
if (!registerName) return null;
|
|
1033
|
-
let ast;
|
|
1034
|
-
try {
|
|
1035
|
-
ast = parse(code, {
|
|
1036
|
-
sourceType: "module",
|
|
1037
|
-
plugins: ["typescript", "jsx"],
|
|
1038
|
-
errorRecovery: true,
|
|
1039
|
-
ranges: true
|
|
1040
|
-
});
|
|
1041
|
-
} catch {
|
|
1042
|
-
return null;
|
|
1043
|
-
}
|
|
1044
|
-
const s = new MagicString(code);
|
|
1045
|
-
let transformed = false;
|
|
1046
|
-
const imports = [];
|
|
1047
|
-
const templateIdent = meta.templatePath ? "__weapp_template__" : void 0;
|
|
1048
|
-
const styleIdent = meta.stylePath ? "__weapp_style__" : void 0;
|
|
1049
|
-
if (meta.templatePath && templateIdent) imports.push(`import ${templateIdent} from '${toRelativeImport(cleanId, meta.templatePath)}'`);
|
|
1050
|
-
if (meta.stylePath && styleIdent) imports.push(`import ${styleIdent} from '${appendInlineQuery(toRelativeImport(cleanId, meta.stylePath))}'`);
|
|
1051
|
-
const registerImports = /* @__PURE__ */ new Set();
|
|
1052
|
-
traverse(ast, { CallExpression(path) {
|
|
1053
|
-
if (!t.isIdentifier(path.node.callee)) return;
|
|
1054
|
-
if (path.node.callee.name === mapRegisterIdentifier(meta.kind)) {
|
|
1055
|
-
registerImports.add(registerName);
|
|
1056
|
-
overwriteCall(path, meta, registerName, templateIdent, styleIdent, s);
|
|
1057
|
-
transformed = true;
|
|
1058
|
-
}
|
|
1059
|
-
} });
|
|
1060
|
-
if (!transformed) return null;
|
|
1061
|
-
if (registerImports.size > 0) imports.unshift(`import { ${Array.from(registerImports).join(", ")} } from '@weapp-vite/web/runtime/polyfill'`);
|
|
1062
|
-
const prefix = `${imports.join("\n")}\n`;
|
|
1063
|
-
s.prepend(prefix);
|
|
1064
|
-
if (enableHmr) s.append(`\nif (import.meta.hot) { import.meta.hot.accept() }\n`);
|
|
1065
|
-
return {
|
|
1066
|
-
code: s.toString(),
|
|
1067
|
-
map: s.generateMap({ hires: true })
|
|
1068
|
-
};
|
|
1069
|
-
}
|
|
1070
|
-
//#endregion
|
|
1071
|
-
//#region src/shared/slugify.ts
|
|
1072
|
-
function slugify(id, prefix) {
|
|
1073
|
-
return `${prefix}-${id.replace(/[^a-z0-9]+/gi, "-").replace(/^-+|-+$/g, "").toLowerCase() || "index"}`;
|
|
1074
|
-
}
|
|
1075
|
-
//#endregion
|
|
1076
|
-
//#region src/plugin/files.ts
|
|
1077
|
-
function isRecord(value) {
|
|
1078
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1079
|
-
}
|
|
1080
|
-
async function readJsonFile(pathname) {
|
|
1081
|
-
const candidates = [pathname];
|
|
1082
|
-
if (pathname.endsWith(".json")) candidates.push(`${pathname}.ts`, `${pathname}.js`);
|
|
1083
|
-
for (const candidate of candidates) {
|
|
1084
|
-
if (!await fs.pathExists(candidate)) continue;
|
|
1085
|
-
if (candidate.endsWith(".json")) {
|
|
1086
|
-
const json = await fs.readJson(candidate).catch(() => void 0);
|
|
1087
|
-
if (!isRecord(json)) return;
|
|
1088
|
-
return json;
|
|
1089
|
-
}
|
|
1090
|
-
const { mod } = await bundleRequire({
|
|
1091
|
-
filepath: candidate,
|
|
1092
|
-
preserveTemporaryFile: true
|
|
1093
|
-
});
|
|
1094
|
-
const resolved = typeof mod.default === "function" ? await mod.default() : mod.default;
|
|
1095
|
-
if (!isRecord(resolved)) return;
|
|
1096
|
-
return resolved;
|
|
1097
|
-
}
|
|
1098
|
-
}
|
|
1099
|
-
async function resolveJsonPath(basePath) {
|
|
1100
|
-
const candidates = [basePath];
|
|
1101
|
-
if (basePath.endsWith(".json")) candidates.push(`${basePath}.ts`, `${basePath}.js`);
|
|
1102
|
-
for (const candidate of candidates) if (await fs.pathExists(candidate)) return candidate;
|
|
1103
|
-
}
|
|
1104
|
-
async function resolveScriptFile(basePath) {
|
|
1105
|
-
if (extname(basePath) && await fs.pathExists(basePath)) return basePath;
|
|
1106
|
-
for (const candidateExt of SCRIPT_EXTS) {
|
|
1107
|
-
const candidate = `${basePath}${candidateExt}`;
|
|
1108
|
-
if (await fs.pathExists(candidate)) return candidate;
|
|
1109
|
-
}
|
|
1110
|
-
}
|
|
1111
|
-
async function resolveStyleFile(scriptPath) {
|
|
1112
|
-
const base = scriptPath.replace(new RegExp(`${extname(scriptPath)}$`), "");
|
|
1113
|
-
for (const ext of STYLE_EXTS) {
|
|
1114
|
-
const candidate = `${base}${ext}`;
|
|
1115
|
-
if (await fs.pathExists(candidate)) return candidate;
|
|
1116
|
-
}
|
|
1117
|
-
}
|
|
1118
|
-
async function resolveTemplateFile(scriptPath) {
|
|
1119
|
-
const base = scriptPath.replace(new RegExp(`${extname(scriptPath)}$`), "");
|
|
1120
|
-
for (const ext of TEMPLATE_EXTS) {
|
|
1121
|
-
const candidate = `${base}${ext}`;
|
|
1122
|
-
if (await fs.pathExists(candidate)) return candidate;
|
|
1123
|
-
}
|
|
1124
|
-
}
|
|
1125
|
-
//#endregion
|
|
1126
|
-
//#region src/plugin/navigation.ts
|
|
1127
|
-
function pickNavigationConfig(source) {
|
|
1128
|
-
const config = {};
|
|
1129
|
-
if (!source) return config;
|
|
1130
|
-
if (typeof source.navigationBarTitleText === "string") config.title = source.navigationBarTitleText;
|
|
1131
|
-
if (typeof source.navigationBarBackgroundColor === "string") config.backgroundColor = source.navigationBarBackgroundColor;
|
|
1132
|
-
if (typeof source.navigationBarTextStyle === "string") config.textStyle = source.navigationBarTextStyle;
|
|
1133
|
-
if (typeof source.navigationStyle === "string") config.navigationStyle = source.navigationStyle;
|
|
1134
|
-
return config;
|
|
1135
|
-
}
|
|
1136
|
-
function mergeNavigationConfig(base, overrides) {
|
|
1137
|
-
return {
|
|
1138
|
-
...base,
|
|
1139
|
-
...overrides
|
|
1140
|
-
};
|
|
1141
|
-
}
|
|
1142
|
-
//#endregion
|
|
1143
|
-
//#region src/plugin/scanConfig.ts
|
|
1144
|
-
async function collectComponentTagsFromConfig({ json, importerDir, jsonPath, warn, resolveComponentScript, getComponentTag, collectComponent, onResolved }) {
|
|
1145
|
-
const usingComponents = json.usingComponents;
|
|
1146
|
-
if (!usingComponents || typeof usingComponents !== "object") return {};
|
|
1147
|
-
const tags = {};
|
|
1148
|
-
const resolved = [];
|
|
1149
|
-
for (const [rawKey, rawValue] of Object.entries(usingComponents)) {
|
|
1150
|
-
if (typeof rawValue !== "string") continue;
|
|
1151
|
-
const key = normalizeComponentKey(rawKey);
|
|
1152
|
-
if (!key) continue;
|
|
1153
|
-
const script = await resolveComponentScript(rawValue, importerDir);
|
|
1154
|
-
if (!script) {
|
|
1155
|
-
warn(`[@weapp-vite/web] usingComponents entry "${rawKey}" not found: ${rawValue} (${jsonPath})`);
|
|
1156
|
-
continue;
|
|
1157
|
-
}
|
|
1158
|
-
tags[key] = getComponentTag(script);
|
|
1159
|
-
resolved.push({ rawValue });
|
|
1160
|
-
}
|
|
1161
|
-
onResolved?.(tags);
|
|
1162
|
-
for (const entry of resolved) await collectComponent(entry.rawValue, importerDir);
|
|
1163
|
-
return tags;
|
|
1164
|
-
}
|
|
1165
|
-
async function collectComponentTagsFromJson({ jsonBasePath, importerDir, warn, collectFromConfig }) {
|
|
1166
|
-
const resolvedPath = await resolveJsonPath(jsonBasePath);
|
|
1167
|
-
if (!resolvedPath) return {};
|
|
1168
|
-
const json = await readJsonFile(resolvedPath);
|
|
1169
|
-
if (!json) return {};
|
|
1170
|
-
return collectFromConfig(json, importerDir, resolvedPath, warn);
|
|
1171
|
-
}
|
|
1172
|
-
function mergeComponentTags(base, overrides) {
|
|
1173
|
-
if (!Object.keys(base).length && !Object.keys(overrides).length) return {};
|
|
1174
|
-
return {
|
|
1175
|
-
...base,
|
|
1176
|
-
...overrides
|
|
1177
|
-
};
|
|
1178
|
-
}
|
|
1179
|
-
function normalizeComponentKey(raw) {
|
|
1180
|
-
return raw.trim().toLowerCase();
|
|
1181
|
-
}
|
|
1182
|
-
//#endregion
|
|
1183
|
-
//#region src/plugin/scan.ts
|
|
1184
|
-
async function scanProject({ srcRoot, warn, state }) {
|
|
1185
|
-
state.moduleMeta.clear();
|
|
1186
|
-
state.pageNavigationMap.clear();
|
|
1187
|
-
state.templateComponentMap.clear();
|
|
1188
|
-
state.templatePathSet.clear();
|
|
1189
|
-
state.componentTagMap.clear();
|
|
1190
|
-
state.componentIdMap.clear();
|
|
1191
|
-
let appNavigationDefaults = {};
|
|
1192
|
-
let appComponentTags = {};
|
|
1193
|
-
const pages = /* @__PURE__ */ new Map();
|
|
1194
|
-
const components = /* @__PURE__ */ new Map();
|
|
1195
|
-
const reportWarning = (message) => {
|
|
1196
|
-
if (warn) {
|
|
1197
|
-
warn(message);
|
|
1198
|
-
return;
|
|
1199
|
-
}
|
|
1200
|
-
if (typeof process !== "undefined" && typeof process.emitWarning === "function") process.emitWarning(message);
|
|
1201
|
-
};
|
|
1202
|
-
const appScript = await resolveScriptFile(join(srcRoot, "app"));
|
|
1203
|
-
if (appScript) state.moduleMeta.set(normalizePath(appScript), {
|
|
1204
|
-
kind: "app",
|
|
1205
|
-
id: "app",
|
|
1206
|
-
scriptPath: appScript,
|
|
1207
|
-
stylePath: await resolveStyleFile(appScript)
|
|
1208
|
-
});
|
|
1209
|
-
const resolveComponentScript = async (raw, importerDir) => {
|
|
1210
|
-
const base = resolveComponentBase(raw, importerDir, srcRoot);
|
|
1211
|
-
if (!base) return;
|
|
1212
|
-
return resolveScriptFile(base);
|
|
1213
|
-
};
|
|
1214
|
-
const getComponentId = (script) => {
|
|
1215
|
-
const cached = state.componentIdMap.get(script);
|
|
1216
|
-
if (cached) return cached;
|
|
1217
|
-
const componentIdPosix = toPosixId(relative(srcRoot, script).replace(new RegExp(`${extname(script)}$`), ""));
|
|
1218
|
-
state.componentIdMap.set(script, componentIdPosix);
|
|
1219
|
-
return componentIdPosix;
|
|
1220
|
-
};
|
|
1221
|
-
const getComponentTag = (script) => {
|
|
1222
|
-
const cached = state.componentTagMap.get(script);
|
|
1223
|
-
if (cached) return cached;
|
|
1224
|
-
const tag = slugify(getComponentId(script), "wv-component");
|
|
1225
|
-
state.componentTagMap.set(script, tag);
|
|
1226
|
-
return tag;
|
|
1227
|
-
};
|
|
1228
|
-
const collectComponent = async (componentId, importerDir) => {
|
|
1229
|
-
const base = resolveComponentBase(componentId, importerDir, srcRoot);
|
|
1230
|
-
const script = base ? await resolveScriptFile(base) : void 0;
|
|
1231
|
-
if (!script || components.has(script)) return;
|
|
1232
|
-
const componentIdPosix = toPosixId(relative(srcRoot, script).replace(new RegExp(`${extname(script)}$`), ""));
|
|
1233
|
-
const template = await resolveTemplateFile(script);
|
|
1234
|
-
const style = await resolveStyleFile(script);
|
|
1235
|
-
if (template) state.templatePathSet.add(normalizePath(template));
|
|
1236
|
-
state.moduleMeta.set(normalizePath(script), {
|
|
1237
|
-
kind: "component",
|
|
1238
|
-
id: componentIdPosix,
|
|
1239
|
-
scriptPath: script,
|
|
1240
|
-
templatePath: template,
|
|
1241
|
-
stylePath: style
|
|
1242
|
-
});
|
|
1243
|
-
components.set(script, {
|
|
1244
|
-
script,
|
|
1245
|
-
id: componentIdPosix
|
|
1246
|
-
});
|
|
1247
|
-
const componentTags = await collectComponentTagsFromJson({
|
|
1248
|
-
jsonBasePath: `${script.replace(new RegExp(`${extname(script)}$`), "")}.json`,
|
|
1249
|
-
importerDir: dirname(script),
|
|
1250
|
-
warn: reportWarning,
|
|
1251
|
-
collectFromConfig: (json, nextImporterDir, jsonPath, nextWarn) => collectComponentTagsFromConfig({
|
|
1252
|
-
json,
|
|
1253
|
-
importerDir: nextImporterDir,
|
|
1254
|
-
jsonPath,
|
|
1255
|
-
warn: nextWarn,
|
|
1256
|
-
resolveComponentScript,
|
|
1257
|
-
getComponentTag,
|
|
1258
|
-
collectComponent
|
|
1259
|
-
})
|
|
1260
|
-
});
|
|
1261
|
-
if (!template) return;
|
|
1262
|
-
const mergedTags = mergeComponentTags(appComponentTags, componentTags);
|
|
1263
|
-
if (Object.keys(mergedTags).length > 0) {
|
|
1264
|
-
state.templateComponentMap.set(normalizePath(template), mergedTags);
|
|
1265
|
-
return;
|
|
1266
|
-
}
|
|
1267
|
-
state.templateComponentMap.delete(normalizePath(template));
|
|
1268
|
-
};
|
|
1269
|
-
const appJsonPath = await resolveJsonPath(join(srcRoot, "app.json"));
|
|
1270
|
-
if (appJsonPath) {
|
|
1271
|
-
const appJson = await readJsonFile(appJsonPath);
|
|
1272
|
-
if (appJson) appComponentTags = await collectComponentTagsFromConfig({
|
|
1273
|
-
json: appJson,
|
|
1274
|
-
importerDir: srcRoot,
|
|
1275
|
-
jsonPath: appJsonPath,
|
|
1276
|
-
warn: reportWarning,
|
|
1277
|
-
resolveComponentScript,
|
|
1278
|
-
getComponentTag,
|
|
1279
|
-
collectComponent,
|
|
1280
|
-
onResolved: (tags) => {
|
|
1281
|
-
appComponentTags = tags;
|
|
1282
|
-
}
|
|
1283
|
-
});
|
|
1284
|
-
if (appJson?.pages && Array.isArray(appJson.pages)) {
|
|
1285
|
-
for (const page of appJson.pages) if (typeof page === "string") await collectPage(page);
|
|
1286
|
-
}
|
|
1287
|
-
if (appJson?.subPackages && Array.isArray(appJson.subPackages)) for (const pkg of appJson.subPackages) {
|
|
1288
|
-
if (!pkg || typeof pkg !== "object" || !Array.isArray(pkg.pages)) continue;
|
|
1289
|
-
const root = typeof pkg.root === "string" ? pkg.root : "";
|
|
1290
|
-
for (const page of pkg.pages) {
|
|
1291
|
-
if (typeof page !== "string") continue;
|
|
1292
|
-
await collectPage(posix.join(root, page));
|
|
1293
|
-
}
|
|
1294
|
-
}
|
|
1295
|
-
appNavigationDefaults = pickNavigationConfig(isRecord(appJson?.window) ? appJson.window : void 0);
|
|
1296
|
-
}
|
|
1297
|
-
state.appNavigationDefaults = appNavigationDefaults;
|
|
1298
|
-
state.appComponentTags = appComponentTags;
|
|
1299
|
-
state.scanResult = {
|
|
1300
|
-
app: appScript,
|
|
1301
|
-
pages: Array.from(pages.values()),
|
|
1302
|
-
components: Array.from(components.values())
|
|
1303
|
-
};
|
|
1304
|
-
async function collectPage(pageId) {
|
|
1305
|
-
const base = join(srcRoot, pageId);
|
|
1306
|
-
const script = await resolveScriptFile(base);
|
|
1307
|
-
if (!script) return;
|
|
1308
|
-
const template = await resolveTemplateFile(base);
|
|
1309
|
-
if (template) state.templatePathSet.add(normalizePath(template));
|
|
1310
|
-
const style = await resolveStyleFile(base);
|
|
1311
|
-
const pageJsonBasePath = join(srcRoot, `${pageId}.json`);
|
|
1312
|
-
const pageJsonPath = await resolveJsonPath(pageJsonBasePath);
|
|
1313
|
-
const pageJson = pageJsonPath ? await readJsonFile(pageJsonPath) : void 0;
|
|
1314
|
-
state.moduleMeta.set(normalizePath(script), {
|
|
1315
|
-
kind: "page",
|
|
1316
|
-
id: toPosixId(pageId),
|
|
1317
|
-
scriptPath: script,
|
|
1318
|
-
templatePath: template,
|
|
1319
|
-
stylePath: style
|
|
1320
|
-
});
|
|
1321
|
-
pages.set(script, {
|
|
1322
|
-
script,
|
|
1323
|
-
id: toPosixId(pageId)
|
|
1324
|
-
});
|
|
1325
|
-
const pageComponentTags = pageJson && pageJsonPath ? await collectComponentTagsFromConfig({
|
|
1326
|
-
json: pageJson,
|
|
1327
|
-
importerDir: dirname(script),
|
|
1328
|
-
jsonPath: pageJsonPath,
|
|
1329
|
-
warn: reportWarning,
|
|
1330
|
-
resolveComponentScript,
|
|
1331
|
-
getComponentTag,
|
|
1332
|
-
collectComponent
|
|
1333
|
-
}) : await collectComponentTagsFromJson({
|
|
1334
|
-
jsonBasePath: pageJsonBasePath,
|
|
1335
|
-
importerDir: dirname(script),
|
|
1336
|
-
warn: reportWarning,
|
|
1337
|
-
collectFromConfig: (json, importerDir, jsonPath, nextWarn) => collectComponentTagsFromConfig({
|
|
1338
|
-
json,
|
|
1339
|
-
importerDir,
|
|
1340
|
-
jsonPath,
|
|
1341
|
-
warn: nextWarn,
|
|
1342
|
-
resolveComponentScript,
|
|
1343
|
-
getComponentTag,
|
|
1344
|
-
collectComponent
|
|
1345
|
-
})
|
|
1346
|
-
});
|
|
1347
|
-
if (template) {
|
|
1348
|
-
const mergedTags = mergeComponentTags(appComponentTags, pageComponentTags);
|
|
1349
|
-
if (Object.keys(mergedTags).length > 0) state.templateComponentMap.set(normalizePath(template), mergedTags);
|
|
1350
|
-
else state.templateComponentMap.delete(normalizePath(template));
|
|
1351
|
-
}
|
|
1352
|
-
if (!template) return;
|
|
1353
|
-
if (pageJson) {
|
|
1354
|
-
state.pageNavigationMap.set(normalizePath(template), mergeNavigationConfig(appNavigationDefaults, pickNavigationConfig(pageJson)));
|
|
1355
|
-
return;
|
|
1356
|
-
}
|
|
1357
|
-
state.pageNavigationMap.set(normalizePath(template), { ...appNavigationDefaults });
|
|
1358
|
-
}
|
|
1359
|
-
}
|
|
1360
|
-
function resolveComponentBase(raw, importerDir, srcRoot) {
|
|
1361
|
-
if (!raw) return;
|
|
1362
|
-
if (raw.startsWith(".")) return resolve(importerDir, raw);
|
|
1363
|
-
if (raw.startsWith("/")) return resolve(srcRoot, raw.slice(1));
|
|
1364
|
-
return resolve(srcRoot, raw);
|
|
1365
|
-
}
|
|
1366
|
-
//#endregion
|
|
1367
|
-
//#region src/plugin/state.ts
|
|
1368
|
-
function createEmptyScanState() {
|
|
1369
|
-
return {
|
|
1370
|
-
moduleMeta: /* @__PURE__ */ new Map(),
|
|
1371
|
-
pageNavigationMap: /* @__PURE__ */ new Map(),
|
|
1372
|
-
templateComponentMap: /* @__PURE__ */ new Map(),
|
|
1373
|
-
templatePathSet: /* @__PURE__ */ new Set(),
|
|
1374
|
-
componentTagMap: /* @__PURE__ */ new Map(),
|
|
1375
|
-
componentIdMap: /* @__PURE__ */ new Map(),
|
|
1376
|
-
appNavigationDefaults: {},
|
|
1377
|
-
appComponentTags: {},
|
|
1378
|
-
scanResult: {
|
|
1379
|
-
app: void 0,
|
|
1380
|
-
pages: [],
|
|
1381
|
-
components: []
|
|
1382
|
-
}
|
|
1383
|
-
};
|
|
1384
|
-
}
|
|
1385
|
-
//#endregion
|
|
1386
|
-
//#region src/plugin/index.ts
|
|
1387
|
-
function isTemplateFile(id) {
|
|
1388
|
-
const lower = id.toLowerCase();
|
|
1389
|
-
return TEMPLATE_EXTS.some((ext) => lower.endsWith(ext));
|
|
1390
|
-
}
|
|
1391
|
-
function isWxsFile(id) {
|
|
1392
|
-
const lower = id.toLowerCase();
|
|
1393
|
-
return WXS_EXTS.some((ext) => lower.endsWith(ext));
|
|
1394
|
-
}
|
|
1395
|
-
function hasWxsQuery(id) {
|
|
1396
|
-
return id.includes("?wxs") || id.includes("&wxs");
|
|
1397
|
-
}
|
|
1398
|
-
function createInlineStyleModule(css) {
|
|
1399
|
-
return [
|
|
1400
|
-
`const __weapp_injected_styles__ = new Map()`,
|
|
1401
|
-
`function __weapp_createStyleId__(css) {`,
|
|
1402
|
-
` let hash = 2166136261`,
|
|
1403
|
-
` for (let i = 0; i < css.length; i++) {`,
|
|
1404
|
-
` hash ^= css.charCodeAt(i)`,
|
|
1405
|
-
` hash += (hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24)`,
|
|
1406
|
-
` }`,
|
|
1407
|
-
` return 'weapp-web-style-' + (hash >>> 0).toString(36)`,
|
|
1408
|
-
`}`,
|
|
1409
|
-
`function __weapp_removeStyle__(id) {`,
|
|
1410
|
-
` if (typeof document === 'undefined') {`,
|
|
1411
|
-
` return`,
|
|
1412
|
-
` }`,
|
|
1413
|
-
` const style = __weapp_injected_styles__.get(id)`,
|
|
1414
|
-
` if (style) {`,
|
|
1415
|
-
` style.remove()`,
|
|
1416
|
-
` __weapp_injected_styles__.delete(id)`,
|
|
1417
|
-
` }`,
|
|
1418
|
-
`}`,
|
|
1419
|
-
`function injectStyle(css, id) {`,
|
|
1420
|
-
` if (typeof document === 'undefined') {`,
|
|
1421
|
-
` return () => {}`,
|
|
1422
|
-
` }`,
|
|
1423
|
-
` const styleId = id ?? __weapp_createStyleId__(css)`,
|
|
1424
|
-
` const existing = __weapp_injected_styles__.get(styleId)`,
|
|
1425
|
-
` if (existing) {`,
|
|
1426
|
-
` if (existing.textContent !== css) {`,
|
|
1427
|
-
` existing.textContent = css`,
|
|
1428
|
-
` }`,
|
|
1429
|
-
` return () => __weapp_removeStyle__(styleId)`,
|
|
1430
|
-
` }`,
|
|
1431
|
-
` const style = document.createElement('style')`,
|
|
1432
|
-
` style.id = styleId`,
|
|
1433
|
-
` style.textContent = css`,
|
|
1434
|
-
` document.head.append(style)`,
|
|
1435
|
-
` __weapp_injected_styles__.set(styleId, style)`,
|
|
1436
|
-
` return () => __weapp_removeStyle__(styleId)`,
|
|
1437
|
-
`}`,
|
|
1438
|
-
`const css = ${JSON.stringify(css)}`,
|
|
1439
|
-
`export default css`,
|
|
1440
|
-
`export function useStyle(id) {`,
|
|
1441
|
-
` return injectStyle(css, id)`,
|
|
1442
|
-
`}`
|
|
1443
|
-
].join("\n");
|
|
1444
|
-
}
|
|
1445
|
-
function weappWebPlugin(options = {}) {
|
|
1446
|
-
let root = process.cwd();
|
|
1447
|
-
let srcRoot = resolve(root, options.srcDir ?? "src");
|
|
1448
|
-
let enableHmr = false;
|
|
1449
|
-
const state = createEmptyScanState();
|
|
1450
|
-
const wxssOptions = options.wxss;
|
|
1451
|
-
const resolveTemplatePath = (raw, importer) => resolveTemplatePathSync(raw, importer, srcRoot);
|
|
1452
|
-
const resolveWxsPath = (raw, importer) => resolveWxsPathSync(raw, importer, srcRoot);
|
|
1453
|
-
return {
|
|
1454
|
-
name: "@weapp-vite/web",
|
|
1455
|
-
enforce: "pre",
|
|
1456
|
-
async configResolved(config) {
|
|
1457
|
-
root = config.root;
|
|
1458
|
-
srcRoot = resolve(root, options.srcDir ?? "src");
|
|
1459
|
-
enableHmr = config.command === "serve";
|
|
1460
|
-
await scanProject({
|
|
1461
|
-
srcRoot,
|
|
1462
|
-
warn: this.warn?.bind(this),
|
|
1463
|
-
state
|
|
1464
|
-
});
|
|
1465
|
-
},
|
|
1466
|
-
async buildStart() {
|
|
1467
|
-
await scanProject({
|
|
1468
|
-
srcRoot,
|
|
1469
|
-
warn: this.warn?.bind(this),
|
|
1470
|
-
state
|
|
1471
|
-
});
|
|
1472
|
-
},
|
|
1473
|
-
resolveId(id) {
|
|
1474
|
-
if (id === "/@weapp-vite/web/entry" || id === "@weapp-vite/web/entry") return ENTRY_ID;
|
|
1475
|
-
return null;
|
|
1476
|
-
},
|
|
1477
|
-
load(id) {
|
|
1478
|
-
if (id === "\0@weapp-vite/web/entry") return generateEntryModule(state.scanResult, root, wxssOptions, options);
|
|
1479
|
-
return null;
|
|
1480
|
-
},
|
|
1481
|
-
async handleHotUpdate(ctx) {
|
|
1482
|
-
const clean = cleanUrl(ctx.file);
|
|
1483
|
-
if (clean.endsWith(".json") || isTemplateFile(clean) || isWxsFile(clean) || clean.endsWith(".wxss") || SCRIPT_EXTS.includes(extname(clean))) await scanProject({
|
|
1484
|
-
srcRoot,
|
|
1485
|
-
warn: this.warn?.bind(this),
|
|
1486
|
-
state
|
|
1487
|
-
});
|
|
1488
|
-
},
|
|
1489
|
-
transform(code, id) {
|
|
1490
|
-
const clean = cleanUrl(id);
|
|
1491
|
-
if (isTemplateFile(clean)) {
|
|
1492
|
-
if (isHtmlEntry(clean, root)) return null;
|
|
1493
|
-
const normalizedId = normalizePath(clean);
|
|
1494
|
-
if (state.templatePathSet.size > 0) {
|
|
1495
|
-
if (!isInsideDir(clean, srcRoot)) return null;
|
|
1496
|
-
if (!state.templatePathSet.has(normalizedId)) return null;
|
|
1497
|
-
}
|
|
1498
|
-
const navigationConfig = state.pageNavigationMap.get(normalizedId);
|
|
1499
|
-
const componentTags = state.templateComponentMap.get(normalizedId);
|
|
1500
|
-
const { code: compiled, dependencies, warnings } = compileWxml({
|
|
1501
|
-
id: clean,
|
|
1502
|
-
source: code,
|
|
1503
|
-
resolveTemplatePath,
|
|
1504
|
-
resolveWxsPath,
|
|
1505
|
-
navigationBar: navigationConfig ? { config: navigationConfig } : void 0,
|
|
1506
|
-
componentTags
|
|
1507
|
-
});
|
|
1508
|
-
if (dependencies.length > 0 && "addWatchFile" in this) for (const dep of dependencies) this.addWatchFile(dep);
|
|
1509
|
-
if (warnings?.length && "warn" in this) for (const warning of warnings) this.warn(warning);
|
|
1510
|
-
return {
|
|
1511
|
-
code: compiled,
|
|
1512
|
-
map: null
|
|
1513
|
-
};
|
|
1514
|
-
}
|
|
1515
|
-
if (isWxsFile(clean) || hasWxsQuery(id)) {
|
|
1516
|
-
const { code: compiled, dependencies, warnings } = transformWxsToEsm(code, clean, {
|
|
1517
|
-
resolvePath: resolveWxsPath,
|
|
1518
|
-
toImportPath: (resolved, importer) => normalizePath(toRelativeImport(importer, resolved))
|
|
1519
|
-
});
|
|
1520
|
-
if (dependencies.length > 0 && "addWatchFile" in this) for (const dep of dependencies) this.addWatchFile(dep);
|
|
1521
|
-
if (warnings?.length && "warn" in this) for (const warning of warnings) this.warn(warning);
|
|
1522
|
-
return {
|
|
1523
|
-
code: compiled,
|
|
1524
|
-
map: null
|
|
1525
|
-
};
|
|
1526
|
-
}
|
|
1527
|
-
if (TRANSFORM_STYLE_EXTS.some((ext) => clean.endsWith(ext))) {
|
|
1528
|
-
const { css } = transformWxssToCss(code, wxssOptions);
|
|
1529
|
-
return {
|
|
1530
|
-
code: createInlineStyleModule(css),
|
|
1531
|
-
map: null
|
|
1532
|
-
};
|
|
1533
|
-
}
|
|
1534
|
-
if (STYLE_EXTS.some((ext) => clean.endsWith(ext)) && !clean.endsWith(".wxss")) {
|
|
1535
|
-
const { css } = transformWxssToCss(code, wxssOptions);
|
|
1536
|
-
return {
|
|
1537
|
-
code: css,
|
|
1538
|
-
map: null
|
|
1539
|
-
};
|
|
1540
|
-
}
|
|
1541
|
-
if (!SCRIPT_EXTS.some((ext) => clean.endsWith(ext))) return null;
|
|
1542
|
-
if (clean.includes("node_modules")) return null;
|
|
1543
|
-
const meta = state.moduleMeta.get(normalizePath(clean));
|
|
1544
|
-
if (!meta) return null;
|
|
1545
|
-
return transformScriptModule({
|
|
1546
|
-
code,
|
|
1547
|
-
cleanId: clean,
|
|
1548
|
-
meta,
|
|
1549
|
-
enableHmr
|
|
1550
|
-
});
|
|
1551
|
-
}
|
|
1552
|
-
};
|
|
1553
|
-
}
|
|
1554
|
-
//#endregion
|
|
1
|
+
import { t as weappWebPlugin } from "./plugin-CsqbKOh1.mjs";
|
|
1555
2
|
export { weappWebPlugin };
|