@dimina/compiler 1.0.16 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +23 -0
- package/dist/bin/index.cjs +17 -15
- package/dist/bin/index.js +13 -11
- package/dist/{compatibility-DlYbbw0F.cjs → compatibility-CzIJUgPs.cjs} +99 -4
- package/dist/{compatibility-C_zWVjYl.js → compatibility-DdxfVhcK.js} +94 -4
- package/dist/core/logic-compiler.cjs +16 -18
- package/dist/core/logic-compiler.js +13 -16
- package/dist/core/style-compiler.cjs +62 -61
- package/dist/core/style-compiler.js +53 -53
- package/dist/core/view-compiler.cjs +232 -111
- package/dist/core/view-compiler.js +224 -107
- package/dist/{env-Dmnqp9bD.cjs → env-B4U3zZUm.cjs} +297 -65
- package/dist/{env-p9Az8lv5.js → env-OH3--qg8.js} +250 -28
- package/dist/index.cjs +124 -32
- package/dist/index.js +119 -28
- package/dist/rolldown-runtime-D6vf50IK.cjs +28 -0
- package/package.json +15 -11
|
@@ -2,6 +2,9 @@ import path from "node:path";
|
|
|
2
2
|
import process from "node:process";
|
|
3
3
|
import fs from "node:fs";
|
|
4
4
|
import os from "node:os";
|
|
5
|
+
import { parseSync } from "oxc-parser";
|
|
6
|
+
import { walk } from "oxc-walker";
|
|
7
|
+
import crypto from "node:crypto";
|
|
5
8
|
//#region src/common/path-utils.js
|
|
6
9
|
var WINDOWS_FS_PATH_RE = /^(?:[a-zA-Z]:[\\/]|\\\\)/;
|
|
7
10
|
function isWindowsFsPath(targetPath) {
|
|
@@ -29,19 +32,6 @@ function getRelativePosixPath(targetPath, rootPath) {
|
|
|
29
32
|
return normalizeToPosixPath(targetPath).replace(normalizeToPosixPath(rootPath), "").replace(/^\//, "");
|
|
30
33
|
}
|
|
31
34
|
//#endregion
|
|
32
|
-
//#region src/common/art.js
|
|
33
|
-
var artCode = `
|
|
34
|
-
██████╗ ██╗███╗ ███╗██╗███╗ ██╗ █████╗
|
|
35
|
-
██╔══██╗██║████╗ ████║██║████╗ ██║██╔══██╗
|
|
36
|
-
██║ ██║██║██╔████╔██║██║██╔██╗ ██║███████║
|
|
37
|
-
██║ ██║██║██║╚██╔╝██║██║██║╚██╗██║██╔══██║
|
|
38
|
-
██████╔╝██║██║ ╚═╝ ██║██║██║ ╚████║██║ ██║
|
|
39
|
-
╚═════╝ ╚═╝╚═╝ ╚═╝╚═╝╚═╝ ╚═══╝╚═╝ ╚═╝
|
|
40
|
-
`;
|
|
41
|
-
function art_default() {
|
|
42
|
-
console.log(artCode);
|
|
43
|
-
}
|
|
44
|
-
//#endregion
|
|
45
35
|
//#region src/common/utils.js
|
|
46
36
|
function hasCompileInfo(modulePath, list, preList) {
|
|
47
37
|
const mergeList = Array.isArray(preList) ? [...preList, ...list] : list;
|
|
@@ -58,19 +48,31 @@ function getAbsolutePath(workPath, pagePath, src) {
|
|
|
58
48
|
return path.resolve(workPath, relativePath, src);
|
|
59
49
|
}
|
|
60
50
|
var assetsMap = {};
|
|
51
|
+
function isPathInside(rootPath, targetPath) {
|
|
52
|
+
const relativePath = path.relative(rootPath, targetPath);
|
|
53
|
+
return relativePath === "" || !relativePath.startsWith(`..${path.sep}`) && relativePath !== ".." && !path.isAbsolute(relativePath);
|
|
54
|
+
}
|
|
55
|
+
function resolveAssetSourcePath(workPath, pagePath, src) {
|
|
56
|
+
const projectRoot = path.resolve(workPath);
|
|
57
|
+
if (src.startsWith("/")) return path.resolve(projectRoot, `.${src}`);
|
|
58
|
+
const normalizedPagePath = path.resolve(pagePath);
|
|
59
|
+
const pageDirectory = path.isAbsolute(pagePath) && isPathInside(projectRoot, normalizedPagePath) ? path.dirname(normalizedPagePath) : path.resolve(projectRoot, path.dirname(pagePath.replace(/^[/\\]+/, "")));
|
|
60
|
+
const resolvedPath = path.resolve(pageDirectory, src);
|
|
61
|
+
if (isPathInside(projectRoot, resolvedPath)) return resolvedPath;
|
|
62
|
+
return path.resolve(projectRoot, src.replace(/^(?:\.\.[/\\])+/, ""));
|
|
63
|
+
}
|
|
61
64
|
/**
|
|
62
65
|
* 将静态资源存储到 static 文件夹
|
|
63
66
|
*/
|
|
64
67
|
function collectAssets(workPath, pagePath, src, targetPath, appId) {
|
|
65
68
|
if (src.startsWith("http") || src.startsWith("//")) return src;
|
|
66
69
|
if (!/\.(?:png|jpe?g|gif|svg)(?:\?.*)?$/.test(src)) return src;
|
|
67
|
-
const
|
|
68
|
-
const absolutePath = src.startsWith("/") ? workPath + src : path.resolve(workPath, relativePath, src);
|
|
70
|
+
const absolutePath = resolveAssetSourcePath(workPath, pagePath, src);
|
|
69
71
|
if (assetsMap[absolutePath]) return assetsMap[absolutePath];
|
|
70
72
|
try {
|
|
71
73
|
const ext = `.${src.split(".").pop()}`;
|
|
72
74
|
const dirPath = absolutePath.split(path.sep).slice(0, -1).join("/");
|
|
73
|
-
const prefix = uuid();
|
|
75
|
+
const prefix = uuid(dirPath);
|
|
74
76
|
const targetStatic = `${targetPath}/main/static`;
|
|
75
77
|
if (!fs.existsSync(targetStatic)) fs.mkdirSync(targetStatic, { recursive: true });
|
|
76
78
|
getFilesWithExtension(dirPath, ext).forEach((file) => {
|
|
@@ -96,15 +98,16 @@ function isString(o) {
|
|
|
96
98
|
function transformRpx(styleText) {
|
|
97
99
|
if (!isString(styleText)) return styleText;
|
|
98
100
|
return styleText.replace(/([+-]?\d+(?:\.\d+)?)rpx/g, (_, pixel) => {
|
|
99
|
-
|
|
101
|
+
const viewportWidth = Number((Number(pixel) / 7.5).toFixed(6));
|
|
102
|
+
return `${Object.is(viewportWidth, -0) ? 0 : viewportWidth}vw`;
|
|
100
103
|
});
|
|
101
104
|
}
|
|
102
|
-
function uuid() {
|
|
103
|
-
return
|
|
105
|
+
function uuid(str) {
|
|
106
|
+
return crypto.createHash("sha256").update(str).digest().readBigUInt64BE(0).toString(36);
|
|
104
107
|
}
|
|
105
108
|
var tagWhiteList = [
|
|
106
109
|
"page",
|
|
107
|
-
"
|
|
110
|
+
"component-host",
|
|
108
111
|
"block",
|
|
109
112
|
"button",
|
|
110
113
|
"camera",
|
|
@@ -145,6 +148,24 @@ var tagWhiteList = [
|
|
|
145
148
|
"view",
|
|
146
149
|
"web-view"
|
|
147
150
|
];
|
|
151
|
+
var miniProgramBuiltinTags = /* @__PURE__ */ new Set([
|
|
152
|
+
...tagWhiteList,
|
|
153
|
+
"canvas",
|
|
154
|
+
"match-media",
|
|
155
|
+
"page-container",
|
|
156
|
+
"share-element",
|
|
157
|
+
"editor",
|
|
158
|
+
"audio",
|
|
159
|
+
"channel-live",
|
|
160
|
+
"channel-video",
|
|
161
|
+
"live-player",
|
|
162
|
+
"live-pusher",
|
|
163
|
+
"voip-room",
|
|
164
|
+
"ad",
|
|
165
|
+
"ad-custom",
|
|
166
|
+
"official-account",
|
|
167
|
+
"xr-frame"
|
|
168
|
+
]);
|
|
148
169
|
//#endregion
|
|
149
170
|
//#region src/common/npm-resolver.js
|
|
150
171
|
/**
|
|
@@ -317,24 +338,119 @@ var NpmResolver = class {
|
|
|
317
338
|
var pathInfo = {};
|
|
318
339
|
var configInfo = {};
|
|
319
340
|
var npmResolver = null;
|
|
341
|
+
var DEFAULT_TEMPLATE_EXTS = [".wxml", ".ddml"];
|
|
342
|
+
var DEFAULT_STYLE_EXTS = [
|
|
343
|
+
".wxss",
|
|
344
|
+
".ddss",
|
|
345
|
+
".less",
|
|
346
|
+
".scss",
|
|
347
|
+
".sass"
|
|
348
|
+
];
|
|
349
|
+
var DEFAULT_VIEW_SCRIPT_EXTS = [".wxs"];
|
|
350
|
+
var DEFAULT_VIEW_SCRIPT_TAGS = ["wxs", "dds"];
|
|
351
|
+
var CUSTOM_TAB_BAR_COMPONENT_PATH = "/custom-tab-bar/index";
|
|
352
|
+
var STYLE_ISOLATION_VALUES = /* @__PURE__ */ new Set([
|
|
353
|
+
"isolated",
|
|
354
|
+
"apply-shared",
|
|
355
|
+
"shared"
|
|
356
|
+
]);
|
|
357
|
+
var RESERVED_EXTS = /* @__PURE__ */ new Set([
|
|
358
|
+
...DEFAULT_TEMPLATE_EXTS,
|
|
359
|
+
...DEFAULT_STYLE_EXTS,
|
|
360
|
+
...DEFAULT_VIEW_SCRIPT_EXTS,
|
|
361
|
+
".js",
|
|
362
|
+
".ts",
|
|
363
|
+
".json"
|
|
364
|
+
]);
|
|
365
|
+
var compilerOptions = normalizeFileTypes();
|
|
366
|
+
/**
|
|
367
|
+
* 将单项规范化为扩展名:去除首尾空白、转小写并补一个前导点。
|
|
368
|
+
* 仅接受字母、数字、连字符和下划线;空字符串、路径分隔符或其他元字符
|
|
369
|
+
* 均返回 null,由调用方丢弃。扩展名会用于生成尾部匹配正则和查找文件,
|
|
370
|
+
* 放行元字符可能导致误匹配。
|
|
371
|
+
*/
|
|
372
|
+
function normalizeExt(raw) {
|
|
373
|
+
if (typeof raw !== "string") return null;
|
|
374
|
+
const v = raw.trim().toLowerCase().replace(/^\.+/, "");
|
|
375
|
+
if (!/^[a-z0-9_-]+$/.test(v)) return null;
|
|
376
|
+
return `.${v}`;
|
|
377
|
+
}
|
|
378
|
+
/**
|
|
379
|
+
* 将单项规范化为内联标签名:去除首尾空白、转小写并移除前导点。
|
|
380
|
+
* 标签名会用于拼接 Cheerio 选择器(如 transTagWxs),因此必须以字母开头,
|
|
381
|
+
* 且只能包含字母、数字、连字符和下划线。拒绝选择器元字符,避免 'qds,view'
|
|
382
|
+
* 误选并删除 <view>,破坏编译产物。
|
|
383
|
+
*/
|
|
384
|
+
function normalizeTag(raw) {
|
|
385
|
+
if (typeof raw !== "string") return null;
|
|
386
|
+
const v = raw.trim().toLowerCase().replace(/^\.+/, "");
|
|
387
|
+
if (!/^[a-z][a-z0-9_-]*$/.test(v)) return null;
|
|
388
|
+
return v;
|
|
389
|
+
}
|
|
390
|
+
/**
|
|
391
|
+
* 合并并去重内置项和自定义项;内置项在前,顺序即同名文件的查找优先级。
|
|
392
|
+
* 传入 reserved 时,落在其中的自定义项被丢弃(防止占用其他角色/逻辑/配置的扩展名)。
|
|
393
|
+
*/
|
|
394
|
+
function mergeUnique(builtins, custom, normalizer, reserved) {
|
|
395
|
+
const out = [...builtins];
|
|
396
|
+
const seen = new Set(builtins);
|
|
397
|
+
if (Array.isArray(custom)) for (const raw of custom) {
|
|
398
|
+
const n = normalizer(raw);
|
|
399
|
+
if (n && !seen.has(n) && !reserved?.has(n)) {
|
|
400
|
+
seen.add(n);
|
|
401
|
+
out.push(n);
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
return out;
|
|
405
|
+
}
|
|
406
|
+
/**
|
|
407
|
+
* 根据 options.fileTypes 生成本次构建使用的自定义扩展名和标签。
|
|
408
|
+
* viewScript 同时用于生成文件扩展名和内联标签。
|
|
409
|
+
*/
|
|
410
|
+
function normalizeFileTypes(fileTypes = {}) {
|
|
411
|
+
const ft = fileTypes || {};
|
|
412
|
+
return {
|
|
413
|
+
templateExts: mergeUnique(DEFAULT_TEMPLATE_EXTS, ft.template, normalizeExt, RESERVED_EXTS),
|
|
414
|
+
styleExts: mergeUnique(DEFAULT_STYLE_EXTS, ft.style, normalizeExt, RESERVED_EXTS),
|
|
415
|
+
viewScriptExts: mergeUnique(DEFAULT_VIEW_SCRIPT_EXTS, ft.viewScript, normalizeExt, RESERVED_EXTS),
|
|
416
|
+
viewScriptTags: mergeUnique(DEFAULT_VIEW_SCRIPT_TAGS, ft.viewScript, normalizeTag)
|
|
417
|
+
};
|
|
418
|
+
}
|
|
320
419
|
/**
|
|
321
420
|
* 持久化编译过程的上下文
|
|
421
|
+
* @param {string} workPath 编译工作目录
|
|
422
|
+
* @param {{ fileTypes?: { template?: string[], style?: string[], viewScript?: string[] } }} [options] 构建选项
|
|
322
423
|
*/
|
|
323
|
-
function storeInfo(workPath) {
|
|
424
|
+
function storeInfo(workPath, options = {}) {
|
|
324
425
|
storePathInfo(workPath);
|
|
325
426
|
storeProjectConfig();
|
|
326
427
|
storeAppConfig();
|
|
327
428
|
storePageConfig();
|
|
429
|
+
compilerOptions = normalizeFileTypes(options.fileTypes);
|
|
328
430
|
return {
|
|
329
431
|
pathInfo,
|
|
330
|
-
configInfo
|
|
432
|
+
configInfo,
|
|
433
|
+
compilerOptions
|
|
331
434
|
};
|
|
332
435
|
}
|
|
333
436
|
function resetStoreInfo(opts) {
|
|
334
437
|
pathInfo = opts.pathInfo;
|
|
335
438
|
configInfo = opts.configInfo;
|
|
439
|
+
compilerOptions = opts.compilerOptions || normalizeFileTypes();
|
|
336
440
|
if (pathInfo.workPath) npmResolver = new NpmResolver(pathInfo.workPath);
|
|
337
441
|
}
|
|
442
|
+
function getTemplateExts() {
|
|
443
|
+
return compilerOptions.templateExts;
|
|
444
|
+
}
|
|
445
|
+
function getStyleExts() {
|
|
446
|
+
return compilerOptions.styleExts;
|
|
447
|
+
}
|
|
448
|
+
function getViewScriptExts() {
|
|
449
|
+
return compilerOptions.viewScriptExts;
|
|
450
|
+
}
|
|
451
|
+
function getViewScriptTags() {
|
|
452
|
+
return compilerOptions.viewScriptTags;
|
|
453
|
+
}
|
|
338
454
|
function storePathInfo(workPath) {
|
|
339
455
|
pathInfo.workPath = workPath;
|
|
340
456
|
if (process.env.TARGET_PATH) pathInfo.targetPath = process.env.TARGET_PATH;
|
|
@@ -394,6 +510,43 @@ function storePageConfig() {
|
|
|
394
510
|
if (subPackages) subPackages.forEach((subPkg) => {
|
|
395
511
|
collectionPageJson(subPkg.pages, subPkg.root);
|
|
396
512
|
});
|
|
513
|
+
storeCustomTabBarConfig();
|
|
514
|
+
}
|
|
515
|
+
/**
|
|
516
|
+
* 微信会把 custom-tab-bar/index 作为每个 tab 页的直属组件创建。业务页面
|
|
517
|
+
* 不需要在 usingComponents 中显式声明它,因此编译阶段补一个内部组件引用,
|
|
518
|
+
* 让逻辑、视图和样式三个编译器都能沿现有依赖图收集该组件。
|
|
519
|
+
*/
|
|
520
|
+
function storeCustomTabBarConfig() {
|
|
521
|
+
const tabBar = configInfo.appInfo?.tabBar;
|
|
522
|
+
if (tabBar?.custom !== true || !Array.isArray(tabBar.list)) return;
|
|
523
|
+
const componentJsonPath = path.join(pathInfo.workPath, "custom-tab-bar/index.json");
|
|
524
|
+
if (!fs.existsSync(componentJsonPath)) {
|
|
525
|
+
console.warn("[env] tabBar.custom 已启用,但找不到 custom-tab-bar/index.json");
|
|
526
|
+
return;
|
|
527
|
+
}
|
|
528
|
+
const dependencyName = `dimina-${uuid(CUSTOM_TAB_BAR_COMPONENT_PATH)}`;
|
|
529
|
+
storeComponentConfig({ usingComponents: { [dependencyName]: CUSTOM_TAB_BAR_COMPONENT_PATH } }, path.join(pathInfo.workPath, "app.json"));
|
|
530
|
+
const componentConfig = configInfo.componentInfo[CUSTOM_TAB_BAR_COMPONENT_PATH];
|
|
531
|
+
if (componentConfig) componentConfig.customTabBar = true;
|
|
532
|
+
for (const item of tabBar.list) {
|
|
533
|
+
const pagePath = typeof item?.pagePath === "string" ? item.pagePath.replace(/^\/+/, "") : "";
|
|
534
|
+
if (!pagePath || !configInfo.appInfo.pages?.includes(pagePath)) continue;
|
|
535
|
+
const pageConfig = configInfo.pageInfo[pagePath] ||= {};
|
|
536
|
+
pageConfig.usingComponents ||= {};
|
|
537
|
+
const declaredComponents = {
|
|
538
|
+
...configInfo.appInfo.usingComponents || {},
|
|
539
|
+
...pageConfig.usingComponents
|
|
540
|
+
};
|
|
541
|
+
let componentName = Object.entries(declaredComponents).find(([, componentPath]) => componentPath === CUSTOM_TAB_BAR_COMPONENT_PATH)?.[0] || dependencyName;
|
|
542
|
+
let suffix = 0;
|
|
543
|
+
while (declaredComponents[componentName] && declaredComponents[componentName] !== CUSTOM_TAB_BAR_COMPONENT_PATH) {
|
|
544
|
+
suffix++;
|
|
545
|
+
componentName = `${dependencyName}-${suffix}`;
|
|
546
|
+
}
|
|
547
|
+
pageConfig.usingComponents[componentName] = CUSTOM_TAB_BAR_COMPONENT_PATH;
|
|
548
|
+
pageConfig.customTabBar = { componentName };
|
|
549
|
+
}
|
|
397
550
|
}
|
|
398
551
|
/**
|
|
399
552
|
* 匹配页面和对应的配置信息
|
|
@@ -447,19 +600,65 @@ function storeComponentConfig(pageJsonContent, pageFilePath) {
|
|
|
447
600
|
}
|
|
448
601
|
const cUsing = cContent.usingComponents || {};
|
|
449
602
|
const isComponent = cContent.component || false;
|
|
603
|
+
const styleIsolation = resolveComponentStyleIsolation(cContent, componentFilePath);
|
|
450
604
|
const cComponents = Object.keys(cUsing).reduce((acc, key) => {
|
|
451
605
|
acc[key] = getModuleId(cUsing[key], componentFilePath);
|
|
452
606
|
return acc;
|
|
453
607
|
}, {});
|
|
454
608
|
configInfo.componentInfo[moduleId] = {
|
|
455
|
-
id: uuid(),
|
|
609
|
+
id: uuid(moduleId),
|
|
456
610
|
path: moduleId,
|
|
457
611
|
component: isComponent,
|
|
612
|
+
styleIsolation,
|
|
458
613
|
usingComponents: cComponents
|
|
459
614
|
};
|
|
460
615
|
if (cContent.usingComponents && Object.keys(cContent.usingComponents).length > 0) storeComponentConfig(configInfo.componentInfo[moduleId], componentFilePath);
|
|
461
616
|
}
|
|
462
617
|
}
|
|
618
|
+
function getStaticProperty(objectExpression, propertyName) {
|
|
619
|
+
if (objectExpression?.type !== "ObjectExpression") return;
|
|
620
|
+
return objectExpression.properties?.find((property) => {
|
|
621
|
+
if (property.type !== "Property" || property.computed) return false;
|
|
622
|
+
return property.key?.name === propertyName || property.key?.value === propertyName;
|
|
623
|
+
})?.value;
|
|
624
|
+
}
|
|
625
|
+
function normalizeStyleIsolation(value) {
|
|
626
|
+
return STYLE_ISOLATION_VALUES.has(value) ? value : void 0;
|
|
627
|
+
}
|
|
628
|
+
/**
|
|
629
|
+
* styleIsolation can be declared either in component.json or in
|
|
630
|
+
* Component({ options }). The style compiler must know it before service
|
|
631
|
+
* runtime starts, so only statically-declared literal options participate.
|
|
632
|
+
* addGlobalClass is the legacy equivalent of apply-shared.
|
|
633
|
+
*/
|
|
634
|
+
function resolveComponentStyleIsolation(componentConfig, componentJsonPath) {
|
|
635
|
+
const jsonValue = normalizeStyleIsolation(componentConfig?.styleIsolation);
|
|
636
|
+
if (jsonValue) return jsonValue;
|
|
637
|
+
const basePath = componentJsonPath.replace(/\.json$/i, "");
|
|
638
|
+
const scriptPath = [".js", ".ts"].map((ext) => `${basePath}${ext}`).find((candidate) => fs.existsSync(candidate));
|
|
639
|
+
if (!scriptPath) return "isolated";
|
|
640
|
+
try {
|
|
641
|
+
const { program } = parseSync(scriptPath, getContentByPath(scriptPath), { sourceType: "unambiguous" });
|
|
642
|
+
let extractedValue;
|
|
643
|
+
walk(program, { enter(expression) {
|
|
644
|
+
if (extractedValue) return;
|
|
645
|
+
if (expression?.type !== "CallExpression" || expression.callee?.type !== "Identifier" || expression.callee.name !== "Component") return;
|
|
646
|
+
const definition = expression.arguments?.[0];
|
|
647
|
+
const options = getStaticProperty(definition, "options");
|
|
648
|
+
const styleIsolation = getStaticProperty(options, "styleIsolation")?.value;
|
|
649
|
+
const normalized = normalizeStyleIsolation(styleIsolation);
|
|
650
|
+
if (normalized) {
|
|
651
|
+
extractedValue = normalized;
|
|
652
|
+
return;
|
|
653
|
+
}
|
|
654
|
+
if (getStaticProperty(options, "addGlobalClass")?.value === true) extractedValue = "apply-shared";
|
|
655
|
+
} });
|
|
656
|
+
if (extractedValue) return extractedValue;
|
|
657
|
+
} catch (error) {
|
|
658
|
+
console.warn(`[env] 无法解析组件样式隔离配置 ${scriptPath}: ${error.message}`);
|
|
659
|
+
}
|
|
660
|
+
return "isolated";
|
|
661
|
+
}
|
|
463
662
|
/**
|
|
464
663
|
* 转化为相对小程序根目录的绝对路径,作为模块唯一性 id
|
|
465
664
|
* 支持 npm 组件解析
|
|
@@ -525,9 +724,12 @@ function getPages() {
|
|
|
525
724
|
...pageComponents
|
|
526
725
|
};
|
|
527
726
|
return {
|
|
528
|
-
id: uuid(),
|
|
727
|
+
id: uuid(path),
|
|
529
728
|
path,
|
|
530
|
-
|
|
729
|
+
appStyleScopeId: getAppStyleScopeId(),
|
|
730
|
+
sharedStyleScopeIds: collectSharedStyleScopeIds(mergedComponents),
|
|
731
|
+
usingComponents: mergedComponents,
|
|
732
|
+
customTabBar: pageInfo[path]?.customTabBar
|
|
531
733
|
};
|
|
532
734
|
});
|
|
533
735
|
const subPages = {};
|
|
@@ -544,9 +746,12 @@ function getPages() {
|
|
|
544
746
|
...pageComponents
|
|
545
747
|
};
|
|
546
748
|
return {
|
|
547
|
-
id: uuid(),
|
|
749
|
+
id: uuid(fullPath),
|
|
548
750
|
path: fullPath,
|
|
549
|
-
|
|
751
|
+
appStyleScopeId: getAppStyleScopeId(),
|
|
752
|
+
sharedStyleScopeIds: collectSharedStyleScopeIds(mergedComponents),
|
|
753
|
+
usingComponents: mergedComponents,
|
|
754
|
+
customTabBar: pageInfo[fullPath]?.customTabBar
|
|
550
755
|
};
|
|
551
756
|
})
|
|
552
757
|
};
|
|
@@ -556,5 +761,22 @@ function getPages() {
|
|
|
556
761
|
subPages
|
|
557
762
|
};
|
|
558
763
|
}
|
|
764
|
+
function collectSharedStyleScopeIds(usingComponents) {
|
|
765
|
+
const result = [];
|
|
766
|
+
const visited = /* @__PURE__ */ new Set();
|
|
767
|
+
const visit = (componentPath) => {
|
|
768
|
+
if (visited.has(componentPath)) return;
|
|
769
|
+
visited.add(componentPath);
|
|
770
|
+
const component = configInfo.componentInfo[componentPath];
|
|
771
|
+
if (!component) return;
|
|
772
|
+
if (component.styleIsolation === "shared") result.push(component.id);
|
|
773
|
+
for (const childPath of Object.values(component.usingComponents || {})) visit(childPath);
|
|
774
|
+
};
|
|
775
|
+
for (const componentPath of Object.values(usingComponents || {})) visit(componentPath);
|
|
776
|
+
return result;
|
|
777
|
+
}
|
|
778
|
+
function getAppStyleScopeId() {
|
|
779
|
+
return uuid("app");
|
|
780
|
+
}
|
|
559
781
|
//#endregion
|
|
560
|
-
export { tagWhiteList as _,
|
|
782
|
+
export { tagWhiteList as C, miniProgramBuiltinTags as S, toMiniProgramModuleId as T, resolveAppAlias as _, getComponent as a, getAbsolutePath as b, getPageConfigInfo as c, getTargetPath as d, getTemplateExts as f, resetStoreInfo as g, getWorkPath as h, getAppStyleScopeId as i, getPages as l, getViewScriptTags as m, getAppId as n, getContentByPath as o, getViewScriptExts as p, getAppName as r, getNpmResolver as s, getAppConfigInfo as t, getStyleExts as u, storeInfo as v, transformRpx as w, hasCompileInfo as x, collectAssets as y };
|
package/dist/index.cjs
CHANGED
|
@@ -1,15 +1,70 @@
|
|
|
1
|
-
const
|
|
1
|
+
const require_rolldown_runtime = require("./rolldown-runtime-D6vf50IK.cjs");
|
|
2
|
+
const require_env = require("./env-B4U3zZUm.cjs");
|
|
2
3
|
let node_path = require("node:path");
|
|
3
|
-
node_path =
|
|
4
|
+
node_path = require_rolldown_runtime.__toESM(node_path, 1);
|
|
5
|
+
let node_process = require("node:process");
|
|
6
|
+
node_process = require_rolldown_runtime.__toESM(node_process, 1);
|
|
4
7
|
let node_url = require("node:url");
|
|
5
8
|
let node_worker_threads = require("node:worker_threads");
|
|
6
9
|
let listr2 = require("listr2");
|
|
7
|
-
let node_process = require("node:process");
|
|
8
|
-
node_process = require_env.__toESM(node_process, 1);
|
|
9
10
|
let node_fs = require("node:fs");
|
|
10
|
-
node_fs =
|
|
11
|
+
node_fs = require_rolldown_runtime.__toESM(node_fs, 1);
|
|
11
12
|
let node_os = require("node:os");
|
|
12
|
-
node_os =
|
|
13
|
+
node_os = require_rolldown_runtime.__toESM(node_os, 1);
|
|
14
|
+
//#region src/common/compile-progress.js
|
|
15
|
+
var DEFAULT_TERMINAL_COLUMNS = 80;
|
|
16
|
+
var MIN_PROGRESS_WIDTH = 8;
|
|
17
|
+
var MAX_PROGRESS_WIDTH = 28;
|
|
18
|
+
var RENDERER_CHROME_WIDTH = 14;
|
|
19
|
+
var PROGRESS_BRACKETS_WIDTH = 2;
|
|
20
|
+
/**
|
|
21
|
+
* Format worker progress without assuming a fixed terminal width.
|
|
22
|
+
* The completed count remains the source of truth. Whole cells avoid the
|
|
23
|
+
* visible gap that partial block glyphs leave before the unfilled section.
|
|
24
|
+
*/
|
|
25
|
+
function formatCompileProgress(completed, total, options = {}) {
|
|
26
|
+
const unicode = options.unicode ?? (0, listr2.isUnicodeSupported)();
|
|
27
|
+
const columns = normalizePositiveInteger(options.columns) || node_process.default.stdout.columns || DEFAULT_TERMINAL_COLUMNS;
|
|
28
|
+
const safeTotal = normalizePositiveInteger(total);
|
|
29
|
+
const safeCompleted = Math.min(normalizePositiveInteger(completed), safeTotal);
|
|
30
|
+
const ratio = safeTotal === 0 ? 0 : safeCompleted / safeTotal;
|
|
31
|
+
const percentage = Math.round(ratio * 100);
|
|
32
|
+
const separator = unicode ? "·" : "|";
|
|
33
|
+
const metadata = `${String(safeCompleted).padStart(String(safeTotal).length)}/${safeTotal} ${separator} ${String(percentage).padStart(3)}%`;
|
|
34
|
+
const availableWidth = columns - metadata.length - RENDERER_CHROME_WIDTH - PROGRESS_BRACKETS_WIDTH;
|
|
35
|
+
if (availableWidth < MIN_PROGRESS_WIDTH) return metadata;
|
|
36
|
+
const width = Math.min(availableWidth, MAX_PROGRESS_WIDTH);
|
|
37
|
+
return `[${unicode ? createUnicodeBar(ratio, width) : createAsciiBar(ratio, width)}] ${metadata}`;
|
|
38
|
+
}
|
|
39
|
+
function createUnicodeBar(ratio, width) {
|
|
40
|
+
const completeWidth = Math.round(ratio * width);
|
|
41
|
+
const emptyWidth = width - completeWidth;
|
|
42
|
+
return `${"█".repeat(completeWidth)}${"░".repeat(emptyWidth)}`;
|
|
43
|
+
}
|
|
44
|
+
function createAsciiBar(ratio, width) {
|
|
45
|
+
const completeWidth = Math.floor(ratio * width);
|
|
46
|
+
const showHead = ratio > 0 && ratio < 1;
|
|
47
|
+
const bodyWidth = Math.max(0, completeWidth - (showHead ? 1 : 0));
|
|
48
|
+
const emptyWidth = width - bodyWidth - (showHead ? 1 : 0);
|
|
49
|
+
return `${"=".repeat(bodyWidth)}${showHead ? ">" : ""}${"-".repeat(emptyWidth)}`;
|
|
50
|
+
}
|
|
51
|
+
function normalizePositiveInteger(value) {
|
|
52
|
+
return Number.isFinite(value) ? Math.max(0, Math.trunc(value)) : 0;
|
|
53
|
+
}
|
|
54
|
+
//#endregion
|
|
55
|
+
//#region src/common/art.js
|
|
56
|
+
var artCode = `
|
|
57
|
+
██████╗ ██╗███╗ ███╗██╗███╗ ██╗ █████╗
|
|
58
|
+
██╔══██╗██║████╗ ████║██║████╗ ██║██╔══██╗
|
|
59
|
+
██║ ██║██║██╔████╔██║██║██╔██╗ ██║███████║
|
|
60
|
+
██║ ██║██║██║╚██╔╝██║██║██║╚██╗██║██╔══██║
|
|
61
|
+
██████╔╝██║██║ ╚═╝ ██║██║██║ ╚████║██║ ██║
|
|
62
|
+
╚═════╝ ╚═╝╚═╝ ╚═╝╚═╝╚═╝ ╚═══╝╚═╝ ╚═╝
|
|
63
|
+
`;
|
|
64
|
+
function art_default() {
|
|
65
|
+
console.log(artCode);
|
|
66
|
+
}
|
|
67
|
+
//#endregion
|
|
13
68
|
//#region src/common/publish.js
|
|
14
69
|
function createDist() {
|
|
15
70
|
const distPath = require_env.getTargetPath();
|
|
@@ -191,13 +246,10 @@ var NpmBuilder = class {
|
|
|
191
246
|
const miniprogramExts = [
|
|
192
247
|
".js",
|
|
193
248
|
".json",
|
|
194
|
-
".wxml",
|
|
195
|
-
".wxss",
|
|
196
|
-
".wxs",
|
|
197
249
|
".ts",
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
250
|
+
...require_env.getTemplateExts(),
|
|
251
|
+
...require_env.getStyleExts(),
|
|
252
|
+
...require_env.getViewScriptExts()
|
|
201
253
|
];
|
|
202
254
|
const ext = node_path.default.extname(filename).toLowerCase();
|
|
203
255
|
return miniprogramExts.includes(ext) || filename === "package.json" || filename === "README.md" || filename.startsWith(".");
|
|
@@ -312,26 +364,32 @@ function compileConfig() {
|
|
|
312
364
|
//#endregion
|
|
313
365
|
//#region src/index.js
|
|
314
366
|
var isPrinted = false;
|
|
367
|
+
var previousCompatibilityWarnings = /* @__PURE__ */ new Map();
|
|
315
368
|
/**
|
|
316
369
|
* 构建命令入口
|
|
317
370
|
* @param {string} targetPath 编译产物目标路径
|
|
318
371
|
* @param {string} workPath 编译工作目录
|
|
319
|
-
* @param {boolean} useAppIdDir 产物根目录是否包含appId
|
|
372
|
+
* @param {boolean} useAppIdDir 产物根目录是否包含 appId
|
|
373
|
+
* @param {object} [options] 构建选项
|
|
374
|
+
* @param {boolean} [options.sourcemap] 是否生成 sourcemap
|
|
375
|
+
* @param {{ template?: string[], style?: string[], viewScript?: string[] }} [options.fileTypes]
|
|
376
|
+
* 自定义文件类型,在内置 wx/dd 类型基础上追加;template 为模板扩展名,style 为样式扩展名,
|
|
377
|
+
* viewScript 为视图脚本扩展名和内联标签名
|
|
320
378
|
*/
|
|
321
379
|
async function build(targetPath, workPath, useAppIdDir = true, options = {}) {
|
|
322
|
-
const { sourcemap = false } = options;
|
|
380
|
+
const { sourcemap = false, fileTypes } = options;
|
|
323
381
|
if (!isPrinted) {
|
|
324
|
-
|
|
382
|
+
art_default();
|
|
325
383
|
isPrinted = true;
|
|
326
384
|
}
|
|
327
385
|
const tasks = new listr2.Listr([
|
|
328
386
|
{
|
|
329
|
-
title: "
|
|
387
|
+
title: "初始化项目",
|
|
330
388
|
task: (_, task) => task.newListr([
|
|
331
389
|
{
|
|
332
390
|
title: "收集配置信息",
|
|
333
391
|
task: (ctx) => {
|
|
334
|
-
ctx.storeInfo = require_env.storeInfo(workPath);
|
|
392
|
+
ctx.storeInfo = require_env.storeInfo(workPath, { fileTypes });
|
|
335
393
|
}
|
|
336
394
|
},
|
|
337
395
|
{
|
|
@@ -355,29 +413,42 @@ async function build(targetPath, workPath, useAppIdDir = true, options = {}) {
|
|
|
355
413
|
], { concurrent: false })
|
|
356
414
|
},
|
|
357
415
|
{
|
|
358
|
-
title:
|
|
416
|
+
title: `编译项目 · ${node_path.default.basename(node_path.default.resolve(workPath))}`,
|
|
359
417
|
task: (ctx, task) => {
|
|
360
418
|
const pages = require_env.getPages();
|
|
361
419
|
ctx.pages = pages;
|
|
420
|
+
ctx.compatibilityWarnings = /* @__PURE__ */ new Set();
|
|
362
421
|
return task.newListr([
|
|
363
422
|
{
|
|
364
|
-
title: "
|
|
423
|
+
title: "编译视图",
|
|
424
|
+
rendererOptions: {
|
|
425
|
+
outputBar: true,
|
|
426
|
+
persistentOutput: false
|
|
427
|
+
},
|
|
365
428
|
task: async (ctx, task) => {
|
|
366
429
|
return runCompileInWorker("view", ctx, task, { sourcemap });
|
|
367
430
|
}
|
|
368
431
|
},
|
|
369
432
|
{
|
|
370
|
-
title: "
|
|
433
|
+
title: "编译逻辑",
|
|
434
|
+
rendererOptions: {
|
|
435
|
+
outputBar: true,
|
|
436
|
+
persistentOutput: false
|
|
437
|
+
},
|
|
371
438
|
task: async (ctx, task) => {
|
|
372
439
|
return runCompileInWorker("logic", ctx, task, { sourcemap });
|
|
373
440
|
}
|
|
374
441
|
},
|
|
375
442
|
{
|
|
376
|
-
title: "
|
|
443
|
+
title: "编译样式",
|
|
444
|
+
rendererOptions: {
|
|
445
|
+
outputBar: true,
|
|
446
|
+
persistentOutput: false
|
|
447
|
+
},
|
|
377
448
|
task: async (ctx, task) => {
|
|
378
449
|
pages.mainPages.unshift({
|
|
379
450
|
path: "app",
|
|
380
|
-
id:
|
|
451
|
+
id: require_env.getAppStyleScopeId()
|
|
381
452
|
});
|
|
382
453
|
return runCompileInWorker("style", ctx, task, { sourcemap });
|
|
383
454
|
}
|
|
@@ -386,14 +457,23 @@ async function build(targetPath, workPath, useAppIdDir = true, options = {}) {
|
|
|
386
457
|
}
|
|
387
458
|
},
|
|
388
459
|
{
|
|
389
|
-
title: "
|
|
460
|
+
title: "写入编译产物",
|
|
390
461
|
task: () => {
|
|
391
462
|
publishToDist(targetPath, useAppIdDir);
|
|
392
463
|
}
|
|
393
464
|
}
|
|
394
|
-
], {
|
|
465
|
+
], {
|
|
466
|
+
concurrent: false,
|
|
467
|
+
rendererOptions: {
|
|
468
|
+
collapseSubtasks: true,
|
|
469
|
+
formatOutput: "truncate",
|
|
470
|
+
timer: listr2.PRESET_TIMER
|
|
471
|
+
},
|
|
472
|
+
fallbackRendererOptions: { timer: listr2.PRESET_TIMER }
|
|
473
|
+
});
|
|
395
474
|
try {
|
|
396
475
|
const context = await tasks.run();
|
|
476
|
+
printCompatibilityWarnings(workPath, context.compatibilityWarnings);
|
|
397
477
|
return {
|
|
398
478
|
appId: require_env.getAppId(),
|
|
399
479
|
name: require_env.getAppName(),
|
|
@@ -422,16 +502,12 @@ function runCompileInWorker(script, ctx, task, options = {}) {
|
|
|
422
502
|
});
|
|
423
503
|
worker.on("message", (message) => {
|
|
424
504
|
try {
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
const percentage = progress * 100;
|
|
428
|
-
const barLength = 30;
|
|
429
|
-
const filledLength = Math.ceil(barLength * progress);
|
|
430
|
-
task.output = `[${"█".repeat(filledLength) + "░".repeat(barLength - filledLength)}] ${percentage.toFixed(2)}%`;
|
|
431
|
-
}
|
|
505
|
+
for (const warning of message.compatibilityWarnings || []) ctx.compatibilityWarnings.add(warning);
|
|
506
|
+
if (node_process.default.stdout.isTTY && message.completedTasks !== void 0) task.output = formatCompileProgress(message.completedTasks, totalTasks);
|
|
432
507
|
if (message.success) {
|
|
433
508
|
if (isResolved) return;
|
|
434
509
|
isResolved = true;
|
|
510
|
+
if (node_process.default.stdout.isTTY && totalTasks > 0) task.output = formatCompileProgress(totalTasks, totalTasks);
|
|
435
511
|
worker.terminate();
|
|
436
512
|
resolve();
|
|
437
513
|
} else if (message.error) {
|
|
@@ -450,9 +526,25 @@ function runCompileInWorker(script, ctx, task, options = {}) {
|
|
|
450
526
|
handleError(err);
|
|
451
527
|
});
|
|
452
528
|
worker.on("exit", (code) => {
|
|
453
|
-
if (code !== 0 && !isResolved)
|
|
529
|
+
if (code !== 0 && !isResolved) {
|
|
530
|
+
const error = workerError || /* @__PURE__ */ new Error(code === 1 ? "Worker terminated due to reaching memory limit: JS heap out of memory" : `Worker stopped with exit code ${code}`);
|
|
531
|
+
handleError(error);
|
|
532
|
+
}
|
|
454
533
|
});
|
|
455
534
|
}));
|
|
456
535
|
}
|
|
536
|
+
function printCompatibilityWarnings(workPath, warnings = /* @__PURE__ */ new Set()) {
|
|
537
|
+
const projectPath = node_path.default.resolve(workPath);
|
|
538
|
+
const hasPreviousResult = previousCompatibilityWarnings.has(projectPath);
|
|
539
|
+
const previousWarnings = previousCompatibilityWarnings.get(projectPath) || /* @__PURE__ */ new Set();
|
|
540
|
+
const currentWarnings = new Set(warnings);
|
|
541
|
+
const newWarnings = [...currentWarnings].filter((warning) => !previousWarnings.has(warning));
|
|
542
|
+
previousCompatibilityWarnings.set(projectPath, currentWarnings);
|
|
543
|
+
if (newWarnings.length === 0) return;
|
|
544
|
+
const qualifier = hasPreviousResult ? " new" : "";
|
|
545
|
+
const suffix = newWarnings.length === 1 ? "" : "s";
|
|
546
|
+
console.warn(`\n[compat] ${newWarnings.length}${qualifier} compatibility warning${suffix}`);
|
|
547
|
+
for (const warning of newWarnings) console.warn(` - ${warning.replace(/^\[compat\]\s*/, "")}`);
|
|
548
|
+
}
|
|
457
549
|
//#endregion
|
|
458
550
|
module.exports = build;
|