Skip to content

Commit 92339ae

Browse files
wan9chiclaude
andcommitted
refactor(vite-patch): inline IPC calls at each call site; use packageExtensions
Rework `patches/vite.patch` to match the shape of the eventual upstream Vite PR: - Drop the synthetic `vite:runner-aware` plugin. Each IPC call is now inlined right at the Vite code that triggers the fs / env access: - `ignoreInput(outDir)` in `prepareOutDir` before `emptyDir` scans it - `ignoreInput(depsCacheDir)` + `ignoreOutput(depsCacheDir)` in `loadCachedDepOptimizationMetadata` before the dep optimizer cache is read / written - `fetchEnv("NODE_ENV", { tracked: true })` in `resolveConfig` before `process.env.NODE_ENV` is first consulted - `ignoreInput`/`ignoreOutput` of `.vite-temp/` in `loadConfigFromBundledFile` (bundled-config temp write+import) - Static `import` of `@voidzero-dev/vite-task-client` by name — the wrapper no-ops when no runner is connected, so no guard is needed at the call sites. - Add a `packageExtensions` entry in `pnpm-workspace.yaml` that injects the wrapper as a real dependency of Vite. The final upstream PR would instead declare it in `packages/vite/package.json`; the only delta between experiment and PR is that one line. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 0760234 commit 92339ae

3 files changed

Lines changed: 73 additions & 55 deletions

File tree

patches/vite.patch

