perf(cli): defer binary provider composition

This commit is contained in:
morluto
2026-10-11 11:07:15 +08:00
parent 76296c5a38
commit 21dbcf7a14
5 changed files with 77 additions and 18 deletions
+2 -2
View File
@@ -138,7 +138,7 @@ export const runManagedProviderExecution = async (
signal?: AbortSignal,
): Promise<Result<AnalysisExecution, AnalysisError>> =>
withProcessCancellation(signal, async (operationSignal) => {
const session = dependencies.createManagedBinarySession();
const session = await dependencies.createManagedBinarySession();
return withSessionCleanup(
session,
async () => {
@@ -194,7 +194,7 @@ const runAnalysis = async (
const { logger, signal, snapshotPath } = options;
const config = dependencies.readConfiguration();
if (!config.ok) return cliError(config.error);
const session = dependencies.createBinarySession(config.value, logger);
const session = await dependencies.createBinarySession(config.value, logger);
return withSessionCleanup(
session,
async () => {
@@ -10,6 +10,8 @@ export interface DirectAnalysisDependencies {
readonly createBinarySession: (
config: AppConfig,
logger: Logger,
) => BinarySession;
readonly createManagedBinarySession: () => BinarySession;
) => BinarySession | Promise<BinarySession>;
readonly createManagedBinarySession: () =>
| BinarySession
| Promise<BinarySession>;
}
+1 -1
View File
@@ -15,7 +15,7 @@ export const runSessionStatus = async (
): Promise<JsonValue> => {
const config = dependencies.readConfiguration();
if (!config.ok) return { error: projectAnalysisError(config.error) };
const session = dependencies.createBinarySession(config.value, logger);
const session = await dependencies.createBinarySession(config.value, logger);
try {
return {
...jsonObjectSchema.parse(session.status()),
+12 -5
View File
@@ -7,7 +7,6 @@ import {
} from "../application/DirectAnalysis.js";
import { runSessionStatus as executeSessionStatus } from "../application/DirectAnalysisStatus.js";
import type { DirectAnalysisDependencies } from "../application/DirectAnalysisDependencies.js";
import { createBinarySession, createManagedBinarySession } from "./binary.js";
/** Bind one-shot analysis and status commands to one caller-selected environment. */
export const createDirectAnalysis = (
@@ -16,9 +15,14 @@ export const createDirectAnalysis = (
const environment = snapshotEnvironment(selectedEnvironment);
const dependencies: DirectAnalysisDependencies = {
readConfiguration: () => parseConfig(environment),
createBinarySession: (config, logger) =>
createBinarySession(config, logger, environment),
createManagedBinarySession,
createBinarySession: async (config, logger) => {
const { createBinarySession } = await import("./binary.js");
return createBinarySession(config, logger, environment);
},
createManagedBinarySession: async () => {
const { createManagedBinarySession } = await import("./binary.js");
return createManagedBinarySession();
},
};
return {
runDirectAnalysis: executeDirectAnalysis.bind(undefined, dependencies),
@@ -34,6 +38,9 @@ export type DirectAnalysis = ReturnType<typeof createDirectAnalysis>;
export const runManagedProviderExecution = executeManagedProvider.bind(
undefined,
{
createManagedBinarySession,
createManagedBinarySession: async () => {
const { createManagedBinarySession } = await import("./binary.js");
return createManagedBinarySession();
},
},
);
+58 -8
View File
@@ -1,5 +1,5 @@
import { execFile } from "node:child_process";
import { mkdir } from "node:fs/promises";
import { mkdir, writeFile } from "node:fs/promises";
import { join } from "node:path";
import { promisify } from "node:util";
@@ -9,20 +9,34 @@ import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
const execute = promisify(execFile);
const MARKER = "REA_TEST_RESOLVED ";
// Dependencies that only one command uses; startup must not resolve them.
const DEFERRED_PACKAGES = ["playwright-core", "isomorphic-git"] as const;
// Dependencies and composition modules used by one command family; startup
// must not resolve them just to register the complete command catalog.
const DEFERRED_IMPORTS = [
{
name: "playwright-core",
path: "/node_modules/playwright-core/",
},
{
name: "isomorphic-git",
path: "/node_modules/isomorphic-git/",
},
{
name: "binary-composition",
path: "/dist/composition/binary.js",
},
] as const;
// Report each resolved deferred package on stderr without changing resolution.
const RESOLUTION_HOOK = `data:text/javascript,${encodeURIComponent(`
import { registerHooks } from "node:module";
const packages = ${JSON.stringify(DEFERRED_PACKAGES)};
const imports = ${JSON.stringify(DEFERRED_IMPORTS)};
registerHooks({
resolve(specifier, context, next) {
const resolved = next(specifier, context);
const name = packages.find((item) =>
resolved.url.includes("/node_modules/" + item + "/"),
const name = imports.find((item) =>
resolved.url.includes(item.path),
);
if (name !== undefined)
process.stderr.write(${JSON.stringify(MARKER)} + name + "\\n");
process.stderr.write(${JSON.stringify(MARKER)} + name.name + "\\n");
return resolved;
},
});
@@ -68,9 +82,45 @@ describe("CLI startup imports", () => {
).resolves.toContain("isomorphic-git");
});
it("does not load command-specific packages to register commands", async () => {
it("does not load command-specific code to register the command catalog", async () => {
await expect(
resolvedPackages(["scripts/rea.mjs", "--help"]),
).resolves.toEqual(new Set());
});
it("does not load native provider composition for JavaScript application analysis", async () => {
const source = await createTestTempDirectory("rea-cli-js-startup-");
await mkdir(join(source, "src"));
await writeFile(
join(source, "package.json"),
JSON.stringify({
name: "startup-fixture",
version: "1.0.0",
main: "src/index.js",
}),
);
await writeFile(
join(source, "src/index.js"),
"export const answer = 42;\n",
);
await expect(
resolvedPackages([
"scripts/rea.mjs",
"analyze-javascript-application",
source,
"--json",
]),
).resolves.toEqual(new Set());
});
it("loads native provider composition when a provider operation is called", async () => {
await expect(
resolvedPackages(
evaluate(
'const { createDirectAnalysis } = await import("./dist/composition/directAnalysis.js"); await createDirectAnalysis({}).runSessionStatus();',
),
),
).resolves.toContain("binary-composition");
});
});