fix(plugins): share bundled public surface jiti cache scope

This commit is contained in:
Vincent Koc
2026-04-14 17:20:44 +01:00
parent 5c28cfbf09
commit 8fa63ac380
4 changed files with 85 additions and 11 deletions

View File

@@ -137,4 +137,48 @@ describe("getCachedPluginJitiLoader", () => {
}),
);
});
it("lets callers intentionally share loaders behind a custom cache scope key", async () => {
const createJiti = vi.fn((filename: string, options: Record<string, unknown>) =>
Object.assign(vi.fn(), {
filename,
options,
}),
);
vi.doMock("jiti", () => ({
createJiti,
}));
const { getCachedPluginJitiLoader } = await importFreshModule<
typeof import("./jiti-loader-cache.js")
>(import.meta.url, "./jiti-loader-cache.js?scope=cache-scope-key");
const cache = new Map();
const first = getCachedPluginJitiLoader({
cache,
modulePath: "/repo/dist/extensions/demo-a/api.js",
importerUrl: "file:///repo/src/plugins/public-surface-loader.ts",
jitiFilename: "file:///repo/src/plugins/public-surface-loader.ts",
aliasMap: {
demo: "/repo/demo-a.js",
},
tryNative: true,
cacheScopeKey: "bundled:native",
});
const second = getCachedPluginJitiLoader({
cache,
modulePath: "/repo/dist/extensions/demo-b/api.js",
importerUrl: "file:///repo/src/plugins/public-surface-loader.ts",
jitiFilename: "file:///repo/src/plugins/public-surface-loader.ts",
aliasMap: {
demo: "/repo/demo-b.js",
},
tryNative: true,
cacheScopeKey: "bundled:native",
});
expect(second).toBe(first);
expect(createJiti).toHaveBeenCalledTimes(1);
expect(cache.size).toBe(1);
});
});

View File

@@ -19,6 +19,7 @@ export function getCachedPluginJitiLoader(params: {
createLoader?: PluginJitiLoaderFactory;
aliasMap?: Record<string, string>;
tryNative?: boolean;
cacheScopeKey?: string;
}): PluginJitiLoader {
const defaultConfig =
params.aliasMap || typeof params.tryNative === "boolean"
@@ -45,7 +46,7 @@ export function getCachedPluginJitiLoader(params: {
tryNative,
aliasMap,
});
const scopedCacheKey = `${params.jitiFilename ?? params.modulePath}::${cacheKey}`;
const scopedCacheKey = `${params.jitiFilename ?? params.modulePath}::${params.cacheScopeKey ?? cacheKey}`;
const cached = params.cache.get(scopedCacheKey);
if (cached) {
return cached;

View File

@@ -105,4 +105,36 @@ describe("bundled plugin public surface loader", () => {
expect(requireLoader).toHaveBeenCalledWith(pathModule.resolve(modulePath));
expect(createJiti).not.toHaveBeenCalled();
});
it("reuses one bundled dist jiti loader across public artifacts with the same native mode", async () => {
const createJiti = vi.fn(() => vi.fn((modulePath: string) => ({ modulePath })));
vi.doMock("jiti", () => ({
createJiti,
}));
const publicSurfaceLoader = await importFreshModule<
typeof import("./public-surface-loader.js")
>(import.meta.url, "./public-surface-loader.js?scope=shared-bundled-jiti");
const tempRoot = createTempDir();
const bundledPluginsDir = path.join(tempRoot, "dist");
process.env.OPENCLAW_BUNDLED_PLUGINS_DIR = bundledPluginsDir;
const firstPath = path.join(bundledPluginsDir, "demo-a", "api.js");
const secondPath = path.join(bundledPluginsDir, "demo-b", "api.js");
fs.mkdirSync(path.dirname(firstPath), { recursive: true });
fs.mkdirSync(path.dirname(secondPath), { recursive: true });
fs.writeFileSync(firstPath, 'export const marker = "demo-a";\n', "utf8");
fs.writeFileSync(secondPath, 'export const marker = "demo-b";\n', "utf8");
publicSurfaceLoader.loadBundledPluginPublicArtifactModuleSync<{ modulePath: string }>({
dirName: "demo-a",
artifactBasename: "api.js",
});
publicSurfaceLoader.loadBundledPluginPublicArtifactModuleSync<{ modulePath: string }>({
dirName: "demo-b",
artifactBasename: "api.js",
});
expect(createJiti).toHaveBeenCalledTimes(1);
});
});

View File

@@ -2,14 +2,12 @@ import fs from "node:fs";
import { createRequire } from "node:module";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { createJiti } from "jiti";
import { openBoundaryFileSync } from "../infra/boundary-file-read.js";
import { resolveBundledPluginsDir } from "./bundled-dir.js";
import { getCachedPluginJitiLoader, type PluginJitiLoaderCache } from "./jiti-loader-cache.js";
import { resolveBundledPluginPublicSurfacePath } from "./public-surface-runtime.js";
import {
buildPluginLoaderAliasMap,
buildPluginLoaderJitiOptions,
isBundledPluginExtensionPath,
resolvePluginLoaderJitiConfig,
resolveLoaderPackageRoot,
@@ -141,17 +139,16 @@ function getSharedBundledPublicSurfaceJiti(modulePath: string, tryNative: boolea
return null;
}
const cacheKey = tryNative ? "bundled:native" : "bundled:source";
const cached = sharedBundledPublicSurfaceJitiLoaders.get(cacheKey);
if (cached) {
return cached;
}
const aliasMap = buildPluginLoaderAliasMap(modulePath, process.argv[1], import.meta.url);
const loader = createJiti(import.meta.url, {
...buildPluginLoaderJitiOptions(aliasMap),
return getCachedPluginJitiLoader({
cache: sharedBundledPublicSurfaceJitiLoaders,
modulePath,
importerUrl: import.meta.url,
jitiFilename: import.meta.url,
cacheScopeKey: cacheKey,
aliasMap,
tryNative,
});
sharedBundledPublicSurfaceJitiLoaders.set(cacheKey, loader);
return loader;
}
export function loadBundledPluginPublicArtifactModuleSync<T extends object>(params: {