Lines changed: 62 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,66 @@
11
diff --git a/dist/node/chunks/node.js b/dist/node/chunks/node.js
2-
index 5be94a01d8aecf2502e76c05087b207980f2b06d..f436a7d9aa32d126fc1888d3bf37a6af0aa10e3e 100644
2+
index 5be94a01d8aecf2502e76c05087b207980f2b06d..3cfee1b787d28dd84ab477316a9354da5d1411d1 100644
33
--- a/dist/node/chunks/node.js
44
+++ b/dist/node/chunks/node.js
5-
@@ -29706,6 +29706,43 @@ function esbuildBannerFooterCompatPlugin(config) {
6-
};
7-
}
8-
//#endregion
9-
+//#region vp:runner-aware-tools (patch)
10-
+// Injected by @voidzero-dev/vite-task-client integration: when Vite runs under
11-
+// `vp run`, report input/output directories and tracked envs to the runner so
12-
+// cache correctness works without manual input/output config.
13-
+let __vpRunnerAddon;
14-
+function __vpRunnerLoadAddon() {
15-
+ if (__vpRunnerAddon !== undefined) return __vpRunnerAddon;
16-
+ const addonPath = process.env.VP_RUN_NODE_CLIENT_PATH;
17-
+ if (!addonPath) return __vpRunnerAddon = null;
18-
+ try {
19-
+ __vpRunnerAddon = createRequire(import.meta.url)(addonPath);
20-
+ } catch {
21-
+ __vpRunnerAddon = null;
22-
+ }
23-
+ return __vpRunnerAddon;
24-
+}
25-
+function vpRunnerAwarePlugin(config) {
26-
+ return {
27-
+ name: "vp:runner-aware",
28-
+ buildStart() {
29-
+ const addon = __vpRunnerLoadAddon();
30-
+ if (!addon) return;
31-
+ const outDir = config.build && config.build.outDir;
32-
+ if (outDir) addon.ignoreInput(outDir);
33-
+ // node_modules holds installed deps plus Vite's own caches
34-
+ // (`.vite`, `.vite-temp`). Everything under it is machine state
35-
+ // rather than user-authored input/output; the task's real fingerprint
36-
+ // comes from sources + the lockfile, tracked separately.
37-
+ const nodeModules = (config.root || process.cwd()) + "/node_modules";
38-
+ addon.ignoreInput(nodeModules);
39-
+ addon.ignoreOutput(nodeModules);
40-
+ // NODE_ENV drives dead-code elimination and `import.meta.env.MODE`.
41-
+ addon.getEnv("NODE_ENV", true);
5+
@@ -1,6 +1,10 @@
6+
import { a as __toCommonJS, i as __require, n as __esmMin, o as __toESM, r as __exportAll, t as __commonJSMin } from "./chunk.js";
7+
import { A as OPTIMIZABLE_ENTRY_RE, C as ERR_FILE_NOT_FOUND_IN_OPTIMIZED_DEP_DIR, D as JS_TYPES_RE, E as FS_PREFIX, F as defaultAllowedOrigins, I as loopbackHosts, L as wildcardHosts, M as SPECIAL_QUERY_RE, N as VERSION, O as KNOWN_ASSET_TYPES, P as VITE_PACKAGE_DIR, R as require_picocolors, S as ENV_PUBLIC_PATH, T as ESBUILD_BASELINE_WIDELY_AVAILABLE_TARGET, _ as DEFAULT_SERVER_CONDITIONS, a as CLIENT_ENTRY, b as DEV_PROD_CONDITION, c as DEFAULT_ASSETS_INLINE_LIMIT, d as DEFAULT_CLIENT_MAIN_FIELDS, f as DEFAULT_CONFIG_FILES, g as DEFAULT_PREVIEW_PORT, h as DEFAULT_EXTERNAL_CONDITIONS, i as CLIENT_DIR, j as ROLLUP_HOOKS, k as METADATA_FILENAME, l as DEFAULT_ASSETS_RE, m as DEFAULT_EXTENSIONS, n as createLogger, o as CLIENT_PUBLIC_PATH, p as DEFAULT_DEV_PORT, r as printServerUrls, s as CSS_LANGS_RE, t as LogLevels, u as DEFAULT_CLIENT_CONDITIONS, v as DEFAULT_SERVER_MAIN_FIELDS, w as ERR_OPTIMIZE_DEPS_PROCESSING_ERROR, x as ENV_ENTRY, y as DEP_VERSION_RE } from "./logger.js";
8+
import { builtinModules, createRequire } from "node:module";
9+
+// vp:runner-aware-tools — report inputs/outputs/tracked envs to the runner so
10+
+// that caching of `vite build` works without manual input/output config.
11+
+// No-op when `@voidzero-dev/vite-task-client` is not connected to a runner.
12+
+import { ignoreInput, ignoreOutput, fetchEnv } from "@voidzero-dev/vite-task-client";
13+
import { parseAst, parseAstAsync } from "rolldown/parseAst";
14+
import { esmExternalRequirePlugin, esmExternalRequirePlugin as esmExternalRequirePlugin$1 } from "rolldown/plugins";
15+
import { TsconfigCache, Visitor, minify, minifySync, parse, parseSync, transformSync } from "rolldown/utils";
16+
@@ -31322,6 +31326,12 @@ async function loadCachedDepOptimizationMetadata(environment, force = environmen
17+
setTimeout(() => cleanupDepsCacheStaleDirs(environment.getTopLevelConfig()), 0).unref();
18+
}
19+
const depsCacheDir = getDepsCacheDir(environment);
20+
+ // vp:runner-aware-tools — the dep optimizer cache is read and written
21+
+ // under the same directory (metadata, pre-bundled deps). Tell the runner
22+
+ // to treat the directory as neither input nor output; the lockfile hash
23+
+ // stored in the metadata already drives invalidation of the real inputs.
24+
+ ignoreInput(depsCacheDir);
25+
+ ignoreOutput(depsCacheDir);
26+
if (!force) {
27+
let cachedMetadata;
28+
try {
29+
@@ -32706,6 +32716,10 @@ function prepareOutDir(outDirs, emptyOutDir, environment) {
30+
const { publicDir } = environment.config;
31+
const outDirsArray = [...outDirs];
32+
for (const outDir of outDirs) {
33+
+ // vp:runner-aware-tools — emptyDir() below reads the entries of outDir.
34+
+ // Without ignoring it, those reads become inferred inputs and mix with
35+
+ // the writes that follow, tripping the runner's read-write overlap check.
36+
+ ignoreInput(outDir);
37+
if (emptyOutDir !== false && fs.existsSync(outDir)) emptyDir(outDir, [...outDirsArray.map((dir) => {
38+
const relative = path.relative(outDir, dir);
39+
if (relative && !relative.startsWith("..") && !path.isAbsolute(relative)) return relative;
40+
@@ -34120,6 +34134,10 @@ async function resolveConfig(inlineConfig, command, defaultMode = "development",
41+
}
42+
let configFileDependencies = [];
43+
let mode = inlineConfig.mode || defaultMode;
44+
+ // vp:runner-aware-tools — NODE_ENV drives dead-code elimination, define
45+
+ // replacements, and `import.meta.env.MODE`; fingerprint it as a tracked
46+
+ // env so cache invalidation follows the value used at build time.
47+
+ fetchEnv("NODE_ENV", { tracked: true });
48+
const isNodeEnvSet = !!process.env.NODE_ENV;
49+
const packageCache = /* @__PURE__ */ new Map();
50+
if (!isNodeEnvSet) process.env.NODE_ENV = defaultNodeEnv;
51+
@@ -34675,6 +34693,15 @@ async function loadConfigFromBundledFile(fileName, bundledCode, isESM) {
52+
if (e.code === "EACCES") nodeModulesDir = void 0;
53+
else throw e;
54+
}
55+
+ // vp:runner-aware-tools — the bundled config is written into
56+
+ // `.vite-temp/<basename>.<hash>.mjs` and then imported back. Ignore
57+
+ // the directory as both input and output so the read-write of this
58+
+ // transient file doesn't poison the runner's cache.
59+
+ if (nodeModulesDir) {
60+
+ const viteTempDir = path.resolve(nodeModulesDir, ".vite-temp");
61+
+ ignoreInput(viteTempDir);
62+
+ ignoreOutput(viteTempDir);
4263
+ }
43-
+ };
44-
+}
45-
+//#endregion
46-
//#region src/node/plugins/index.ts
47-
async function resolvePlugins(config, prePlugins, normalPlugins, postPlugins) {
48-
const isBuild = config.command === "build";
49-
@@ -29717,6 +29754,7 @@ async function resolvePlugins(config, prePlugins, normalPlugins, postPlugins) {
50-
};
51-
const { modulePreload } = config.build;
52-
return [
53-
+ vpRunnerAwarePlugin(config),
54-
!isBundled ? optimizedDepsPlugin() : null,
55-
!isWorker ? watchPackageDataPlugin(config.packageCache) : null,
56-
!isBundled ? preAliasPlugin(config) : null,
64+
const hash = `timestamp-${Date.now()}-${Math.random().toString(16).slice(2)}`;
65+
const tempFileName = nodeModulesDir ? path.resolve(nodeModulesDir, `.vite-temp/${path.basename(fileName)}.${hash}.mjs`) : `${fileName}.${hash}.mjs`;
66+
await fsp.writeFile(tempFileName, bundledCode);

pnpm-lock.yaml

Lines changed: 6 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pnpm-workspace.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,10 @@ catalog:
1414

1515
catalogMode: prefer
1616

17+
packageExtensions:
18+
vite:
19+
dependencies:
20+
'@voidzero-dev/vite-task-client': workspace:*
21+
1722
patchedDependencies:
1823
vite: patches/vite.patch

0 commit comments

Comments
 (0)