weapp-vite 7.4.0 → 7.5.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 +51 -1
- package/bin/bootstrap.js +14 -1
- package/dist/adapters-CcHrsYaj.mjs +1 -0
- package/dist/analyze-ZJUvEdaY.mjs +248 -0
- package/dist/auto-import-components/resolvers.mjs +1 -2
- package/dist/auto-import-presets/wevu-router.mjs +1 -2
- package/dist/auto-import-presets/wevu.mjs +1 -2
- package/dist/auto-routes.mjs +2 -1
- package/dist/budget-BD7VqLCl.d.mts +178 -0
- package/dist/chunkStrategy-DRA5WpB-.mjs +1436 -0
- package/dist/cli-acceptance.d.mts +1 -0
- package/dist/cli-acceptance.mjs +21 -0
- package/dist/cli.mjs +1420 -1554
- package/dist/compatibility.mjs +1 -2
- package/dist/{config-Dbvj5yK7.d.mts → config-V0L-IAJf.d.mts} +87 -30
- package/dist/config.d.mts +2 -2
- package/dist/config.mjs +1 -1
- package/dist/{constants-WOsG3Eqd.mjs → constants-DEZdcsMn.mjs} +1 -1
- package/dist/{createContext-UOEgeYnA.mjs → createCompilerContextInstance-DJH_P_nZ.mjs} +31278 -32148
- package/dist/createContext-BqYzHhY9.mjs +12 -0
- package/dist/dashboard/analyze.d.mts +48 -0
- package/dist/dashboard/analyze.mjs +1 -0
- package/dist/dashboard/vite.d.mts +1 -1
- package/dist/dashboard-DvqF3Key.mjs +1842 -0
- package/dist/dashboard.d.mts +3 -2
- package/dist/dashboard.mjs +1 -2
- package/dist/dashboardViteBridge-Dy3nAD4m.mjs +299 -0
- package/dist/dev-fR5GiJRO.mjs +63 -0
- package/dist/devProvider-BGBkw28J.mjs +1050 -0
- package/dist/docs/README.md +51 -1
- package/dist/docs/ai-workflows.md +4 -0
- package/dist/docs/doctor.md +38 -0
- package/dist/docs/getting-started.md +3 -1
- package/dist/docs/index.md +3 -1
- package/dist/docs/mcp.md +94 -1
- package/dist/docs/testing.md +29 -2
- package/dist/docs/troubleshooting.md +8 -0
- package/dist/docs/uni-app-component-libraries.md +8 -7
- package/dist/docs/upload.md +40 -3
- package/dist/docs/vite-plugin.md +171 -0
- package/dist/docs/vue-sfc.md +19 -0
- package/dist/docs/weapp-config.md +54 -0
- package/dist/docs/wevu-authoring.md +10 -0
- package/dist/doctor-worker.d.mts +1 -0
- package/dist/doctor-worker.mjs +59 -0
- package/dist/doctor.d.mts +144 -0
- package/dist/doctor.mjs +848 -0
- package/dist/eslint.mjs +1 -2
- package/dist/file-DRb4eWqw.mjs +1 -0
- package/dist/{file-giE9UMZa.mjs → file-sC3jD7Fh.mjs} +15 -9
- package/dist/files-BqxFIPRp.mjs +45 -0
- package/dist/getInstance-DiGSzBNI.mjs +28 -0
- package/dist/getInstance-SiE6WZRh.mjs +1 -0
- package/dist/index-C9HjUX5c.d.mts +741 -0
- package/dist/index.d.mts +10 -8
- package/dist/index.mjs +3 -2
- package/dist/json.d.mts +1 -1
- package/dist/json.mjs +1 -2
- package/dist/lifecycle-BROTlwSL.mjs +320 -0
- package/dist/loadConfig-C3BQhz7F.mjs +59 -0
- package/dist/loadConfig-VGtBF4qm.mjs +1 -0
- package/dist/logger-DGn5iEVN.mjs +1 -0
- package/dist/{mcp-BG6TliEg.mjs → mcp-Cj8Maqo6.mjs} +16 -7
- package/dist/mcp-D3Yh24Cj.mjs +529 -0
- package/dist/mcp.d.mts +6 -3
- package/dist/mcp.mjs +1 -2
- package/dist/package-7swhyLmf.mjs +91 -0
- package/dist/path-doV773b7.mjs +103 -0
- package/dist/{platform-DTWs5QRi.mjs → platform-CnkySBKz.mjs} +1 -1
- package/dist/processCleanup-B6KA30Zc.mjs +77 -0
- package/dist/protocol-vg8HGJ4n.mjs +138 -0
- package/dist/{resolvers-icNxkpcy.mjs → resolvers-Dod-euqX.mjs} +4 -1
- package/dist/resolvers.mjs +1 -2
- package/dist/runtime.mjs +1 -2
- package/dist/session-PskhD-nZ.mjs +390 -0
- package/dist/test.d.mts +1 -0
- package/dist/test.mjs +201 -44
- package/dist/types.d.mts +2 -2
- package/dist/{upload-D0RcEWrq.mjs → upload-D4msblBf.mjs} +174 -15
- package/dist/upload-worker.mjs +136 -3
- package/dist/utils-CJSCgEj6.mjs +1094 -0
- package/dist/vite.d.mts +9 -0
- package/dist/vite.mjs +270 -0
- package/dist/volar.d.mts +2 -2
- package/dist/web-apis.mjs +1 -2
- package/package.json +67 -41
- package/dist/adapters-BwnMMIZR.mjs +0 -2
- package/dist/dashboard-BzaVesmQ.mjs +0 -558
- package/dist/file-D19nbDoN.mjs +0 -2
- package/dist/getInstance-CYF1vl5l.mjs +0 -2
- package/dist/index-DbqVupg0.d.mts +0 -246
- package/dist/logger-mt4mSTqV.mjs +0 -2
|
@@ -0,0 +1,390 @@
|
|
|
1
|
+
import { C as attachStatefulHmrHost, D as resolveHmrRuntimeDecision, E as createSharedBuildConfig, T as getStatefulHmrHost, _ as getPackNpmRelationList, b as createOxcRuntimeSupport, g as captureWatchDependencies, h as checkAppWorkersOptions, m as syncManagedTsconfigFiles, u as CompilerSession, v as createPackageBuilder, w as createStatefulHmrHostPlugins, y as settlePackageBuilds } from "./createCompilerContextInstance-DJH_P_nZ.mjs";
|
|
2
|
+
import { c as resolveRealpath } from "./protocol-vg8HGJ4n.mjs";
|
|
3
|
+
import { F as resolveNpmDistDirName, L as resolveTargetDependencies, M as resolveMainBuildDependencyPatterns, N as resolveNpmBuildCandidateDependenciesSync, f as attachDevModuleGraphHost } from "./devProvider-BGBkw28J.mjs";
|
|
4
|
+
import { v as loadHostRolldownBuild, y as pruneOwnedAssetFiles } from "./utils-CJSCgEj6.mjs";
|
|
5
|
+
import path from "pathe";
|
|
6
|
+
import { mkdtemp, readFile, readdir, rm } from "node:fs/promises";
|
|
7
|
+
import { build } from "vite";
|
|
8
|
+
import { createHash } from "node:crypto";
|
|
9
|
+
import { Buffer } from "node:buffer";
|
|
10
|
+
import os from "node:os";
|
|
11
|
+
//#region src/vite/npm/sourcemap.ts
|
|
12
|
+
const URL_SCHEME = /^[a-z][a-z\d+.-]*:/i;
|
|
13
|
+
const INLINE_MAP = /(\/\/[#@]\s*sourceMappingURL=data:application\/json(?:;charset=[^;,]*)?;base64,)([a-z\d+/=]+)/gi;
|
|
14
|
+
/** npm 镜像目录深度可能不同,重定位相对源码路径但保持 URL 与绝对来源不变。 */
|
|
15
|
+
function relocateNpmSourcemap(source, from, to) {
|
|
16
|
+
if (!from.endsWith(".map")) {
|
|
17
|
+
if (/\.[cm]?js$/.test(from)) return (typeof source === "string" ? source : Buffer.from(source).toString("utf8")).replace(INLINE_MAP, (_match, prefix, encoded) => {
|
|
18
|
+
const map = relocateNpmSourcemap(Buffer.from(encoded, "base64"), `${from}.map`, `${to}.map`);
|
|
19
|
+
return `${prefix}${Buffer.from(map).toString("base64")}`;
|
|
20
|
+
});
|
|
21
|
+
return source;
|
|
22
|
+
}
|
|
23
|
+
let value;
|
|
24
|
+
try {
|
|
25
|
+
value = JSON.parse(typeof source === "string" ? source : Buffer.from(source).toString("utf8"));
|
|
26
|
+
} catch {
|
|
27
|
+
return source;
|
|
28
|
+
}
|
|
29
|
+
if (!value || typeof value !== "object" || !("sources" in value) || !Array.isArray(value.sources) || !value.sources.every((item) => typeof item === "string")) return source;
|
|
30
|
+
const sourceRoot = "sourceRoot" in value && typeof value.sourceRoot === "string" ? value.sourceRoot : "";
|
|
31
|
+
if (URL_SCHEME.test(sourceRoot)) return source;
|
|
32
|
+
const sources = value.sources.map((item) => {
|
|
33
|
+
if (URL_SCHEME.test(item) || path.isAbsolute(item)) return item;
|
|
34
|
+
return path.relative(path.dirname(to), path.resolve(path.dirname(from), sourceRoot, item));
|
|
35
|
+
});
|
|
36
|
+
return JSON.stringify({
|
|
37
|
+
...value,
|
|
38
|
+
sourceRoot: "",
|
|
39
|
+
sources
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
//#endregion
|
|
43
|
+
//#region src/vite/npm/output.ts
|
|
44
|
+
function relativeOutput(root, target) {
|
|
45
|
+
const relative = path.relative(root, target);
|
|
46
|
+
return relative !== ".." && !relative.startsWith("../") && !path.isAbsolute(relative) ? relative : void 0;
|
|
47
|
+
}
|
|
48
|
+
/** 依赖回调只决定逻辑路径,bundle 保持内存,原生包复制只进入本会话的临时目录。 */
|
|
49
|
+
function createNpmOutput(temporaryRoot, targetRoots) {
|
|
50
|
+
const directories = /* @__PURE__ */ new Map();
|
|
51
|
+
const roots = new Set(targetRoots);
|
|
52
|
+
const files = /* @__PURE__ */ new Map();
|
|
53
|
+
const watchFiles = /* @__PURE__ */ new Set();
|
|
54
|
+
function addFile(fileName, source) {
|
|
55
|
+
const existing = files.get(fileName);
|
|
56
|
+
if (existing !== void 0 && !Buffer.from(existing).equals(Buffer.from(source))) throw new Error(`[weapp-vite] 多个 npm 依赖产生了不同内容的同名文件:${fileName}`);
|
|
57
|
+
files.set(fileName, source);
|
|
58
|
+
}
|
|
59
|
+
const output = {
|
|
60
|
+
watchFile(fileName) {
|
|
61
|
+
watchFiles.add(fileName);
|
|
62
|
+
},
|
|
63
|
+
directory(outDir) {
|
|
64
|
+
roots.add(outDir);
|
|
65
|
+
const parent = [...directories.keys()].filter((root) => relativeOutput(root, outDir) !== void 0).sort((a, b) => b.length - a.length)[0];
|
|
66
|
+
if (parent) return path.join(directories.get(parent), relativeOutput(parent, outDir));
|
|
67
|
+
const directory = path.join(temporaryRoot, String(directories.size));
|
|
68
|
+
directories.set(outDir, directory);
|
|
69
|
+
return directory;
|
|
70
|
+
},
|
|
71
|
+
async bundle(options, outDir) {
|
|
72
|
+
roots.add(outDir);
|
|
73
|
+
const result = await build({
|
|
74
|
+
...options,
|
|
75
|
+
build: {
|
|
76
|
+
...options.build,
|
|
77
|
+
write: false,
|
|
78
|
+
watch: null
|
|
79
|
+
},
|
|
80
|
+
plugins: [
|
|
81
|
+
...options.plugins ?? [],
|
|
82
|
+
captureWatchDependencies((file) => watchFiles.add(file)),
|
|
83
|
+
{
|
|
84
|
+
name: "weapp-vite:npm-inputs",
|
|
85
|
+
configResolved(config) {
|
|
86
|
+
for (const file of config.configFileDependencies) watchFiles.add(file);
|
|
87
|
+
},
|
|
88
|
+
buildEnd() {
|
|
89
|
+
for (const file of this.getModuleIds()) if (!file.includes("\0")) watchFiles.add(file.split("?")[0]);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
]
|
|
93
|
+
});
|
|
94
|
+
for (const bundle of Array.isArray(result) ? result : [result]) {
|
|
95
|
+
if (!("output" in bundle)) throw new Error("[weapp-vite] npm 子构建必须返回内存产物。");
|
|
96
|
+
for (const item of bundle.output) addFile(path.resolve(outDir, item.fileName), item.type === "chunk" ? item.code : item.source);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
for (const root of targetRoots) output.directory(root);
|
|
101
|
+
async function collect(directory, logicalRoot) {
|
|
102
|
+
let entries;
|
|
103
|
+
try {
|
|
104
|
+
entries = await readdir(directory, { withFileTypes: true });
|
|
105
|
+
} catch (error) {
|
|
106
|
+
if (error.code === "ENOENT") return;
|
|
107
|
+
throw error;
|
|
108
|
+
}
|
|
109
|
+
for (const entry of entries) {
|
|
110
|
+
const source = path.join(directory, entry.name);
|
|
111
|
+
const destination = path.join(logicalRoot, entry.name);
|
|
112
|
+
if (entry.isDirectory()) await collect(source, destination);
|
|
113
|
+
else if (entry.isFile()) addFile(destination, await readFile(source));
|
|
114
|
+
else throw new Error(`[weapp-vite] npm 中间目录含有无法发布的文件类型:${destination}`);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return {
|
|
118
|
+
output,
|
|
119
|
+
async finish(hostOutDir, mainOutDir, mirrors) {
|
|
120
|
+
for (const [logicalRoot, directory] of directories) await collect(directory, logicalRoot);
|
|
121
|
+
const mainFiles = [...files].filter(([fileName]) => relativeOutput(mainOutDir, fileName) !== void 0);
|
|
122
|
+
for (const mirror of mirrors) {
|
|
123
|
+
roots.add(mirror);
|
|
124
|
+
for (const [fileName, source] of mainFiles) {
|
|
125
|
+
const mirroredFile = path.join(mirror, relativeOutput(mainOutDir, fileName));
|
|
126
|
+
addFile(mirroredFile, relocateNpmSourcemap(source, fileName, mirroredFile));
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
const result = {
|
|
130
|
+
assets: [],
|
|
131
|
+
external: /* @__PURE__ */ new Map(),
|
|
132
|
+
watchFiles: [...watchFiles]
|
|
133
|
+
};
|
|
134
|
+
for (const [absolutePath, source] of files) {
|
|
135
|
+
const relative = relativeOutput(hostOutDir, absolutePath);
|
|
136
|
+
if (relative !== void 0) {
|
|
137
|
+
result.assets.push({
|
|
138
|
+
type: "asset",
|
|
139
|
+
fileName: relative,
|
|
140
|
+
source
|
|
141
|
+
});
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
const directory = [...roots].filter((root) => relativeOutput(root, absolutePath) !== void 0).sort((a, b) => a.length - b.length)[0];
|
|
145
|
+
const assets = result.external.get(directory) ?? [];
|
|
146
|
+
assets.push({
|
|
147
|
+
type: "asset",
|
|
148
|
+
fileName: relativeOutput(directory, absolutePath),
|
|
149
|
+
source
|
|
150
|
+
});
|
|
151
|
+
result.external.set(directory, assets);
|
|
152
|
+
}
|
|
153
|
+
return result;
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
//#endregion
|
|
158
|
+
//#region src/vite/npm/index.ts
|
|
159
|
+
/** 复用依赖编译器和 npm 关联配置,最终输出统一交给宿主 emit/write。 */
|
|
160
|
+
async function prepareNpmAssets(ctx) {
|
|
161
|
+
const config = ctx.configService;
|
|
162
|
+
const empty = {
|
|
163
|
+
assets: [],
|
|
164
|
+
external: /* @__PURE__ */ new Map(),
|
|
165
|
+
watchFiles: []
|
|
166
|
+
};
|
|
167
|
+
if (config.weappLibConfig?.enabled || !config.weappViteConfig.npm?.enable) return empty;
|
|
168
|
+
const [main, ...mirrors] = getPackNpmRelationList(ctx, { defaultOutputRoot: config.outDir });
|
|
169
|
+
if (!main) return empty;
|
|
170
|
+
const packageJsonPath = path.resolve(config.cwd, main.packageJsonPath);
|
|
171
|
+
const resolveFrom = path.dirname(packageJsonPath);
|
|
172
|
+
let packageJson;
|
|
173
|
+
try {
|
|
174
|
+
packageJson = JSON.parse(await readFile(packageJsonPath, "utf8"));
|
|
175
|
+
} catch (error) {
|
|
176
|
+
if (error.code === "ENOENT") return empty;
|
|
177
|
+
throw error;
|
|
178
|
+
}
|
|
179
|
+
const candidates = resolveNpmBuildCandidateDependenciesSync(ctx, packageJson, resolveFrom);
|
|
180
|
+
ctx.scanService.loadSubPackages();
|
|
181
|
+
const npmDirName = resolveNpmDistDirName(config);
|
|
182
|
+
const mainOutDir = path.resolve(config.cwd, main.miniprogramNpmDistDir, npmDirName);
|
|
183
|
+
const targets = [{
|
|
184
|
+
outDir: mainOutDir,
|
|
185
|
+
dependencies: resolveTargetDependencies(candidates, resolveMainBuildDependencyPatterns(ctx))
|
|
186
|
+
}, ...[...ctx.scanService.subPackageMap.values()].filter((entry) => entry.subPackage.dependencies?.length).map((entry) => ({
|
|
187
|
+
outDir: path.join(config.outDir, entry.subPackage.root, npmDirName),
|
|
188
|
+
dependencies: resolveTargetDependencies(candidates, entry.subPackage.dependencies)
|
|
189
|
+
}))];
|
|
190
|
+
const temporaryRoot = await mkdtemp(path.join(os.tmpdir(), "weapp-vite-npm-"));
|
|
191
|
+
const capture = createNpmOutput(temporaryRoot, targets.map((target) => target.outDir));
|
|
192
|
+
capture.output.watchFile?.(packageJsonPath);
|
|
193
|
+
const builder = createPackageBuilder(ctx, createOxcRuntimeSupport().vitePlugin, capture.output);
|
|
194
|
+
try {
|
|
195
|
+
for (const target of targets) await settlePackageBuilds(target.dependencies.map((dep) => builder.buildPackage({
|
|
196
|
+
dep,
|
|
197
|
+
resolveFrom,
|
|
198
|
+
outDir: target.outDir,
|
|
199
|
+
isDependenciesCacheOutdate: true
|
|
200
|
+
})));
|
|
201
|
+
const result = await capture.finish(config.outDir, mainOutDir, mirrors.map((relation) => path.resolve(config.cwd, relation.miniprogramNpmDistDir, npmDirName)));
|
|
202
|
+
if (result.external.size && config.inlineConfig.build?.write === false) throw new Error("[weapp-vite] build.write=false 无法表示宿主输出目录之外的 npm 产物;请使用 write=true 或将 npm 输出映射到宿主 outDir 内。");
|
|
203
|
+
return result;
|
|
204
|
+
} finally {
|
|
205
|
+
await rm(temporaryRoot, {
|
|
206
|
+
recursive: true,
|
|
207
|
+
force: true
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
//#endregion
|
|
212
|
+
//#region src/vite/npm/publish.ts
|
|
213
|
+
/** 手工映射到主目录外的依赖仍由宿主配套引擎写出,只清理上轮实际拥有的文件。 */
|
|
214
|
+
async function publishNpmAssets(outDir, assets, obsolete) {
|
|
215
|
+
const virtualEntry = "\0weapp-vite-npm-output";
|
|
216
|
+
const plugin = {
|
|
217
|
+
name: "weapp-vite:npm-output-writer",
|
|
218
|
+
resolveId: (id) => id === virtualEntry ? id : void 0,
|
|
219
|
+
load: (id) => id === virtualEntry ? "export {}" : void 0,
|
|
220
|
+
buildStart() {
|
|
221
|
+
for (const asset of assets) this.emitFile(asset);
|
|
222
|
+
},
|
|
223
|
+
generateBundle(_options, bundle) {
|
|
224
|
+
for (const [fileName, item] of Object.entries(bundle)) if (item.type === "chunk" && item.facadeModuleId === virtualEntry) delete bundle[fileName];
|
|
225
|
+
},
|
|
226
|
+
async writeBundle() {
|
|
227
|
+
await pruneOwnedAssetFiles(outDir, obsolete);
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
const { rolldown } = await loadHostRolldownBuild();
|
|
231
|
+
const bundle = await rolldown({
|
|
232
|
+
input: virtualEntry,
|
|
233
|
+
logLevel: "silent",
|
|
234
|
+
plugins: [plugin]
|
|
235
|
+
});
|
|
236
|
+
try {
|
|
237
|
+
await bundle.write({
|
|
238
|
+
dir: outDir,
|
|
239
|
+
format: "es"
|
|
240
|
+
});
|
|
241
|
+
} finally {
|
|
242
|
+
await bundle.close();
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
//#endregion
|
|
246
|
+
//#region src/vite/npm/ownership.ts
|
|
247
|
+
async function readOwnership(fileName) {
|
|
248
|
+
let value;
|
|
249
|
+
try {
|
|
250
|
+
value = JSON.parse(await readFile(fileName, "utf8"));
|
|
251
|
+
} catch (error) {
|
|
252
|
+
if (error.code === "ENOENT") return /* @__PURE__ */ new Map();
|
|
253
|
+
throw error;
|
|
254
|
+
}
|
|
255
|
+
if (!Array.isArray(value) || !value.every((entry) => Array.isArray(entry) && entry.length === 2 && typeof entry[0] === "string" && Array.isArray(entry[1]) && entry[1].every((file) => typeof file === "string"))) throw new Error("[weapp-vite] npm 输出归属记录损坏,请移除 .weapp-vite/native-npm-output 后重建。");
|
|
256
|
+
return new Map(value);
|
|
257
|
+
}
|
|
258
|
+
/** 保存外部产物的实际归属,使独立 build 也能删除旧依赖而保留非构建文件。 */
|
|
259
|
+
async function publishOwnedNpmAssets(cwd, hostOutDir, external) {
|
|
260
|
+
const key = createHash("sha256").update(hostOutDir).digest("hex").slice(0, 20);
|
|
261
|
+
const metadataRoot = path.join(cwd, ".weapp-vite/native-npm-output");
|
|
262
|
+
const metadataName = `${key}.json`;
|
|
263
|
+
const previous = await readOwnership(path.join(metadataRoot, metadataName));
|
|
264
|
+
const current = /* @__PURE__ */ new Map();
|
|
265
|
+
const currentFiles = /* @__PURE__ */ new Set();
|
|
266
|
+
for (const [directory, assets] of external) if (assets.length) {
|
|
267
|
+
const names = assets.map((asset) => asset.fileName);
|
|
268
|
+
current.set(directory, names);
|
|
269
|
+
for (const file of names) currentFiles.add(path.resolve(directory, file));
|
|
270
|
+
}
|
|
271
|
+
for (const directory of /* @__PURE__ */ new Set([...external.keys(), ...previous.keys()])) await publishNpmAssets(directory, external.get(directory) ?? [], (previous.get(directory) ?? []).filter((file) => !currentFiles.has(path.resolve(directory, file))));
|
|
272
|
+
if (current.size || previous.size) await publishNpmAssets(metadataRoot, [{
|
|
273
|
+
type: "asset",
|
|
274
|
+
fileName: metadataName,
|
|
275
|
+
source: JSON.stringify([...current])
|
|
276
|
+
}], []);
|
|
277
|
+
}
|
|
278
|
+
//#endregion
|
|
279
|
+
//#region src/vite/session.ts
|
|
280
|
+
/** 标准插件的目标校验和依赖准备,共享底层编译会话生命周期。 */
|
|
281
|
+
var WeappBuildSession = class extends CompilerSession {
|
|
282
|
+
dependencyBuild;
|
|
283
|
+
validating;
|
|
284
|
+
isWeb = false;
|
|
285
|
+
statefulController;
|
|
286
|
+
async prepare(config, cwd, mode, isDev = false) {
|
|
287
|
+
if (!config.resolve?.preserveSymlinks) try {
|
|
288
|
+
cwd = resolveRealpath(cwd);
|
|
289
|
+
} catch {}
|
|
290
|
+
this.isWeb = config.weapp?.platform === "web";
|
|
291
|
+
await this.initialize({
|
|
292
|
+
cwd,
|
|
293
|
+
mode,
|
|
294
|
+
isDev,
|
|
295
|
+
emitDefaultAutoImportOutputs: false,
|
|
296
|
+
hostConfig: { config: {
|
|
297
|
+
...config,
|
|
298
|
+
root: cwd
|
|
299
|
+
} },
|
|
300
|
+
cliPlatform: this.isWeb ? "web" : void 0,
|
|
301
|
+
syncSupportFiles: false,
|
|
302
|
+
preloadAppEntry: false
|
|
303
|
+
});
|
|
304
|
+
const service = this.context.configService;
|
|
305
|
+
if (this.isWeb) {
|
|
306
|
+
const merged = service.mergeWeb();
|
|
307
|
+
if (!merged) throw new Error("[weapp-vite] Web 目标不能禁用 weapp.web。");
|
|
308
|
+
return merged;
|
|
309
|
+
}
|
|
310
|
+
if (isDev && resolveHmrRuntimeDecision({
|
|
311
|
+
platform: service.platform,
|
|
312
|
+
configured: service.weappViteConfig.hmr?.runtime,
|
|
313
|
+
compileHotReLoad: service.projectPrivateConfig.setting?.compileHotReLoad
|
|
314
|
+
}).runtime === "stateful-experimental") {
|
|
315
|
+
if (service.platform !== "weapp") throw new Error("[weapp-vite] stateful-experimental 仅支持微信;其他平台请配置 hmr.runtime=classic。");
|
|
316
|
+
this.statefulController = createStatefulHmrHostPlugins(this.context);
|
|
317
|
+
}
|
|
318
|
+
return this.context.configService.merge(void 0, createSharedBuildConfig(this.context.configService, this.context.scanService));
|
|
319
|
+
}
|
|
320
|
+
validateEntries() {
|
|
321
|
+
if (this.validating && !this.isClosing) return this.validating;
|
|
322
|
+
if (this.state !== "ready" && this.state !== "building") return Promise.reject(/* @__PURE__ */ new Error(`[weapp-vite] 无法从 ${this.state} 状态开始构建。`));
|
|
323
|
+
this.dependencyBuild = void 0;
|
|
324
|
+
return this.validating = this.run(async () => {
|
|
325
|
+
if (!this.isWeb && !this.context.configService.weappLibConfig?.enabled) {
|
|
326
|
+
const app = await this.context.scanService.loadAppEntry();
|
|
327
|
+
checkAppWorkersOptions("app", this.context.configService, app);
|
|
328
|
+
}
|
|
329
|
+
if (this.isClosing) throw new Error("[weapp-vite] 构建会话已关闭。");
|
|
330
|
+
await syncManagedTsconfigFiles(this.context);
|
|
331
|
+
if (this.isClosing) throw new Error("[weapp-vite] 构建会话已关闭。");
|
|
332
|
+
this.state = "building";
|
|
333
|
+
}).finally(() => {
|
|
334
|
+
this.validating = void 0;
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
async startDev(server) {
|
|
338
|
+
if (this.isWeb) {
|
|
339
|
+
await this.run(() => syncManagedTsconfigFiles(this.context));
|
|
340
|
+
this.state = "watching";
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
let started = false;
|
|
344
|
+
let successful = false;
|
|
345
|
+
let reportedReady = false;
|
|
346
|
+
const reportReady = () => {
|
|
347
|
+
if (started && successful && !reportedReady && !this.isClosing) {
|
|
348
|
+
reportedReady = true;
|
|
349
|
+
server.config.logger.info(`[weapp-vite] 小程序开发产物已就绪 (${this.statefulController ? "stateful-experimental" : "classic"})`);
|
|
350
|
+
}
|
|
351
|
+
};
|
|
352
|
+
if (this.statefulController) this.onClose(attachStatefulHmrHost(this.context, {
|
|
353
|
+
server,
|
|
354
|
+
controller: this.statefulController
|
|
355
|
+
}));
|
|
356
|
+
this.onClose(attachDevModuleGraphHost(this.context, server, (result) => {
|
|
357
|
+
successful = result;
|
|
358
|
+
reportReady();
|
|
359
|
+
}));
|
|
360
|
+
this.onClose(() => this.context.watcherService.closeAll());
|
|
361
|
+
await this.validateEntries();
|
|
362
|
+
await this.run(() => this.context.buildService.build({}));
|
|
363
|
+
if (!this.isClosing) {
|
|
364
|
+
this.state = "watching";
|
|
365
|
+
if (this.statefulController) successful = true;
|
|
366
|
+
started = true;
|
|
367
|
+
reportReady();
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
async refreshHostControl() {
|
|
371
|
+
await getStatefulHmrHost(this.context)?.refreshControl?.();
|
|
372
|
+
}
|
|
373
|
+
buildDependencies() {
|
|
374
|
+
if (this.isWeb) return Promise.resolve({
|
|
375
|
+
assets: [],
|
|
376
|
+
external: /* @__PURE__ */ new Map(),
|
|
377
|
+
watchFiles: []
|
|
378
|
+
});
|
|
379
|
+
if (this.state !== "building") throw new Error("[weapp-vite] 依赖构建需要活动的构建会话。");
|
|
380
|
+
return this.dependencyBuild ??= this.run(() => prepareNpmAssets(this.context));
|
|
381
|
+
}
|
|
382
|
+
async publishDependencies() {
|
|
383
|
+
if (!this.dependencyBuild) return;
|
|
384
|
+
const { external } = await this.dependencyBuild;
|
|
385
|
+
const { cwd, outDir } = this.context.configService;
|
|
386
|
+
await this.run(() => publishOwnedNpmAssets(cwd, outDir, external));
|
|
387
|
+
}
|
|
388
|
+
};
|
|
389
|
+
//#endregion
|
|
390
|
+
export { WeappBuildSession };
|
package/dist/test.d.mts
CHANGED
|
@@ -22,6 +22,7 @@ export interface WeappViteTestArtifactWatcher {
|
|
|
22
22
|
close: () => Promise<void>;
|
|
23
23
|
rebuild: () => Promise<WeappViteTestArtifact>;
|
|
24
24
|
}
|
|
25
|
+
export declare function isTestArtifactCurrent(artifact: WeappViteTestArtifact): Promise<boolean>;
|
|
25
26
|
export declare function buildTestArtifact(options?: BuildTestArtifactOptions): Promise<{
|
|
26
27
|
appConfigPath: string;
|
|
27
28
|
miniprogramRootPath: string;
|
package/dist/test.mjs
CHANGED
|
@@ -1,82 +1,239 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
1
|
+
import { g as captureWatchDependencies, u as CompilerSession } from "./createCompilerContextInstance-DJH_P_nZ.mjs";
|
|
2
|
+
import { a as parseSidecarModuleId, i as parseLogicalEntryId } from "./protocol-vg8HGJ4n.mjs";
|
|
3
3
|
import process from "node:process";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import fs from "node:fs/promises";
|
|
6
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
4
7
|
import chokidar from "chokidar";
|
|
8
|
+
//#region src/testArtifact/inputs.ts
|
|
9
|
+
const sessionId = randomUUID();
|
|
10
|
+
const excludedDirectories = /* @__PURE__ */ new Set([
|
|
11
|
+
".git",
|
|
12
|
+
".weapp-vite",
|
|
13
|
+
"node_modules"
|
|
14
|
+
]);
|
|
15
|
+
function resolveArtifactOutDir(cwd, options, generation = randomUUID()) {
|
|
16
|
+
if (options.outDir) return path.resolve(cwd, options.outDir);
|
|
17
|
+
const key = createHash("sha256").update(JSON.stringify({
|
|
18
|
+
configFile: options.configFile && path.resolve(cwd, options.configFile),
|
|
19
|
+
mode: options.mode ?? "test",
|
|
20
|
+
projectConfigPath: options.projectConfigPath && path.resolve(cwd, options.projectConfigPath),
|
|
21
|
+
skipNpm: options.skipNpm ?? false
|
|
22
|
+
})).digest("hex").slice(0, 16);
|
|
23
|
+
return path.join(cwd, ".weapp-vite/test-artifacts", `${process.pid}-${sessionId}`, key, generation);
|
|
24
|
+
}
|
|
25
|
+
function projectInputFiles(cwd) {
|
|
26
|
+
return [
|
|
27
|
+
...[
|
|
28
|
+
"vite.config",
|
|
29
|
+
"weapp-vite.config",
|
|
30
|
+
"vitest.config"
|
|
31
|
+
].flatMap((name) => [
|
|
32
|
+
"ts",
|
|
33
|
+
"mts",
|
|
34
|
+
"cts",
|
|
35
|
+
"js",
|
|
36
|
+
"mjs",
|
|
37
|
+
"cjs"
|
|
38
|
+
].map((ext) => `${name}.${ext}`)),
|
|
39
|
+
"package.json",
|
|
40
|
+
"pnpm-lock.yaml",
|
|
41
|
+
"package-lock.json",
|
|
42
|
+
"yarn.lock",
|
|
43
|
+
"tsconfig.json",
|
|
44
|
+
"project.config.json"
|
|
45
|
+
].map((file) => path.join(cwd, file));
|
|
46
|
+
}
|
|
47
|
+
/** 对真实输入及目录成员取内容摘要,覆盖同长度改写、新增路由和删除文件。 */
|
|
48
|
+
async function fingerprintPaths(paths, excluded = []) {
|
|
49
|
+
const hash = createHash("sha256");
|
|
50
|
+
const visited = /* @__PURE__ */ new Set();
|
|
51
|
+
const ignored = excluded.map((file) => path.resolve(file));
|
|
52
|
+
const visit = async (file) => {
|
|
53
|
+
if (ignored.some((root) => file === root || file.startsWith(`${root}${path.sep}`))) return;
|
|
54
|
+
hash.update(`${file}\0`);
|
|
55
|
+
try {
|
|
56
|
+
if ((await fs.stat(file)).isDirectory()) {
|
|
57
|
+
const real = await fs.realpath(file);
|
|
58
|
+
if (visited.has(real)) return;
|
|
59
|
+
visited.add(real);
|
|
60
|
+
const entries = await fs.readdir(file, { withFileTypes: true });
|
|
61
|
+
for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) if (!excludedDirectories.has(entry.name)) await visit(path.join(file, entry.name));
|
|
62
|
+
} else hash.update(await fs.readFile(file));
|
|
63
|
+
} catch (error) {
|
|
64
|
+
if (error.code !== "ENOENT") throw error;
|
|
65
|
+
hash.update("missing");
|
|
66
|
+
}
|
|
67
|
+
hash.update("\0");
|
|
68
|
+
};
|
|
69
|
+
for (const file of [...new Set(paths)].sort()) await visit(path.resolve(file));
|
|
70
|
+
return hash.digest("hex");
|
|
71
|
+
}
|
|
72
|
+
//#endregion
|
|
5
73
|
//#region src/testArtifact.ts
|
|
6
74
|
let pendingBuild = Promise.resolve();
|
|
75
|
+
const artifactInputs = /* @__PURE__ */ new WeakMap();
|
|
7
76
|
function enqueueBuild(task) {
|
|
8
77
|
const result = pendingBuild.then(task, task);
|
|
9
78
|
pendingBuild = result.then(() => void 0, () => void 0);
|
|
10
79
|
return result;
|
|
11
80
|
}
|
|
12
|
-
function
|
|
13
|
-
|
|
81
|
+
async function isTestArtifactCurrent(artifact) {
|
|
82
|
+
const inputs = artifactInputs.get(artifact);
|
|
83
|
+
return inputs !== void 0 && inputs.fingerprint === await fingerprintPaths(inputs.paths);
|
|
14
84
|
}
|
|
15
85
|
async function buildTestArtifact(options = {}) {
|
|
16
86
|
return await enqueueBuild(async () => {
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
87
|
+
const session = new CompilerSession();
|
|
88
|
+
try {
|
|
89
|
+
const cwd = path.resolve(options.cwd ?? process.cwd());
|
|
90
|
+
const outDir = resolveArtifactOutDir(cwd, options);
|
|
91
|
+
const dependencies = new Set(projectInputFiles(cwd));
|
|
92
|
+
const discoveredInputs = /* @__PURE__ */ new Map();
|
|
93
|
+
const inlineConfig = {
|
|
94
|
+
plugins: [captureWatchDependencies((file) => {
|
|
95
|
+
dependencies.add(file);
|
|
96
|
+
if (!discoveredInputs.has(file)) discoveredInputs.set(file, fingerprintPaths([file]));
|
|
97
|
+
}), {
|
|
98
|
+
name: "weapp-vite:test-artifact-inputs",
|
|
99
|
+
generateBundle() {
|
|
100
|
+
for (const file of this.getModuleIds()) {
|
|
101
|
+
const clean = (parseLogicalEntryId(file)?.sourceId ?? parseSidecarModuleId(file)?.ownerId ?? file).split("?")[0];
|
|
102
|
+
if (path.isAbsolute(clean)) {
|
|
103
|
+
dependencies.add(clean);
|
|
104
|
+
for (const dependency of session.context.moduleGraphService.getTransformDependencies(clean)) dependencies.add(dependency);
|
|
105
|
+
for (const dependency of session.context.moduleGraphService.getEntryDependencies(clean)) dependencies.add(dependency.sourceId);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}],
|
|
110
|
+
build: {
|
|
111
|
+
emptyOutDir: true,
|
|
112
|
+
outDir
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
const ctx = await session.initialize({
|
|
116
|
+
cwd,
|
|
117
|
+
mode: options.mode ?? "test",
|
|
118
|
+
isDev: false,
|
|
119
|
+
configFile: options.configFile,
|
|
120
|
+
inlineConfig,
|
|
121
|
+
outputRoot: outDir,
|
|
122
|
+
projectConfigPath: options.projectConfigPath,
|
|
123
|
+
emitDefaultAutoImportOutputs: false,
|
|
124
|
+
preloadAppEntry: false,
|
|
125
|
+
syncSupportFiles: false
|
|
126
|
+
});
|
|
127
|
+
for (const file of ctx.configService.configFileDependencies ?? []) dependencies.add(file);
|
|
128
|
+
if (options.projectConfigPath) dependencies.add(path.resolve(cwd, options.projectConfigPath));
|
|
129
|
+
dependencies.add(ctx.configService.absoluteSrcRoot);
|
|
130
|
+
const initialInputs = [...dependencies];
|
|
131
|
+
const before = await fingerprintPaths(initialInputs, [outDir]);
|
|
132
|
+
await session.run(() => ctx.buildService.build({ skipNpm: options.skipNpm }));
|
|
133
|
+
const artifact = {
|
|
134
|
+
appConfigPath: path.join(ctx.configService.outDir, "app.json"),
|
|
135
|
+
miniprogramRootPath: ctx.configService.outDir,
|
|
136
|
+
projectPath: cwd,
|
|
137
|
+
sourceRootPath: ctx.configService.absoluteSrcRoot
|
|
138
|
+
};
|
|
139
|
+
const paths = [...dependencies, outDir];
|
|
140
|
+
const stable = (await Promise.all([...discoveredInputs].map(async ([file, fingerprint]) => await fingerprint === await fingerprintPaths([file])))).every(Boolean) && before === await fingerprintPaths(initialInputs, [outDir]);
|
|
141
|
+
artifactInputs.set(artifact, {
|
|
142
|
+
paths,
|
|
143
|
+
fingerprint: stable ? await fingerprintPaths(paths) : ""
|
|
144
|
+
});
|
|
145
|
+
return artifact;
|
|
146
|
+
} finally {
|
|
147
|
+
await session.close();
|
|
148
|
+
}
|
|
42
149
|
});
|
|
43
150
|
}
|
|
44
151
|
async function watchTestArtifact(options = {}) {
|
|
45
152
|
let artifact = await buildTestArtifact(options);
|
|
46
153
|
let closed = false;
|
|
47
154
|
let scheduled;
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
155
|
+
let active;
|
|
156
|
+
let dirty = false;
|
|
157
|
+
let forced = false;
|
|
158
|
+
let closing;
|
|
159
|
+
const watchedInputs = () => artifactInputs.get(artifact).paths.filter((file) => file !== artifact.miniprogramRootPath && (file === artifact.sourceRootPath || !file.startsWith(`${artifact.sourceRootPath}${path.sep}`)));
|
|
160
|
+
let watched = watchedInputs();
|
|
161
|
+
const watcher = chokidar.watch(watched, {
|
|
162
|
+
ignoreInitial: true,
|
|
163
|
+
ignored(file) {
|
|
164
|
+
if (watched.some((input) => input === file || input.startsWith(`${file}${path.sep}`))) return false;
|
|
165
|
+
return /[/\\](?:node_modules|\.git|\.weapp-vite)(?:[/\\]|$)/.test(file) || file === artifact.miniprogramRootPath || file.startsWith(`${artifact.miniprogramRootPath}${path.sep}`);
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
const requestRebuild = (force) => {
|
|
169
|
+
if (closed) return Promise.reject(/* @__PURE__ */ new Error("The weapp-vite test artifact watcher has already closed."));
|
|
170
|
+
dirty = true;
|
|
171
|
+
forced ||= force;
|
|
172
|
+
if (!active) active = (async () => {
|
|
173
|
+
do {
|
|
174
|
+
dirty = false;
|
|
175
|
+
const forceBuild = forced;
|
|
176
|
+
forced = false;
|
|
177
|
+
if (!forceBuild && await isTestArtifactCurrent(artifact)) continue;
|
|
178
|
+
if (closed) break;
|
|
179
|
+
artifact = await buildTestArtifact(options);
|
|
180
|
+
if (!closed) {
|
|
181
|
+
const next = watchedInputs();
|
|
182
|
+
await watcher.unwatch(watched.filter((file) => !next.includes(file)));
|
|
183
|
+
watched = next;
|
|
184
|
+
watcher.add(watched);
|
|
185
|
+
await options.onRebuilt?.(artifact);
|
|
186
|
+
}
|
|
187
|
+
if (closed) break;
|
|
188
|
+
} while (dirty);
|
|
189
|
+
return artifact;
|
|
190
|
+
})().finally(() => {
|
|
191
|
+
active = void 0;
|
|
192
|
+
});
|
|
193
|
+
return active;
|
|
53
194
|
};
|
|
54
195
|
const scheduleRebuild = () => {
|
|
55
196
|
if (closed || scheduled) return;
|
|
56
197
|
scheduled = setTimeout(() => {
|
|
57
198
|
scheduled = void 0;
|
|
58
|
-
|
|
199
|
+
requestRebuild(false).catch((error) => {
|
|
200
|
+
if (!closed) options.onError?.(error);
|
|
201
|
+
});
|
|
59
202
|
}, 20);
|
|
60
203
|
};
|
|
61
|
-
const watcher = chokidar.watch(artifact.sourceRootPath, {
|
|
62
|
-
ignoreInitial: true,
|
|
63
|
-
ignored: [artifact.miniprogramRootPath]
|
|
64
|
-
});
|
|
65
204
|
watcher.on("add", scheduleRebuild);
|
|
66
205
|
watcher.on("change", scheduleRebuild);
|
|
67
206
|
watcher.on("unlink", scheduleRebuild);
|
|
207
|
+
watcher.on("error", (error) => options.onError?.(error));
|
|
208
|
+
try {
|
|
209
|
+
await new Promise((resolve, reject) => {
|
|
210
|
+
watcher.once("ready", resolve);
|
|
211
|
+
watcher.once("error", reject);
|
|
212
|
+
});
|
|
213
|
+
if (!await isTestArtifactCurrent(artifact)) await requestRebuild(false);
|
|
214
|
+
} catch (error) {
|
|
215
|
+
closed = true;
|
|
216
|
+
if (scheduled) clearTimeout(scheduled);
|
|
217
|
+
await watcher.close();
|
|
218
|
+
await active?.catch(() => void 0);
|
|
219
|
+
throw error;
|
|
220
|
+
}
|
|
68
221
|
return {
|
|
69
222
|
get artifact() {
|
|
70
223
|
return artifact;
|
|
71
224
|
},
|
|
72
|
-
|
|
73
|
-
if (
|
|
225
|
+
close() {
|
|
226
|
+
if (closing) return closing;
|
|
74
227
|
closed = true;
|
|
75
228
|
if (scheduled) clearTimeout(scheduled);
|
|
76
|
-
|
|
229
|
+
closing = (async () => {
|
|
230
|
+
await watcher.close();
|
|
231
|
+
await active?.catch(() => void 0);
|
|
232
|
+
})();
|
|
233
|
+
return closing;
|
|
77
234
|
},
|
|
78
|
-
rebuild
|
|
235
|
+
rebuild: () => requestRebuild(true)
|
|
79
236
|
};
|
|
80
237
|
}
|
|
81
238
|
//#endregion
|
|
82
|
-
export { buildTestArtifact, watchTestArtifact };
|
|
239
|
+
export { buildTestArtifact, isTestArtifactCurrent, watchTestArtifact };
|