perf: reduce jiti loader alias work

This commit is contained in:
Peter Steinberger
2026-04-20 18:03:24 +01:00
parent 254417a344
commit f76b426e2b
7 changed files with 143 additions and 32 deletions

View File

@@ -82,6 +82,13 @@ function applyVitestCapabilityAliasOverrides(params: {
};
}
function shouldApplyVitestCapabilityAliasOverrides(params: {
pluginSdkResolution?: PluginSdkResolutionPreference;
env?: PluginLoadOptions["env"];
}): boolean {
return Boolean(params.env?.VITEST && params.pluginSdkResolution === "dist");
}
export function buildBundledCapabilityRuntimeConfig(
pluginIds: readonly string[],
env?: PluginLoadOptions["env"],
@@ -193,22 +200,28 @@ export function loadBundledCapabilityRuntimeRegistry(params: {
const getJiti = (modulePath: string) => {
const tryNative =
shouldPreferNativeJiti(modulePath) && !(env?.VITEST && params.pluginSdkResolution === "dist");
const aliasMap = applyVitestCapabilityAliasOverrides({
aliasMap: buildPluginLoaderAliasMap(
modulePath,
process.argv[1],
import.meta.url,
params.pluginSdkResolution,
),
const aliasMap = shouldApplyVitestCapabilityAliasOverrides({
pluginSdkResolution: params.pluginSdkResolution,
env,
});
})
? applyVitestCapabilityAliasOverrides({
aliasMap: buildPluginLoaderAliasMap(
modulePath,
process.argv[1],
import.meta.url,
params.pluginSdkResolution,
),
pluginSdkResolution: params.pluginSdkResolution,
env,
})
: undefined;
return getCachedPluginJitiLoader({
cache: jitiLoaders,
modulePath,
importerUrl: import.meta.url,
jitiFilename: import.meta.url,
aliasMap,
...(aliasMap ? { aliasMap } : {}),
pluginSdkResolution: params.pluginSdkResolution,
tryNative,
});
};

View File

@@ -3,6 +3,7 @@ import {
buildPluginLoaderJitiOptions,
createPluginLoaderJitiCacheKey,
resolvePluginLoaderJitiConfig,
type PluginSdkResolutionPreference,
} from "./sdk-alias.js";
export type PluginJitiLoader = ReturnType<typeof createJiti>;
@@ -19,6 +20,7 @@ export function getCachedPluginJitiLoader(params: {
createLoader?: PluginJitiLoaderFactory;
aliasMap?: Record<string, string>;
tryNative?: boolean;
pluginSdkResolution?: PluginSdkResolutionPreference;
cacheScopeKey?: string;
}): PluginJitiLoader {
const jitiFilename = params.jitiFilename ?? params.modulePath;
@@ -38,23 +40,27 @@ export function getCachedPluginJitiLoader(params: {
argv1: params.argvEntry ?? process.argv[1],
moduleUrl: params.importerUrl,
...(params.preferBuiltDist ? { preferBuiltDist: true } : {}),
...(params.pluginSdkResolution
? { pluginSdkResolution: params.pluginSdkResolution }
: {}),
})
: null;
const canReuseDefaultCacheKey =
defaultConfig !== null &&
(!hasAliasOverride || params.aliasMap === defaultConfig.aliasMap) &&
(!hasTryNativeOverride || params.tryNative === defaultConfig.tryNative);
const resolved = defaultConfig
? {
tryNative: params.tryNative ?? defaultConfig.tryNative,
aliasMap: params.aliasMap ?? defaultConfig.aliasMap,
cacheKey:
!hasAliasOverride &&
(!hasTryNativeOverride || params.tryNative === defaultConfig.tryNative)
? defaultConfig.cacheKey
: undefined,
cacheKey: canReuseDefaultCacheKey ? defaultConfig.cacheKey : undefined,
}
: resolvePluginLoaderJitiConfig({
modulePath: params.modulePath,
argv1: params.argvEntry ?? process.argv[1],
moduleUrl: params.importerUrl,
...(params.preferBuiltDist ? { preferBuiltDist: true } : {}),
...(params.pluginSdkResolution ? { pluginSdkResolution: params.pluginSdkResolution } : {}),
});
const { tryNative, aliasMap } = resolved;
const cacheKey =

View File

@@ -454,18 +454,12 @@ function createPluginJitiLoader(options: Pick<PluginLoadOptions, "pluginSdkResol
const jitiLoaders: PluginJitiLoaderCache = new Map();
return (modulePath: string) => {
const tryNative = shouldPreferNativeJiti(modulePath);
const aliasMap = buildPluginLoaderAliasMap(
modulePath,
process.argv[1],
import.meta.url,
options.pluginSdkResolution,
);
return getCachedPluginJitiLoader({
cache: jitiLoaders,
modulePath,
importerUrl: import.meta.url,
jitiFilename: import.meta.url,
aliasMap,
pluginSdkResolution: options.pluginSdkResolution,
// Source .ts runtime shims import sibling ".js" specifiers that only exist
// after build. Disable native loading for source entries so Jiti rewrites
// those imports against the source graph, while keeping native dist/*.js

View File

@@ -7,7 +7,6 @@ import { resolveBundledPluginsDir } from "./bundled-dir.js";
import { getCachedPluginJitiLoader, type PluginJitiLoaderCache } from "./jiti-loader-cache.js";
import { resolveBundledPluginPublicSurfacePath } from "./public-surface-runtime.js";
import {
buildPluginLoaderAliasMap,
isBundledPluginExtensionPath,
resolvePluginLoaderJitiTryNative,
resolveLoaderPackageRoot,
@@ -129,14 +128,12 @@ function getSharedBundledPublicSurfaceJiti(modulePath: string, tryNative: boolea
return null;
}
const cacheKey = tryNative ? "bundled:native" : "bundled:source";
const aliasMap = buildPluginLoaderAliasMap(modulePath, process.argv[1], import.meta.url);
return getCachedPluginJitiLoader({
cache: sharedBundledPublicSurfaceJitiLoaders,
modulePath,
importerUrl: import.meta.url,
jitiFilename: import.meta.url,
cacheScopeKey: cacheKey,
aliasMap,
tryNative,
});
}

View File

@@ -3,7 +3,7 @@ import path from "node:path";
import { loadConfig } from "../../config/config.js";
import { getCachedPluginJitiLoader, type PluginJitiLoaderCache } from "../jiti-loader-cache.js";
import { loadPluginManifestRegistry } from "../manifest-registry.js";
import { buildPluginLoaderAliasMap, shouldPreferNativeJiti } from "../sdk-alias.js";
import { shouldPreferNativeJiti } from "../sdk-alias.js";
type PluginRuntimeRecord = {
origin?: string;
@@ -116,13 +116,11 @@ export function resolvePluginRuntimeModulePath(
export function getPluginBoundaryJiti(modulePath: string, loaders: PluginJitiLoaderCache) {
const tryNative = shouldPreferNativeJiti(modulePath);
const aliasMap = buildPluginLoaderAliasMap(modulePath);
return getCachedPluginJitiLoader({
cache: loaders,
modulePath,
importerUrl: import.meta.url,
jitiFilename: import.meta.url,
aliasMap,
tryNative,
});
}

View File

@@ -699,6 +699,35 @@ describe("plugin sdk alias helpers", () => {
});
});
it("falls back to source plugin-sdk subpath aliases when dist chunks are stale", () => {
const fixture = createPluginSdkAliasFixture({
srcFile: "provider-entry.ts",
distFile: "provider-entry.js",
distBody: 'import { entry } from "../missing-provider-entry-chunk.js";\nexport { entry };\n',
packageExports: {
"./plugin-sdk/provider-entry": { default: "./dist/plugin-sdk/provider-entry.js" },
},
});
const sourceProviderEntryPath = path.join(
fixture.root,
"src",
"plugin-sdk",
"provider-entry.ts",
);
const sourcePluginEntry = writePluginEntry(
fixture.root,
bundledPluginFile("demo", "src/index.ts"),
);
const distAliases = withEnv({ NODE_ENV: undefined }, () =>
buildPluginLoaderAliasMap(sourcePluginEntry, undefined, undefined, "dist"),
);
expect(fs.realpathSync(distAliases["openclaw/plugin-sdk/provider-entry"] ?? "")).toBe(
fs.realpathSync(sourceProviderEntryPath),
);
});
it("builds source plugin-sdk subpath aliases through the wider source extension family", () => {
const { fixture, sourceRootAlias, sourceChannelRuntimePath } =
createPluginSdkAliasTargetFixture({
@@ -939,7 +968,45 @@ describe("plugin sdk alias helpers", () => {
preferBuiltDist: true,
});
expect(second).toEqual(first);
expect(second).toBe(first);
});
it("scopes plugin loader Jiti config by plugin-sdk resolution", () => {
const { fixture, sourceRootAlias, distRootAlias } = createPluginSdkAliasTargetFixture();
const sourcePluginEntry = writePluginEntry(
fixture.root,
bundledPluginFile("demo", "src/index.ts"),
);
const { auto, dist, distAgain } = withEnv({ NODE_ENV: undefined }, () => ({
auto: resolvePluginLoaderJitiConfig({
modulePath: sourcePluginEntry,
argv1: path.join(fixture.root, "openclaw.mjs"),
moduleUrl: pathToFileURL(path.join(fixture.root, "src/plugins/loader.ts")).href,
pluginSdkResolution: "auto",
}),
dist: resolvePluginLoaderJitiConfig({
modulePath: sourcePluginEntry,
argv1: path.join(fixture.root, "openclaw.mjs"),
moduleUrl: pathToFileURL(path.join(fixture.root, "src/plugins/loader.ts")).href,
pluginSdkResolution: "dist",
}),
distAgain: resolvePluginLoaderJitiConfig({
modulePath: sourcePluginEntry,
argv1: path.join(fixture.root, "openclaw.mjs"),
moduleUrl: pathToFileURL(path.join(fixture.root, "src/plugins/loader.ts")).href,
pluginSdkResolution: "dist",
}),
}));
expect(distAgain).toBe(dist);
expect(auto).not.toBe(dist);
expect(fs.realpathSync(auto.aliasMap["openclaw/plugin-sdk"] ?? "")).toBe(
fs.realpathSync(sourceRootAlias),
);
expect(fs.realpathSync(dist.aliasMap["openclaw/plugin-sdk"] ?? "")).toBe(
fs.realpathSync(distRootAlias),
);
});
it("detects bundled plugin extension paths across source and dist roots", () => {

View File

@@ -260,6 +260,35 @@ const PLUGIN_SDK_SOURCE_CANDIDATE_EXTENSIONS = [
".cts",
".cjs",
] as const;
const JS_STATIC_RELATIVE_DEPENDENCY_PATTERN =
/(?:\bfrom\s*["']|\bimport\s*\(\s*["']|\brequire\s*\(\s*["'])(\.{1,2}\/[^"']+)["']/g;
function isUsableDistPluginSdkArtifact(candidate: string): boolean {
if (!fs.existsSync(candidate)) {
return false;
}
switch (normalizeLowercaseStringOrEmpty(path.extname(candidate))) {
case ".js":
case ".mjs":
case ".cjs":
break;
default:
return true;
}
try {
const source = fs.readFileSync(candidate, "utf-8");
for (const match of source.matchAll(JS_STATIC_RELATIVE_DEPENDENCY_PATTERN)) {
const specifier = match[1];
if (!specifier || fs.existsSync(path.resolve(path.dirname(candidate), specifier))) {
continue;
}
return false;
}
} catch {
return false;
}
return true;
}
function readPrivateLocalOnlyPluginSdkSubpaths(packageRoot: string): string[] {
try {
@@ -283,7 +312,7 @@ function shouldIncludePrivateLocalOnlyPluginSdkSubpaths() {
function hasPluginSdkSubpathArtifact(packageRoot: string, subpath: string) {
const distPath = path.join(packageRoot, "dist", "plugin-sdk", `${subpath}.js`);
if (fs.existsSync(distPath)) {
if (isUsableDistPluginSdkArtifact(distPath)) {
return true;
}
return PLUGIN_SDK_SOURCE_CANDIDATE_EXTENSIONS.some((ext) =>
@@ -369,7 +398,7 @@ export function resolvePluginSdkScopedAliasMap(
for (const kind of orderedKinds) {
if (kind === "dist") {
const candidate = path.join(packageRoot, "dist", "plugin-sdk", `${subpath}.js`);
if (fs.existsSync(candidate)) {
if (isUsableDistPluginSdkArtifact(candidate)) {
for (const packageName of PLUGIN_SDK_PACKAGE_NAMES) {
aliasMap[`${packageName}/${subpath}`] = candidate;
}
@@ -482,13 +511,14 @@ function buildPluginLoaderJitiConfigCacheKey(params: {
argv1?: string;
moduleUrl: string;
preferBuiltDist?: boolean;
pluginSdkResolution?: PluginSdkResolutionPreference;
}) {
return [
buildPluginLoaderAliasMapCacheKey({
modulePath: params.modulePath,
argv1: params.argv1,
moduleUrl: params.moduleUrl,
pluginSdkResolution: "auto",
pluginSdkResolution: params.pluginSdkResolution ?? "auto",
}),
params.preferBuiltDist === true ? "prefer-built-dist" : "default-dist",
].join("\0");
@@ -647,6 +677,7 @@ export function resolvePluginLoaderJitiConfig(params: {
argv1?: string;
moduleUrl: string;
preferBuiltDist?: boolean;
pluginSdkResolution?: PluginSdkResolutionPreference;
}): {
tryNative: boolean;
aliasMap: Record<string, string>;
@@ -662,7 +693,12 @@ export function resolvePluginLoaderJitiConfig(params: {
params.modulePath,
params.preferBuiltDist ? { preferBuiltDist: true } : {},
);
const aliasMap = buildPluginLoaderAliasMap(params.modulePath, params.argv1, params.moduleUrl);
const aliasMap = buildPluginLoaderAliasMap(
params.modulePath,
params.argv1,
params.moduleUrl,
params.pluginSdkResolution,
);
const result = {
tryNative,
aliasMap,