perf(plugins): cache runtime mirror file decisions

This commit is contained in:
Peter Steinberger
2026-04-28 23:36:59 +01:00
parent 6ce1058296
commit 75df09b9ec
5 changed files with 103 additions and 9 deletions

View File

@@ -25,6 +25,7 @@ import {
resolveBundledRuntimeDependencyInstallRootPlan,
resolveBundledRuntimeDepsNpmRunner,
scanBundledPluginRuntimeDeps,
shouldMaterializeBundledRuntimeMirrorDistFile,
type BundledRuntimeDepsInstallParams,
} from "./bundled-runtime-deps.js";
@@ -99,11 +100,42 @@ afterEach(() => {
spawnMock.mockReset();
spawnSyncMock.mockReset();
bundledRuntimeDepsActivityTesting.resetBundledRuntimeDepsInstallActivity();
bundledRuntimeDepsTesting.clearBundledRuntimeMirrorMaterializeCache();
for (const dir of tempDirs.splice(0)) {
fs.rmSync(dir, { recursive: true, force: true });
}
});
describe("shouldMaterializeBundledRuntimeMirrorDistFile", () => {
it("reuses unchanged root dist file decisions without rereading source", () => {
const root = makeTempDir();
const sourcePath = path.join(root, "shared-runtime.js");
fs.writeFileSync(
sourcePath,
[
`//#region extensions/browser/src/runtime.ts`,
`export const marker = "shared-runtime";`,
`//#endregion`,
"",
].join("\n"),
"utf8",
);
const realReadFileSync = fs.readFileSync.bind(fs);
let sourceReads = 0;
vi.spyOn(fs, "readFileSync").mockImplementation(((target, options) => {
if (path.resolve(target.toString()) === path.resolve(sourcePath)) {
sourceReads += 1;
}
return realReadFileSync(target, options as never);
}) as typeof fs.readFileSync);
expect(shouldMaterializeBundledRuntimeMirrorDistFile(sourcePath)).toBe(true);
expect(shouldMaterializeBundledRuntimeMirrorDistFile(sourcePath)).toBe(true);
expect(sourceReads).toBe(1);
});
});
describe("resolveBundledRuntimeDepsNpmRunner", () => {
it("ignores npm_execpath and uses the Node-adjacent npm CLI on Windows", () => {
const execPath = "C:\\Program Files\\nodejs\\node.exe";

View File

@@ -78,6 +78,10 @@ const BUNDLED_RUNTIME_MIRROR_IMPORT_SPECIFIER_RE =
const NPM_EXECPATH_ENV_KEY = "npm_execpath";
const registeredBundledRuntimeDepNodePaths = new Set<string>();
const bundledRuntimeMirrorMaterializeCache = new Map<
string,
{ signature: string; materialize: boolean }
>();
export type BundledRuntimeDepsNpmRunner = {
command: string;
@@ -85,10 +89,15 @@ export type BundledRuntimeDepsNpmRunner = {
env?: NodeJS.ProcessEnv;
};
export function shouldMaterializeBundledRuntimeMirrorDistFile(sourcePath: string): boolean {
if (!BUNDLED_RUNTIME_MIRROR_MATERIALIZED_EXTENSIONS.has(path.extname(sourcePath))) {
return false;
}
function clearBundledRuntimeMirrorMaterializeCache(): void {
bundledRuntimeMirrorMaterializeCache.clear();
}
function statSignature(stat: Pick<fs.Stats, "dev" | "ino" | "size" | "mtimeMs">): string {
return `${stat.dev}:${stat.ino}:${stat.size}:${stat.mtimeMs}`;
}
function computeBundledRuntimeMirrorDistFileMaterialization(sourcePath: string): boolean {
let source: string;
try {
source = fs.readFileSync(sourcePath, "utf8");
@@ -113,6 +122,27 @@ export function shouldMaterializeBundledRuntimeMirrorDistFile(sourcePath: string
return true;
}
export function shouldMaterializeBundledRuntimeMirrorDistFile(sourcePath: string): boolean {
if (!BUNDLED_RUNTIME_MIRROR_MATERIALIZED_EXTENSIONS.has(path.extname(sourcePath))) {
return false;
}
const cacheKey = path.resolve(sourcePath);
let signature: string;
try {
signature = statSignature(fs.statSync(sourcePath));
} catch {
bundledRuntimeMirrorMaterializeCache.delete(cacheKey);
return false;
}
const cached = bundledRuntimeMirrorMaterializeCache.get(cacheKey);
if (cached?.signature === signature) {
return cached.materialize;
}
const materialize = computeBundledRuntimeMirrorDistFileMaterialization(sourcePath);
bundledRuntimeMirrorMaterializeCache.set(cacheKey, { signature, materialize });
return materialize;
}
export function materializeBundledRuntimeMirrorDistFile(
sourcePath: string,
targetPath: string,
@@ -404,6 +434,7 @@ function formatRuntimeDepsLockTimeoutMessage(params: {
}
export const __testing = {
clearBundledRuntimeMirrorMaterializeCache,
formatRuntimeDepsLockTimeoutMessage,
shouldRemoveRuntimeDepsLock,
};