@proteus-vue/plugin-vite 0.2.0-beta.2 → 0.2.0-beta.5
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/gen-routes.d.ts +11 -0
- package/dist/index.js +255 -97
- package/dist/plugin.d.ts +2 -0
- package/dist/tag-scan.d.ts +28 -0
- package/package.json +6 -6
package/dist/gen-routes.d.ts
CHANGED
|
@@ -20,6 +20,17 @@ export interface GenRoutesOptions {
|
|
|
20
20
|
dependencies?: Record<string, string>;
|
|
21
21
|
preload?: string[];
|
|
22
22
|
}>;
|
|
23
|
+
/**
|
|
24
|
+
* ★Web 目标只生成**应用侧路由表**(2026-09-19 修外部实战报告的第 3 条阻断项):
|
|
25
|
+
* `auto-routes.ts` 是 **双端共用** 产物(Web 的 RouterView 与 MP 的 app.json 同源),
|
|
26
|
+
* 但此前 gen-routes 只在 MP 目标被调用(`needsGenRoutes: isMp`)→ 使用 `proteus build --target web`
|
|
27
|
+
* 的工程新增页面后路由表不更新 → **页面 404**(外部项目实测:新增 `src/pages/editor/` 后
|
|
28
|
+
* Web 构建成功但路由表未收录)。
|
|
29
|
+
* `webOnly: true` 时:只 `scanPages → buildRoutes → validate → writeAutoRoutes`,
|
|
30
|
+
* **跳过 MP 专属产物**(app.json/page.json/component.json/project.config.json,web 构建不需要)
|
|
31
|
+
* 且**不清理 `dist/mp-weixin`**(否则会把已构建的 MP 产物删掉——那不属于 web 构建的职责)。
|
|
32
|
+
*/
|
|
33
|
+
webOnly?: boolean;
|
|
23
34
|
}
|
|
24
35
|
/**
|
|
25
36
|
* 运行路由表生成(纯函数,可单测):清理 dist 产物 → 扫描页面 → 生成 auto-routes/app.json/page.json/component.json
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// src/plugin.ts
|
|
2
|
-
import
|
|
3
|
-
import
|
|
2
|
+
import fs5 from "node:fs";
|
|
3
|
+
import path5 from "node:path";
|
|
4
4
|
import { createRequire as createRequire3 } from "node:module";
|
|
5
5
|
|
|
6
6
|
// ../types/src/router-config.ts
|
|
@@ -294,6 +294,10 @@ function runGenRoutes(options) {
|
|
|
294
294
|
return ` { ${parts.join(", ")} },`;
|
|
295
295
|
}
|
|
296
296
|
function writeAutoRoutes(routes2) {
|
|
297
|
+
if (!rc.routesOutput) {
|
|
298
|
+
console.log("[gen-routes] routesOutput \u4E3A\u7A7A \u2192 \u6309\u914D\u7F6E**\u8DF3\u8FC7**\u5E94\u7528\u4FA7\u8DEF\u7531\u8868\u751F\u6210\uFF08\u5DE5\u7A0B\u81EA\u5E26\u8DEF\u7531\u673A\u5236\uFF09");
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
297
301
|
const lines = [
|
|
298
302
|
`// ${rc.routesOutput} \u2014\u2014 \u5E94\u7528\u4FA7\u8DEF\u7531\u8868\uFF08AUTO-GENERATED by scripts/gen-routes.ts\uFF0C\u52FF\u624B\u52A8\u7F16\u8F91\uFF09`,
|
|
299
303
|
"// \u2605\u62C6\u5305\u6B65\u9AA4 4\uFF1Aauto-routes \u968F\u5E94\u7528\u5B58\u653E\uFF08\u5DE5\u5382\u5316\u540E\u8DEF\u7531\u8868\u7531\u5E94\u7528\u6CE8\u5165 createRouter\uFF09\uFF0C\u4E0D\u518D\u5C5E\u4E8E @proteus-vue/router \u5305",
|
|
@@ -555,7 +559,7 @@ function runGenRoutes(options) {
|
|
|
555
559
|
"details",
|
|
556
560
|
"summary"
|
|
557
561
|
]);
|
|
558
|
-
function
|
|
562
|
+
function extractTemplateBody2(src) {
|
|
559
563
|
const n = src.length;
|
|
560
564
|
let i = 0;
|
|
561
565
|
while (i < n) {
|
|
@@ -611,7 +615,7 @@ function runGenRoutes(options) {
|
|
|
611
615
|
}
|
|
612
616
|
function collectComponents(file, skipSemantic = false) {
|
|
613
617
|
const src = fs2.readFileSync(file, "utf-8");
|
|
614
|
-
const tpl =
|
|
618
|
+
const tpl = extractTemplateBody2(src);
|
|
615
619
|
const customTags = new Set(Object.keys(config.rules?.customTags ?? {}));
|
|
616
620
|
const gridRuleDisabled = (config.rules?.disabled ?? []).includes("fluid/semantic-grid");
|
|
617
621
|
const semanticTags = skipSemantic && !gridRuleDisabled ? /* @__PURE__ */ new Set(["p-grid"]) : /* @__PURE__ */ new Set();
|
|
@@ -715,10 +719,15 @@ function runGenRoutes(options) {
|
|
|
715
719
|
fs2.writeFileSync(path2.join(OUT_DIR, "project.config.json"), JSON.stringify(projectConfig, null, 2) + "\n");
|
|
716
720
|
console.log(`[gen-routes] \u5DF2\u751F\u6210 dist/mp-weixin/project.config.json\uFF08appid=${config.appid}\uFF0Cprojectname=${projectName}\uFF09`);
|
|
717
721
|
}
|
|
718
|
-
fs2.rmSync(OUT_DIR, { recursive: true, force: true });
|
|
719
722
|
const pages = scanPages();
|
|
720
723
|
const routes = buildRoutes(pages);
|
|
721
724
|
validate(pages, routes);
|
|
725
|
+
if (options.webOnly) {
|
|
726
|
+
writeAutoRoutes(routes);
|
|
727
|
+
console.log(`[gen-routes] \uFF08web \u76EE\u6807\uFF09\u5DF2\u66F4\u65B0\u5E94\u7528\u4FA7\u8DEF\u7531\u8868\uFF1A\u5171 ${pages.length} \u4E2A\u9875\u9762`);
|
|
728
|
+
return;
|
|
729
|
+
}
|
|
730
|
+
fs2.rmSync(OUT_DIR, { recursive: true, force: true });
|
|
722
731
|
writeAutoRoutes(routes);
|
|
723
732
|
writeAppJson(pages, routes);
|
|
724
733
|
writePageJsons(pages);
|
|
@@ -898,6 +907,138 @@ function createBundleCache(cacheDir) {
|
|
|
898
907
|
};
|
|
899
908
|
}
|
|
900
909
|
|
|
910
|
+
// src/tag-scan.ts
|
|
911
|
+
import fs4 from "node:fs";
|
|
912
|
+
import path4 from "node:path";
|
|
913
|
+
function extractTemplateBody(src) {
|
|
914
|
+
const n = src.length;
|
|
915
|
+
let i = 0;
|
|
916
|
+
while (i < n) {
|
|
917
|
+
const lt = src.indexOf("<", i);
|
|
918
|
+
if (lt < 0) return "";
|
|
919
|
+
if (src.startsWith("<!--", lt)) {
|
|
920
|
+
const e = src.indexOf("-->", lt + 4);
|
|
921
|
+
i = e < 0 ? n : e + 3;
|
|
922
|
+
continue;
|
|
923
|
+
}
|
|
924
|
+
const block = /^<(script|style)\b/i.exec(src.slice(lt, lt + 32));
|
|
925
|
+
if (block) {
|
|
926
|
+
const tag = block[1].toLowerCase();
|
|
927
|
+
const end = src.toLowerCase().indexOf(`</${tag}`, lt + block[0].length);
|
|
928
|
+
if (end < 0) return "";
|
|
929
|
+
const gt = src.indexOf(">", end);
|
|
930
|
+
i = gt < 0 ? n : gt + 1;
|
|
931
|
+
continue;
|
|
932
|
+
}
|
|
933
|
+
if (/^<template[\s>]/i.test(src.slice(lt, lt + 16))) {
|
|
934
|
+
const gt = src.indexOf(">", lt);
|
|
935
|
+
if (gt < 0) return "";
|
|
936
|
+
let depth = 1;
|
|
937
|
+
let j = gt + 1;
|
|
938
|
+
while (j < n) {
|
|
939
|
+
const l2 = src.indexOf("<", j);
|
|
940
|
+
if (l2 < 0) return src.slice(gt + 1);
|
|
941
|
+
if (src.startsWith("<!--", l2)) {
|
|
942
|
+
const e = src.indexOf("-->", l2 + 4);
|
|
943
|
+
j = e < 0 ? n : e + 3;
|
|
944
|
+
continue;
|
|
945
|
+
}
|
|
946
|
+
const seg = src.slice(l2, l2 + 16);
|
|
947
|
+
if (/^<\/template[\s>]/i.test(seg)) {
|
|
948
|
+
depth--;
|
|
949
|
+
if (depth === 0) return src.slice(gt + 1, l2);
|
|
950
|
+
j = l2 + "</template>".length;
|
|
951
|
+
continue;
|
|
952
|
+
}
|
|
953
|
+
if (/^<template[\s>]/i.test(seg)) {
|
|
954
|
+
depth++;
|
|
955
|
+
const g2 = src.indexOf(">", l2);
|
|
956
|
+
j = g2 < 0 ? n : g2 + 1;
|
|
957
|
+
continue;
|
|
958
|
+
}
|
|
959
|
+
j = l2 + 1;
|
|
960
|
+
}
|
|
961
|
+
return src.slice(gt + 1);
|
|
962
|
+
}
|
|
963
|
+
i = lt + 1;
|
|
964
|
+
}
|
|
965
|
+
return "";
|
|
966
|
+
}
|
|
967
|
+
function extractTags(tpl) {
|
|
968
|
+
const out = /* @__PURE__ */ new Set();
|
|
969
|
+
let idx = 0;
|
|
970
|
+
while (idx < tpl.length) {
|
|
971
|
+
const lt = tpl.indexOf("<", idx);
|
|
972
|
+
if (lt < 0) break;
|
|
973
|
+
if (tpl.startsWith("<!--", lt)) {
|
|
974
|
+
const e = tpl.indexOf("-->", lt + 4);
|
|
975
|
+
idx = e < 0 ? tpl.length : e + 3;
|
|
976
|
+
continue;
|
|
977
|
+
}
|
|
978
|
+
if (tpl.startsWith("</", lt)) {
|
|
979
|
+
idx = lt + 2;
|
|
980
|
+
continue;
|
|
981
|
+
}
|
|
982
|
+
const mm = /^([A-Za-z][\w-]*)/.exec(tpl.slice(lt + 1));
|
|
983
|
+
if (!mm) {
|
|
984
|
+
idx = lt + 1;
|
|
985
|
+
continue;
|
|
986
|
+
}
|
|
987
|
+
const raw = mm[1];
|
|
988
|
+
out.add(/[A-Z]/.test(raw) ? raw.replace(/\B([A-Z])/g, "-$1").toLowerCase() : raw);
|
|
989
|
+
idx = lt + 1 + mm[0].length;
|
|
990
|
+
}
|
|
991
|
+
return out;
|
|
992
|
+
}
|
|
993
|
+
function collectCompilerEmittedTags(templateBody) {
|
|
994
|
+
const out = /* @__PURE__ */ new Set();
|
|
995
|
+
if (/<(?:svg|circle|rect|ellipse|path|line|polyline|polygon)[\s>][\s\S]*?<animate\b/i.test(templateBody)) {
|
|
996
|
+
const shapeAnim = /<animate\s[^>]*attributeName\s*=\s*["'](cx|cy|r|rx|ry|x|y|width|height|d|points|stroke-dashoffset|stroke-dasharray)["']/i;
|
|
997
|
+
if (shapeAnim.test(templateBody)) out.add("p-svg-canvas");
|
|
998
|
+
}
|
|
999
|
+
return out;
|
|
1000
|
+
}
|
|
1001
|
+
function resolveComponentFile(componentsDir, tag) {
|
|
1002
|
+
const dirIndex = path4.join(componentsDir, tag, "index.vue");
|
|
1003
|
+
if (fs4.existsSync(dirIndex)) return dirIndex;
|
|
1004
|
+
const flat = path4.join(componentsDir, `${tag}.vue`);
|
|
1005
|
+
if (fs4.existsSync(flat)) return flat;
|
|
1006
|
+
return null;
|
|
1007
|
+
}
|
|
1008
|
+
function collectUsedFrameworkComponents(pageFiles, componentsDir) {
|
|
1009
|
+
const used = /* @__PURE__ */ new Set();
|
|
1010
|
+
const visitedFiles = /* @__PURE__ */ new Set();
|
|
1011
|
+
const queue = [...pageFiles];
|
|
1012
|
+
while (queue.length) {
|
|
1013
|
+
const file = queue.pop();
|
|
1014
|
+
if (visitedFiles.has(file)) continue;
|
|
1015
|
+
visitedFiles.add(file);
|
|
1016
|
+
if (!fs4.existsSync(file)) continue;
|
|
1017
|
+
let tags;
|
|
1018
|
+
const body = (() => {
|
|
1019
|
+
try {
|
|
1020
|
+
return extractTemplateBody(fs4.readFileSync(file, "utf-8"));
|
|
1021
|
+
} catch {
|
|
1022
|
+
return "";
|
|
1023
|
+
}
|
|
1024
|
+
})();
|
|
1025
|
+
try {
|
|
1026
|
+
tags = extractTags(body);
|
|
1027
|
+
for (const t of collectCompilerEmittedTags(body)) tags.add(t);
|
|
1028
|
+
} catch {
|
|
1029
|
+
continue;
|
|
1030
|
+
}
|
|
1031
|
+
for (const tag of tags) {
|
|
1032
|
+
if (used.has(tag)) continue;
|
|
1033
|
+
const compFile = resolveComponentFile(componentsDir, tag);
|
|
1034
|
+
if (!compFile) continue;
|
|
1035
|
+
used.add(tag);
|
|
1036
|
+
queue.push(compFile);
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1039
|
+
return used;
|
|
1040
|
+
}
|
|
1041
|
+
|
|
901
1042
|
// src/plugin.ts
|
|
902
1043
|
var MP_TAG_MAP = {
|
|
903
1044
|
view: "proteus-view",
|
|
@@ -925,7 +1066,15 @@ var MP_ONLY_TAGS = /* @__PURE__ */ new Set([
|
|
|
925
1066
|
"share-element",
|
|
926
1067
|
"keyboard-accessory",
|
|
927
1068
|
"cover-view",
|
|
928
|
-
"cover-image"
|
|
1069
|
+
"cover-image",
|
|
1070
|
+
// ★端对齐批次3(2026-09-16):宿主能力组件的 MP 原生标签——其模板用 v-if 双分支
|
|
1071
|
+
// (MP 原生 / Web 降级),Web 端死分支不渲染但会被 resolveComponent 提升解析 → 声明为自定义元素消除告警。
|
|
1072
|
+
"rich-text",
|
|
1073
|
+
"map",
|
|
1074
|
+
"camera",
|
|
1075
|
+
"canvas",
|
|
1076
|
+
"ad",
|
|
1077
|
+
"web-view"
|
|
929
1078
|
]);
|
|
930
1079
|
function defaultScopedPlugin() {
|
|
931
1080
|
return {
|
|
@@ -960,13 +1109,13 @@ function resolvePkgPath(projectRoot, modPath) {
|
|
|
960
1109
|
const m = modPath.match(/^node_modules\/((?:@[^/]+\/)?[^/]+)\/([\s\S]+)$/);
|
|
961
1110
|
if (m) {
|
|
962
1111
|
try {
|
|
963
|
-
const pkgRequire = createRequire3(
|
|
964
|
-
const pkgRoot =
|
|
965
|
-
return
|
|
1112
|
+
const pkgRequire = createRequire3(path5.join(projectRoot, "package.json"));
|
|
1113
|
+
const pkgRoot = path5.dirname(pkgRequire.resolve(`${m[1]}/package.json`));
|
|
1114
|
+
return path5.join(pkgRoot, m[2]);
|
|
966
1115
|
} catch {
|
|
967
1116
|
}
|
|
968
1117
|
}
|
|
969
|
-
return
|
|
1118
|
+
return path5.join(projectRoot, modPath);
|
|
970
1119
|
}
|
|
971
1120
|
function preprocessStyle(lang, content) {
|
|
972
1121
|
if (lang === "scss" || lang === "sass") {
|
|
@@ -984,11 +1133,11 @@ function preprocessStyle(lang, content) {
|
|
|
984
1133
|
return content;
|
|
985
1134
|
}
|
|
986
1135
|
function loadStyleSrcWithVariant(src, fromFilename, platform = "mp") {
|
|
987
|
-
const base =
|
|
988
|
-
const hit = resolvePlatformVariant(base, platform,
|
|
1136
|
+
const base = path5.resolve(path5.dirname(fromFilename), src);
|
|
1137
|
+
const hit = resolvePlatformVariant(base, platform, fs5.existsSync);
|
|
989
1138
|
if (!hit) return null;
|
|
990
1139
|
try {
|
|
991
|
-
return
|
|
1140
|
+
return fs5.readFileSync(hit, "utf-8");
|
|
992
1141
|
} catch {
|
|
993
1142
|
return null;
|
|
994
1143
|
}
|
|
@@ -997,10 +1146,10 @@ var VENDOR_SINGLETONS = ["pinia", "vue", "@vue/devtools-api"];
|
|
|
997
1146
|
function resolveSharedModule(appDir, absFrom, source, frameworkDir, resolveFrom, platform = "mp") {
|
|
998
1147
|
if (source.startsWith("@proteus-vue/")) {
|
|
999
1148
|
try {
|
|
1000
|
-
const resolver = resolveFrom ? createRequire3(
|
|
1001
|
-
const pkgRoot =
|
|
1002
|
-
const entry =
|
|
1003
|
-
if (!
|
|
1149
|
+
const resolver = resolveFrom ? createRequire3(path5.join(resolveFrom, "package.json")) : require2;
|
|
1150
|
+
const pkgRoot = path5.dirname(resolver.resolve(`${source}/package.json`));
|
|
1151
|
+
const entry = path5.join(pkgRoot, "dist", "index.js");
|
|
1152
|
+
if (!fs5.existsSync(entry)) return null;
|
|
1004
1153
|
return { file: entry, relNoExt: `_proteus/${source.replace("@proteus-vue/", "")}` };
|
|
1005
1154
|
} catch {
|
|
1006
1155
|
return null;
|
|
@@ -1014,34 +1163,34 @@ function resolveSharedModule(appDir, absFrom, source, frameworkDir, resolveFrom,
|
|
|
1014
1163
|
return null;
|
|
1015
1164
|
}
|
|
1016
1165
|
};
|
|
1017
|
-
const entry = tryResolve(
|
|
1018
|
-
if (!entry || !
|
|
1166
|
+
const entry = tryResolve(path5.join(resolveFrom ?? appDir, "package.json")) ?? tryResolve(absFrom);
|
|
1167
|
+
if (!entry || !fs5.existsSync(entry)) return null;
|
|
1019
1168
|
return { file: entry, relNoExt: `_proteus/${source}` };
|
|
1020
1169
|
}
|
|
1021
1170
|
if (!source.startsWith(".")) return null;
|
|
1022
|
-
const base =
|
|
1171
|
+
const base = path5.resolve(path5.dirname(absFrom), source);
|
|
1023
1172
|
const JS_EXTS = /* @__PURE__ */ new Set([".ts", ".js", ".mjs", ".cjs"]);
|
|
1024
1173
|
const variantHit = resolvePlatformVariantWithExts(base, [...JS_EXTS], platform, (p) => {
|
|
1025
1174
|
try {
|
|
1026
|
-
return
|
|
1175
|
+
return fs5.statSync(p).isFile();
|
|
1027
1176
|
} catch {
|
|
1028
1177
|
return false;
|
|
1029
1178
|
}
|
|
1030
1179
|
});
|
|
1031
|
-
const candidates = variantHit ? [variantHit] : [base, `${base}.ts`, `${base}.js`,
|
|
1180
|
+
const candidates = variantHit ? [variantHit] : [base, `${base}.ts`, `${base}.js`, path5.join(base, "index.ts"), path5.join(base, "index.js")];
|
|
1032
1181
|
for (const cand of candidates) {
|
|
1033
1182
|
if (cand.endsWith(".vue")) continue;
|
|
1034
|
-
if (!JS_EXTS.has(
|
|
1183
|
+
if (!JS_EXTS.has(path5.extname(cand).toLowerCase())) continue;
|
|
1035
1184
|
let isFile = false;
|
|
1036
1185
|
try {
|
|
1037
|
-
isFile =
|
|
1186
|
+
isFile = fs5.statSync(cand).isFile();
|
|
1038
1187
|
} catch {
|
|
1039
1188
|
isFile = false;
|
|
1040
1189
|
}
|
|
1041
1190
|
if (isFile) {
|
|
1042
|
-
let relNoExt =
|
|
1043
|
-
if (relNoExt.startsWith("../") && frameworkDir && !
|
|
1044
|
-
relNoExt = `proteus/${
|
|
1191
|
+
let relNoExt = path5.relative(appDir, cand).replace(/\\/g, "/").replace(/\.(ts|js)$/, "");
|
|
1192
|
+
if (relNoExt.startsWith("../") && frameworkDir && !path5.relative(frameworkDir, cand).startsWith("..")) {
|
|
1193
|
+
relNoExt = `proteus/${path5.relative(frameworkDir, cand).replace(/\\/g, "/").replace(/\.(ts|js)$/, "")}`;
|
|
1045
1194
|
}
|
|
1046
1195
|
return { file: cand, relNoExt };
|
|
1047
1196
|
}
|
|
@@ -1053,10 +1202,10 @@ function rewriteRootToPage(css) {
|
|
|
1053
1202
|
}
|
|
1054
1203
|
function rewriteFrameworkRequires(js, relOutput) {
|
|
1055
1204
|
if (!js.includes("require('@proteus-vue/")) return js;
|
|
1056
|
-
const pageDir =
|
|
1205
|
+
const pageDir = path5.posix.dirname(relOutput);
|
|
1057
1206
|
return js.replace(/require\('@proteus-vue\/([A-Za-z0-9_-]+)'\)/g, (m, name) => {
|
|
1058
1207
|
const pkgRel = `_proteus/${name}.js`;
|
|
1059
|
-
let rel =
|
|
1208
|
+
let rel = path5.posix.relative(pageDir, pkgRel);
|
|
1060
1209
|
if (!rel.startsWith(".")) rel = `./${rel}`;
|
|
1061
1210
|
return `require('${rel}')`;
|
|
1062
1211
|
});
|
|
@@ -1105,11 +1254,11 @@ async function loadPresetBuilders(projectRoot, cfg) {
|
|
|
1105
1254
|
for (const d of duplicates) console.warn(`[mp-transform] \u8DEF\u7531\u5B57\u6BB5 "${d}" \u5728\u9876\u5C42\u4E0E router \u6BB5\u540C\u65F6\u58F0\u660E\u2014\u2014\u5DF2\u53D6 router.${d}\uFF08#492 \u7EDF\u4E00\u8DEF\u7531\u7BA1\u7406\uFF1A\u5EFA\u8BAE\u5220\u9664\u9876\u5C42\u9057\u7559\u5199\u6CD5\uFF09`);
|
|
1106
1255
|
for (const [name, modPath] of Object.entries(rc.customRoute.builders)) {
|
|
1107
1256
|
const abs = resolvePkgPath(projectRoot, modPath);
|
|
1108
|
-
if (!
|
|
1257
|
+
if (!fs5.existsSync(abs)) {
|
|
1109
1258
|
console.warn(`[mp-transform] \u9884\u8BBE builder ${name} \u4E0D\u5B58\u5728\uFF1A${modPath}`);
|
|
1110
1259
|
continue;
|
|
1111
1260
|
}
|
|
1112
|
-
const { code } = await esbuildTransform(
|
|
1261
|
+
const { code } = await esbuildTransform(fs5.readFileSync(abs, "utf-8"), { loader: "ts", charset: "utf8" });
|
|
1113
1262
|
const fnName = extractBuilderFnName(code);
|
|
1114
1263
|
if (!fnName) {
|
|
1115
1264
|
console.warn(`[mp-transform] \u9884\u8BBE builder ${name} \u672A\u627E\u5230\u51FD\u6570\u58F0\u660E\uFF0C\u5DF2\u8DF3\u8FC7`);
|
|
@@ -1120,10 +1269,10 @@ async function loadPresetBuilders(projectRoot, cfg) {
|
|
|
1120
1269
|
return presets;
|
|
1121
1270
|
}
|
|
1122
1271
|
function walkVueFiles(dir, acc = []) {
|
|
1123
|
-
if (!
|
|
1124
|
-
for (const entry of
|
|
1272
|
+
if (!fs5.existsSync(dir)) return acc;
|
|
1273
|
+
for (const entry of fs5.readdirSync(dir, { withFileTypes: true })) {
|
|
1125
1274
|
if (entry.name.startsWith(".")) continue;
|
|
1126
|
-
const full =
|
|
1275
|
+
const full = path5.join(dir, entry.name);
|
|
1127
1276
|
if (entry.isDirectory()) walkVueFiles(full, acc);
|
|
1128
1277
|
else if (entry.name.endsWith(".vue")) acc.push(full);
|
|
1129
1278
|
}
|
|
@@ -1139,19 +1288,26 @@ function collectMpEntries(opts) {
|
|
|
1139
1288
|
onSkipWebOnly?.(f);
|
|
1140
1289
|
continue;
|
|
1141
1290
|
}
|
|
1142
|
-
const relBase =
|
|
1291
|
+
const relBase = path5.relative(appDir, splitVariant2(f).base).replace(/\\/g, "/");
|
|
1143
1292
|
out.push({ file: f, rel: relBase.replace(/\.vue$/, ""), isComponent });
|
|
1144
1293
|
}
|
|
1145
1294
|
};
|
|
1146
|
-
pushRel(
|
|
1147
|
-
for (const sp of subPackages) pushRel(
|
|
1148
|
-
pushRel(
|
|
1295
|
+
pushRel(path5.join(projectRoot, pagesDir), false);
|
|
1296
|
+
for (const sp of subPackages) pushRel(path5.join(projectRoot, sp.root), false);
|
|
1297
|
+
pushRel(path5.join(appDir, "components"), true);
|
|
1298
|
+
const pageFiles = out.filter((t) => !t.isComponent).map((t) => t.file);
|
|
1299
|
+
const emitAll = (opts.componentEmit ?? "used") === "all";
|
|
1300
|
+
const usedComponents = emitAll ? null : collectUsedFrameworkComponents(pageFiles, componentsDir);
|
|
1149
1301
|
for (const f of effectiveVariants2(walkVueFiles(componentsDir), platform)) {
|
|
1150
1302
|
if (webOnlyPages?.has(f)) {
|
|
1151
1303
|
onSkipWebOnly?.(f);
|
|
1152
1304
|
continue;
|
|
1153
1305
|
}
|
|
1154
|
-
|
|
1306
|
+
if (usedComponents) {
|
|
1307
|
+
const compName = path5.relative(componentsDir, splitVariant2(f).base).replace(/\\/g, "/").split("/")[0];
|
|
1308
|
+
if (!usedComponents.has(compName)) continue;
|
|
1309
|
+
}
|
|
1310
|
+
const relIn = path5.relative(componentsDir, splitVariant2(f).base).replace(/\\/g, "/").replace(/\.vue$/, "");
|
|
1155
1311
|
out.push({ file: f, rel: `proteus/${relIn}`, isComponent: true });
|
|
1156
1312
|
}
|
|
1157
1313
|
return out;
|
|
@@ -1184,13 +1340,13 @@ function mpTransform(opts) {
|
|
|
1184
1340
|
projectRoot = resolved.root;
|
|
1185
1341
|
},
|
|
1186
1342
|
async buildStart() {
|
|
1187
|
-
const appDir =
|
|
1188
|
-
const compileCache = createCompileCache(
|
|
1189
|
-
const bundleCache = createBundleCache(
|
|
1343
|
+
const appDir = path5.join(projectRoot, path5.dirname(cfg.pagesDir));
|
|
1344
|
+
const compileCache = createCompileCache(path5.join(projectRoot, "node_modules", ".cache", "proteus", "compile"));
|
|
1345
|
+
const bundleCache = createBundleCache(path5.join(projectRoot, "node_modules", ".cache", "proteus", "bundle"));
|
|
1190
1346
|
const webOnlyPages = /* @__PURE__ */ new Set();
|
|
1191
1347
|
const detectWebOnly = (file) => {
|
|
1192
1348
|
try {
|
|
1193
|
-
const src =
|
|
1349
|
+
const src = fs5.readFileSync(file, "utf-8");
|
|
1194
1350
|
const m = src.match(/<route>\s*([\s\S]*?)<\/route>/);
|
|
1195
1351
|
if (!m) return;
|
|
1196
1352
|
if (/"?webOnly"?\s*:\s*true/.test(m[1])) {
|
|
@@ -1210,10 +1366,10 @@ function mpTransform(opts) {
|
|
|
1210
1366
|
} catch {
|
|
1211
1367
|
}
|
|
1212
1368
|
};
|
|
1213
|
-
for (const pagesRoot of [
|
|
1369
|
+
for (const pagesRoot of [path5.join(projectRoot, cfg.pagesDir), ...(effectiveSubPackages ?? []).map((sp) => path5.join(projectRoot, sp.root))]) {
|
|
1214
1370
|
for (const f of walkVueFiles(pagesRoot)) detectWebOnly(f);
|
|
1215
1371
|
}
|
|
1216
|
-
const frameworkComponents = opts.componentsDir ?
|
|
1372
|
+
const frameworkComponents = opts.componentsDir ? path5.resolve(projectRoot, opts.componentsDir) : resolveComponentsRoot(projectRoot);
|
|
1217
1373
|
const files = collectMpEntries({
|
|
1218
1374
|
projectRoot,
|
|
1219
1375
|
appDir,
|
|
@@ -1221,20 +1377,22 @@ function mpTransform(opts) {
|
|
|
1221
1377
|
subPackages: effectiveSubPackages ?? [],
|
|
1222
1378
|
componentsDir: frameworkComponents,
|
|
1223
1379
|
webOnlyPages,
|
|
1224
|
-
onSkipWebOnly: (f) => console.log(`[mp-transform] \u8DF3\u8FC7 webOnly \u9875\u9762\uFF1A${
|
|
1380
|
+
onSkipWebOnly: (f) => console.log(`[mp-transform] \u8DF3\u8FC7 webOnly \u9875\u9762\uFF1A${path5.relative(projectRoot, f).replace(/\\/g, "/")}`),
|
|
1381
|
+
// ★框架组件按引用输出(2026-09-18);PROTEUS_COMPONENTS_EMIT=all 回退全量(非常规用法逃生舱)
|
|
1382
|
+
componentEmit: process.env.PROTEUS_COMPONENTS_EMIT === "all" ? "all" : "used"
|
|
1225
1383
|
});
|
|
1226
1384
|
const appUsesStore = files.some((f) => {
|
|
1227
1385
|
try {
|
|
1228
|
-
const s =
|
|
1386
|
+
const s = fs5.readFileSync(f.file, "utf-8");
|
|
1229
1387
|
const script = s.includes("<script") ? s.match(/<script[^>]*>([\s\S]*?)<\/script>/i)?.[1] ?? "" : s;
|
|
1230
1388
|
return /\buse[A-Z]\w*Store\s*\(/.test(script);
|
|
1231
1389
|
} catch {
|
|
1232
1390
|
return false;
|
|
1233
1391
|
}
|
|
1234
1392
|
});
|
|
1235
|
-
const mpEntry =
|
|
1236
|
-
if (
|
|
1237
|
-
const src =
|
|
1393
|
+
const mpEntry = path5.join(appDir, "main.mp.ts");
|
|
1394
|
+
if (fs5.existsSync(mpEntry)) {
|
|
1395
|
+
const src = fs5.readFileSync(mpEntry, "utf-8");
|
|
1238
1396
|
const { code } = await esbuildTransform(src, { loader: "ts", charset: "utf8" });
|
|
1239
1397
|
const presets = filterOverriddenPresets(code, await loadPresetBuilders(projectRoot, cfg));
|
|
1240
1398
|
const piniaInstall = appUsesStore ? " // \u2605\u9875\u9762\u4F7F\u7528 store \u2192 \u5B89\u88C5\u5E76\u6FC0\u6D3B Pinia\uFF08\u5C0F\u7A0B\u5E8F\u65E0 createApp\uFF0C\u5FC5\u987B setActivePinia\uFF09\n var __proteusPiniaMod = require('./_proteus/runtime.js')\n if (__proteusPiniaMod && __proteusPiniaMod.createMpPinia) __proteusPiniaMod.createMpPinia()" : " // \uFF08\u672A\u68C0\u6D4B\u5230 store \u4F7F\u7528\u2014\u2014\u8DF3\u8FC7 Pinia \u5B89\u88C5\uFF09";
|
|
@@ -1243,19 +1401,19 @@ function mpTransform(opts) {
|
|
|
1243
1401
|
console.log(`[mp-transform] app.js \u5DF2\u76F4\u51FA\uFF08${isDebug ? "debug" : "\u6B63\u5F0F"}\uFF09\uFF0C\u5185\u7F6E\u9884\u8BBE\uFF1A${presets.map((p) => p.name).join("/") || "\u65E0"}${appUsesStore ? "\uFF0CPinia \u5DF2\u5B89\u88C5" : ""}`);
|
|
1244
1402
|
}
|
|
1245
1403
|
{
|
|
1246
|
-
const explicit = cfg.globalStyle ?
|
|
1404
|
+
const explicit = cfg.globalStyle ? path5.resolve(projectRoot, cfg.globalStyle) : void 0;
|
|
1247
1405
|
const candidates = [
|
|
1248
1406
|
explicit,
|
|
1249
|
-
|
|
1250
|
-
|
|
1407
|
+
path5.join(appDir, "app.wxss"),
|
|
1408
|
+
path5.join(projectRoot, "app.wxss")
|
|
1251
1409
|
].filter((p) => Boolean(p));
|
|
1252
|
-
const globalStylePath = candidates.find((p) =>
|
|
1410
|
+
const globalStylePath = candidates.find((p) => fs5.existsSync(p));
|
|
1253
1411
|
if (globalStylePath) {
|
|
1254
|
-
const raw =
|
|
1412
|
+
const raw = fs5.readFileSync(globalStylePath, "utf-8");
|
|
1255
1413
|
const normalized = rewriteRootToPage(raw);
|
|
1256
1414
|
const wxss = transformStyleToWxss(normalized, { px2rpx: cfg.style?.px2rpx ?? true, rpxRatio: cfg.style?.rpxRatio ?? 2, rules: cfg.rules });
|
|
1257
1415
|
this.emitFile({ type: "asset", fileName: "app.wxss", source: wxss });
|
|
1258
|
-
console.log(`[mp-transform] app.wxss \u5DF2\u4EA7\u51FA\uFF08${
|
|
1416
|
+
console.log(`[mp-transform] app.wxss \u5DF2\u4EA7\u51FA\uFF08${path5.relative(projectRoot, globalStylePath).replace(/\\/g, "/")}\u2014\u2014\u5168\u5C40\u8BBE\u8BA1 token/\u91CD\u7F6E\uFF0C:root\u2192page\uFF09`);
|
|
1259
1417
|
}
|
|
1260
1418
|
}
|
|
1261
1419
|
const moduleImportsByFile = /* @__PURE__ */ new Map();
|
|
@@ -1263,7 +1421,7 @@ function mpTransform(opts) {
|
|
|
1263
1421
|
const sharedRelNoExt = /* @__PURE__ */ new Map();
|
|
1264
1422
|
const resolveShared = (absFrom, source) => resolveSharedModule(appDir, absFrom, source, frameworkComponents, projectRoot, "mp");
|
|
1265
1423
|
const scanImports = (absFile) => {
|
|
1266
|
-
const src =
|
|
1424
|
+
const src = fs5.readFileSync(absFile, "utf-8");
|
|
1267
1425
|
const script = src.includes("<script") ? src.match(/<script[^>]*>([\s\S]*?)<\/script>/i)?.[1] ?? "" : src;
|
|
1268
1426
|
return scanSourceImports(script);
|
|
1269
1427
|
};
|
|
@@ -1327,21 +1485,21 @@ function mpTransform(opts) {
|
|
|
1327
1485
|
name: "proteus-pkg-require-path",
|
|
1328
1486
|
setup(b) {
|
|
1329
1487
|
const mapExternal = (target) => {
|
|
1330
|
-
const dir =
|
|
1331
|
-
let rel =
|
|
1488
|
+
const dir = path5.posix.dirname(relNoExt);
|
|
1489
|
+
let rel = path5.posix.relative(dir, target);
|
|
1332
1490
|
if (!rel.startsWith(".")) rel = `./${rel}`;
|
|
1333
1491
|
return { path: rel, external: true };
|
|
1334
1492
|
};
|
|
1335
1493
|
b.onResolve({ filter: /^@proteus-vue\// }, (args) => mapExternal(`_proteus/${args.path.replace("@proteus-vue/", "")}.js`));
|
|
1336
1494
|
b.onResolve({ filter: new RegExp(`^(${VENDOR_SINGLETONS.join("|")})$`) }, (args) => mapExternal(`_proteus/${args.path}.js`));
|
|
1337
1495
|
b.onLoad({ filter: /\.(md|txt|json)$/ }, (args) => ({
|
|
1338
|
-
contents: `export default ${JSON.stringify(
|
|
1496
|
+
contents: `export default ${JSON.stringify(fs5.readFileSync(args.path, "utf-8"))}`,
|
|
1339
1497
|
loader: "js"
|
|
1340
1498
|
}));
|
|
1341
1499
|
b.onLoad({ filter: /\.(png|jpe?g|gif|webp|svg|ico|woff2?|ttf|eot|mp3|mp4|wav|zip)$/ }, (args) => ({
|
|
1342
1500
|
errors: [
|
|
1343
1501
|
{
|
|
1344
|
-
text: `MP \u4EA7\u7269\u4E0D\u652F\u6301\u4E8C\u8FDB\u5236\u8D44\u6E90 import\uFF1A${
|
|
1502
|
+
text: `MP \u4EA7\u7269\u4E0D\u652F\u6301\u4E8C\u8FDB\u5236\u8D44\u6E90 import\uFF1A${path5.relative(projectRoot, args.path)}\u2014\u2014\u8BF7\u6539\u7528\u7F51\u7EDC URL \u6216 base64 \u5185\u8054`
|
|
1345
1503
|
}
|
|
1346
1504
|
]
|
|
1347
1505
|
}));
|
|
@@ -1400,7 +1558,7 @@ function mpTransform(opts) {
|
|
|
1400
1558
|
const inputFiles = Object.keys(build.metafile.inputs);
|
|
1401
1559
|
const inputs = inputFiles.map((f) => {
|
|
1402
1560
|
try {
|
|
1403
|
-
const st =
|
|
1561
|
+
const st = fs5.statSync(f);
|
|
1404
1562
|
return { file: f, mtimeMs: st.mtimeMs, size: st.size };
|
|
1405
1563
|
} catch {
|
|
1406
1564
|
return null;
|
|
@@ -1415,18 +1573,18 @@ function mpTransform(opts) {
|
|
|
1415
1573
|
for (const [file, list] of moduleImportsByFile) {
|
|
1416
1574
|
const entry = files.find((f) => f.file === file);
|
|
1417
1575
|
if (!entry) continue;
|
|
1418
|
-
const pageDir =
|
|
1576
|
+
const pageDir = path5.posix.dirname(entry.rel);
|
|
1419
1577
|
for (const item of list) {
|
|
1420
1578
|
const shared = resolveShared(file, item.source);
|
|
1421
1579
|
if (!shared) continue;
|
|
1422
1580
|
const sharedRel = `${shared.relNoExt}.js`;
|
|
1423
|
-
let rel =
|
|
1581
|
+
let rel = path5.posix.relative(pageDir, sharedRel);
|
|
1424
1582
|
if (!rel.startsWith(".")) rel = `./${rel}`;
|
|
1425
1583
|
item.requirePath = rel;
|
|
1426
1584
|
}
|
|
1427
1585
|
}
|
|
1428
1586
|
for (const { file, rel, isComponent } of files) {
|
|
1429
|
-
const source =
|
|
1587
|
+
const source = fs5.readFileSync(file, "utf-8");
|
|
1430
1588
|
if (rustCompiler) {
|
|
1431
1589
|
const v = verifyDualCompilerEquivalence(source, { rustBin: rustCliBin, filename: file });
|
|
1432
1590
|
if (v.status === "ok") {
|
|
@@ -1546,21 +1704,21 @@ function mpTransform(opts) {
|
|
|
1546
1704
|
console.log(`[mp-transform] ${rel} \u2192 wxml/js/wxss \u5DF2\u8F93\u51FA`);
|
|
1547
1705
|
}
|
|
1548
1706
|
{
|
|
1549
|
-
const publicDir =
|
|
1550
|
-
if (
|
|
1707
|
+
const publicDir = path5.join(projectRoot, "public");
|
|
1708
|
+
if (fs5.existsSync(publicDir)) {
|
|
1551
1709
|
const rels = [];
|
|
1552
1710
|
const walk = (dir) => {
|
|
1553
|
-
for (const e of
|
|
1711
|
+
for (const e of fs5.readdirSync(dir, { withFileTypes: true })) {
|
|
1554
1712
|
if (e.name.startsWith(".")) continue;
|
|
1555
|
-
const full =
|
|
1713
|
+
const full = path5.join(dir, e.name);
|
|
1556
1714
|
if (e.isDirectory()) walk(full);
|
|
1557
|
-
else rels.push(
|
|
1715
|
+
else rels.push(path5.relative(publicDir, full).replace(/\\/g, "/"));
|
|
1558
1716
|
}
|
|
1559
1717
|
};
|
|
1560
1718
|
walk(publicDir);
|
|
1561
1719
|
let assetN = 0;
|
|
1562
1720
|
for (const { from, to } of mapPublicAssetVariants(rels, "mp")) {
|
|
1563
|
-
this.emitFile({ type: "asset", fileName: to, source:
|
|
1721
|
+
this.emitFile({ type: "asset", fileName: to, source: fs5.readFileSync(path5.join(publicDir, from)) });
|
|
1564
1722
|
assetN++;
|
|
1565
1723
|
}
|
|
1566
1724
|
if (assetN) console.log(`[mp-transform] public \u9759\u6001\u8D44\u6E90 \u2192 ${assetN} \u4E2A\uFF08\u5E73\u53F0\u53D8\u4F53\u5DF2\u6309 mp \u89E3\u6790\uFF09`);
|
|
@@ -1592,8 +1750,8 @@ function mpTransform(opts) {
|
|
|
1592
1750
|
}
|
|
1593
1751
|
|
|
1594
1752
|
// src/devtools-plugin.ts
|
|
1595
|
-
import
|
|
1596
|
-
import
|
|
1753
|
+
import fs6 from "node:fs";
|
|
1754
|
+
import path6 from "node:path";
|
|
1597
1755
|
import { createRequire as createRequire4 } from "node:module";
|
|
1598
1756
|
import { WebSocketServer } from "ws";
|
|
1599
1757
|
|
|
@@ -1664,7 +1822,7 @@ function isOriginAllowed(origin, allowFrom) {
|
|
|
1664
1822
|
return allowFrom.indexOf(origin) >= 0;
|
|
1665
1823
|
}
|
|
1666
1824
|
function resolveDevtoolsDir() {
|
|
1667
|
-
return
|
|
1825
|
+
return path6.dirname(require_.resolve("@proteus-vue/devtools/package.json"));
|
|
1668
1826
|
}
|
|
1669
1827
|
function createPanelPageHandler(devtoolsDir) {
|
|
1670
1828
|
return (req, res) => {
|
|
@@ -1673,19 +1831,19 @@ function createPanelPageHandler(devtoolsDir) {
|
|
|
1673
1831
|
if (pathname === base || pathname === base + "/") {
|
|
1674
1832
|
const host = req.headers?.host ?? "localhost";
|
|
1675
1833
|
const proto = req.headers?.["x-forwarded-proto"] === "https" ? "wss" : "ws";
|
|
1676
|
-
const html =
|
|
1834
|
+
const html = fs6.readFileSync(path6.join(devtoolsDir, "panel.html"), "utf8").replace(/__PROTEUS_DEFAULT_WS__/g, `'${proto}://${host}/proteus-panel'`).replace("./style.css", base + "/style.css").replace("./dist/panel.js", base + "/panel.js");
|
|
1677
1835
|
res.setHeader("content-type", "text/html; charset=utf-8");
|
|
1678
1836
|
res.end(html);
|
|
1679
1837
|
return true;
|
|
1680
1838
|
}
|
|
1681
1839
|
if (pathname === base + "/style.css") {
|
|
1682
1840
|
res.setHeader("content-type", "text/css; charset=utf-8");
|
|
1683
|
-
res.end(
|
|
1841
|
+
res.end(fs6.readFileSync(path6.join(devtoolsDir, "style.css")));
|
|
1684
1842
|
return true;
|
|
1685
1843
|
}
|
|
1686
1844
|
if (pathname === base + "/panel.js") {
|
|
1687
1845
|
res.setHeader("content-type", "application/javascript; charset=utf-8");
|
|
1688
|
-
res.end(
|
|
1846
|
+
res.end(fs6.readFileSync(path6.join(devtoolsDir, "dist", "panel.js")));
|
|
1689
1847
|
return true;
|
|
1690
1848
|
}
|
|
1691
1849
|
return false;
|
|
@@ -1759,8 +1917,8 @@ function devtoolsRelayPlugin(opts = {}) {
|
|
|
1759
1917
|
}
|
|
1760
1918
|
|
|
1761
1919
|
// src/vite-config.ts
|
|
1762
|
-
import
|
|
1763
|
-
import
|
|
1920
|
+
import path7 from "node:path";
|
|
1921
|
+
import fs7 from "node:fs";
|
|
1764
1922
|
import { pathToFileURL } from "node:url";
|
|
1765
1923
|
import { createRequire as createRequire5 } from "node:module";
|
|
1766
1924
|
import {
|
|
@@ -1794,25 +1952,25 @@ function platformVariantPlugin(root, platform) {
|
|
|
1794
1952
|
const bare = qIdx >= 0 ? id.slice(0, qIdx) : id;
|
|
1795
1953
|
if (!bare) return null;
|
|
1796
1954
|
let base;
|
|
1797
|
-
if (bare.startsWith(".")) base =
|
|
1798
|
-
else if (bare.startsWith("@/")) base =
|
|
1955
|
+
if (bare.startsWith(".")) base = path7.resolve(path7.dirname(importer), bare);
|
|
1956
|
+
else if (bare.startsWith("@/")) base = path7.resolve(root, "src", bare.slice(2));
|
|
1799
1957
|
else return null;
|
|
1800
|
-
const hasExt =
|
|
1958
|
+
const hasExt = path7.extname(base) !== "";
|
|
1801
1959
|
if (hasExt) {
|
|
1802
|
-
const r2 = resolvePlatformVariant2(base, platform,
|
|
1960
|
+
const r2 = resolvePlatformVariant2(base, platform, fs7.existsSync);
|
|
1803
1961
|
return r2 && r2 !== base ? r2 + query : null;
|
|
1804
1962
|
}
|
|
1805
|
-
const r = resolvePlatformVariantWithExts2(base, CODE_EXTS, platform,
|
|
1963
|
+
const r = resolvePlatformVariantWithExts2(base, CODE_EXTS, platform, fs7.existsSync);
|
|
1806
1964
|
return r ? r + query : null;
|
|
1807
1965
|
}
|
|
1808
1966
|
};
|
|
1809
1967
|
}
|
|
1810
1968
|
function hasPublicVariants(publicDir) {
|
|
1811
|
-
if (!
|
|
1969
|
+
if (!fs7.existsSync(publicDir)) return false;
|
|
1812
1970
|
const walk = (dir) => {
|
|
1813
|
-
for (const e of
|
|
1971
|
+
for (const e of fs7.readdirSync(dir, { withFileTypes: true })) {
|
|
1814
1972
|
if (e.name.startsWith(".")) continue;
|
|
1815
|
-
const full =
|
|
1973
|
+
const full = path7.join(dir, e.name);
|
|
1816
1974
|
if (e.isDirectory()) {
|
|
1817
1975
|
if (walk(full)) return true;
|
|
1818
1976
|
} else if (splitVariant3(e.name).platform !== void 0) {
|
|
@@ -1828,20 +1986,20 @@ function platformPublicAssetsPlugin(root, platform) {
|
|
|
1828
1986
|
name: "proteus-platform-public-assets",
|
|
1829
1987
|
apply: "build",
|
|
1830
1988
|
generateBundle() {
|
|
1831
|
-
const publicDir =
|
|
1832
|
-
if (!
|
|
1989
|
+
const publicDir = path7.join(root, "public");
|
|
1990
|
+
if (!fs7.existsSync(publicDir)) return;
|
|
1833
1991
|
const rels = [];
|
|
1834
1992
|
const walk = (dir) => {
|
|
1835
|
-
for (const e of
|
|
1993
|
+
for (const e of fs7.readdirSync(dir, { withFileTypes: true })) {
|
|
1836
1994
|
if (e.name.startsWith(".")) continue;
|
|
1837
|
-
const full =
|
|
1995
|
+
const full = path7.join(dir, e.name);
|
|
1838
1996
|
if (e.isDirectory()) walk(full);
|
|
1839
|
-
else rels.push(
|
|
1997
|
+
else rels.push(path7.relative(publicDir, full).replace(/\\/g, "/"));
|
|
1840
1998
|
}
|
|
1841
1999
|
};
|
|
1842
2000
|
walk(publicDir);
|
|
1843
2001
|
for (const { from, to } of mapPublicAssetVariants2(rels, platform)) {
|
|
1844
|
-
this.emitFile({ type: "asset", fileName: to, source:
|
|
2002
|
+
this.emitFile({ type: "asset", fileName: to, source: fs7.readFileSync(path7.join(publicDir, from)) });
|
|
1845
2003
|
}
|
|
1846
2004
|
}
|
|
1847
2005
|
};
|
|
@@ -1869,7 +2027,7 @@ function virtualMpEntryPlugin() {
|
|
|
1869
2027
|
};
|
|
1870
2028
|
}
|
|
1871
2029
|
async function importFromRoot(root, spec) {
|
|
1872
|
-
const req = createRequire5(
|
|
2030
|
+
const req = createRequire5(path7.join(root, "package.json"));
|
|
1873
2031
|
const resolved = req.resolve(spec);
|
|
1874
2032
|
return import(pathToFileURL(resolved).href);
|
|
1875
2033
|
}
|
|
@@ -1906,15 +2064,15 @@ async function resolveProteusViteConfig(ctx, config) {
|
|
|
1906
2064
|
// ★平台变体·静态资源 Web 通道(第 3 层):public/ 含平台变体(logo.web.png)时,
|
|
1907
2065
|
// 关掉 Vite 默认逐字拷贝(会把他端变体也拷进产物),改由 platformPublicAssetsPlugin 按 web 解析;
|
|
1908
2066
|
// 无变体时保持默认(零侵入,避免改变既有工程行为)。
|
|
1909
|
-
publicDir: hasPublicVariants(
|
|
2067
|
+
publicDir: hasPublicVariants(path7.join(root, "public")) ? false : void 0,
|
|
1910
2068
|
resolve: {
|
|
1911
|
-
alias: [{ find: "@", replacement:
|
|
2069
|
+
alias: [{ find: "@", replacement: path7.join(root, "src") }]
|
|
1912
2070
|
},
|
|
1913
2071
|
build: {
|
|
1914
2072
|
target: "es2018",
|
|
1915
2073
|
cssCodeSplit: false,
|
|
1916
2074
|
minify: isMp ? false : void 0,
|
|
1917
|
-
outDir:
|
|
2075
|
+
outDir: path7.join(root, "dist", platform),
|
|
1918
2076
|
emptyOutDir: !isMp,
|
|
1919
2077
|
rollupOptions: isMp ? { input: "proteus:mp-entry", output: { entryFileNames: "mp-entry.js" } } : void 0
|
|
1920
2078
|
}
|
package/dist/plugin.d.ts
CHANGED
|
@@ -119,6 +119,8 @@ export declare function collectMpEntries(opts: {
|
|
|
119
119
|
onSkipWebOnly?: (file: string) => void;
|
|
120
120
|
/** ★平台变体(2026-09-13):按该平台解析 `foo.mp.vue`/`foo.web.vue`(缺省 mp) */
|
|
121
121
|
platform?: VariantPlatform;
|
|
122
|
+
/** ★框架组件输出策略(2026-09-18):'used'(缺省,按引用闭包输出)/ 'all'(全量,逃生舱) */
|
|
123
|
+
componentEmit?: 'used' | 'all';
|
|
122
124
|
}): Array<{
|
|
123
125
|
file: string;
|
|
124
126
|
rel: string;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/** 抽取 `<template>` 块正文(跳过注释 / script / style / 嵌套 template 深度) */
|
|
2
|
+
export declare function extractTemplateBody(src: string): string;
|
|
3
|
+
/**
|
|
4
|
+
* 扫描模板正文中出现的全部标签名(kebab 化;跳过注释块)。
|
|
5
|
+
* PascalCase(`<PSafe>`)→ kebab(`p-safe`)——★旧正则只匹配小写开头,
|
|
6
|
+
* 导致 `<PSafe>` 完全跳过扫描(既不注册也不告警 → 组件静默不渲染,showcase 踩坑)。
|
|
7
|
+
*/
|
|
8
|
+
export declare function extractTags(tpl: string): Set<string>;
|
|
9
|
+
/**
|
|
10
|
+
* ★编译器**产出**的组件标签(源码模板中不存在,由 compiler lowering 生成)。
|
|
11
|
+
* 必须计入引用集合,否则按需输出会把这些组件漏掉 → 运行时不渲染(真 bug)。
|
|
12
|
+
*
|
|
13
|
+
* 与 gen-routes 的 collectComponents 同源规则(两处必须一致):
|
|
14
|
+
* 源码含**形状变化动画**的 SVG(cx/r/d/stroke-dashoffset 等)→ 编译器 lowering 为 `<p-svg-canvas>`。
|
|
15
|
+
*/
|
|
16
|
+
export declare function collectCompilerEmittedTags(templateBody: string): Set<string>;
|
|
17
|
+
/**
|
|
18
|
+
* 计算页面**实际引用**的框架组件目录集合(含组件间传递依赖闭包)。
|
|
19
|
+
*
|
|
20
|
+
* 用途:MP 产物只输出用到的组件(而非全量 76 个 = 607 KB)——对每个真实应用都是可观瘦身。
|
|
21
|
+
* ★诚实边界:仅识别**静态模板标签**。运行时动态拼标签不受支持(MP 本就无 `<component :is>`,
|
|
22
|
+
* 编译器已对 `<component :is>` 显式告警)——若确有非常规用法,可用 `components.emit: 'all'` 关闭本优化。
|
|
23
|
+
*
|
|
24
|
+
* @param pageFiles 页面源文件绝对路径(主包 + 分包,**须已排除 webOnly 页面**)
|
|
25
|
+
* @param componentsDir 框架组件根目录
|
|
26
|
+
* @returns 组件目录名集合(如 `p-view`);空集表示「未引用任何框架组件」
|
|
27
|
+
*/
|
|
28
|
+
export declare function collectUsedFrameworkComponents(pageFiles: readonly string[], componentsDir: string): Set<string>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@proteus-vue/plugin-vite",
|
|
3
|
-
"version": "0.2.0-beta.
|
|
3
|
+
"version": "0.2.0-beta.5",
|
|
4
4
|
"description": "Proteus Vite 插件(mp-weixin 编译管线适配层)+ gen-routes 路由表生成器",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -19,14 +19,14 @@
|
|
|
19
19
|
"README.md"
|
|
20
20
|
],
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@proteus-vue/compiler": "0.3.0-beta.
|
|
23
|
-
"@proteus-vue/module": "0.1.0",
|
|
24
|
-
"@proteus-vue/router": "0.2.0-beta.
|
|
25
|
-
"@proteus-vue/types": "0.2.0-beta.
|
|
22
|
+
"@proteus-vue/compiler": "0.3.0-beta.3",
|
|
23
|
+
"@proteus-vue/module": "0.1.1-beta.0",
|
|
24
|
+
"@proteus-vue/router": "0.2.0-beta.5",
|
|
25
|
+
"@proteus-vue/types": "0.2.0-beta.2",
|
|
26
26
|
"esbuild": "^0.28.2",
|
|
27
27
|
"sass": "^1.103.1",
|
|
28
28
|
"ws": "^8.0.0",
|
|
29
|
-
"@proteus-vue/compiler-backend": "0.1.1-beta.
|
|
29
|
+
"@proteus-vue/compiler-backend": "0.1.1-beta.1"
|
|
30
30
|
},
|
|
31
31
|
"peerDependencies": {
|
|
32
32
|
"vite": "^5.0.0"
|