From de28ca9f0e7573efba1d2d93475b5f53112bfe52 Mon Sep 17 00:00:00 2001 From: Kit Langton Date: Thu, 13 Aug 2026 21:48:48 -0400 Subject: [PATCH] refactor(util): load npm package parser lazily (#42467) --- packages/core/test/npm.test.ts | 44 ++++++++++++++++++++++++- packages/util/src/npm.ts | 2 +- packages/workerd-spike/vitest.config.ts | 2 +- 3 files changed, 45 insertions(+), 3 deletions(-) diff --git a/packages/core/test/npm.test.ts b/packages/core/test/npm.test.ts index 3dae4f434be..b970aad1115 100644 --- a/packages/core/test/npm.test.ts +++ b/packages/core/test/npm.test.ts @@ -1,7 +1,7 @@ import fs from "fs/promises" import path from "path" import { describe, expect, test } from "bun:test" -import { Effect, Option } from "effect" +import { Effect } from "effect" import { AppNodeBuilder } from "@opencode-ai/core/effect/app-node-builder" import { Global } from "@opencode-ai/util/global" import { Npm } from "@opencode-ai/util/npm" @@ -36,6 +36,48 @@ describe("Npm.sanitize", () => { }) describe("Npm.add", () => { + test("resolves cached scoped package specs without reifying", async () => { + await using tmp = await tmpdir() + const spec = "@fixture/provider@1.0.0" + const directory = path.join( + tmp.path, + "cache", + "packages", + Npm.sanitize(spec), + "node_modules", + "@fixture", + "provider", + ) + await fs.mkdir(directory, { recursive: true }) + await writePackage(directory, { name: "@fixture/provider", exports: "./index.js" }) + await Bun.write(path.join(directory, "index.js"), "export const fixture = true\n") + + const entry = await Effect.gen(function* () { + const npm = yield* Npm.Service + return yield* npm.add(spec) + }).pipe(Effect.scoped, Effect.provide(npmLayer(path.join(tmp.path, "cache"))), Effect.runPromise) + + expect(entry.directory).toBe(directory) + expect(entry.entrypoint).toEndWith("/index.js") + }) + + test("falls back to the original spec when parsing fails", async () => { + await using tmp = await tmpdir() + const spec = "fixture provider" + const directory = path.join(tmp.path, "cache", "packages", Npm.sanitize(spec), "node_modules", spec) + await fs.mkdir(directory, { recursive: true }) + await writePackage(directory, { name: spec, exports: "./index.js" }) + await Bun.write(path.join(directory, "index.js"), "export const fixture = true\n") + + const entry = await Effect.gen(function* () { + const npm = yield* Npm.Service + return yield* npm.add(spec) + }).pipe(Effect.scoped, Effect.provide(npmLayer(path.join(tmp.path, "cache"))), Effect.runPromise) + + expect(entry.directory).toBe(directory) + expect(entry.entrypoint).toEndWith("/index.js") + }) + test("reifies when package cache directory exists without the package installed", async () => { await using tmp = await tmpdir() await fs.mkdir(path.join(tmp.path, "fixture-provider")) diff --git a/packages/util/src/npm.ts b/packages/util/src/npm.ts index e2722f33bbc..26080ce50ff 100644 --- a/packages/util/src/npm.ts +++ b/packages/util/src/npm.ts @@ -1,7 +1,6 @@ export * as Npm from "./npm.js" import path from "path" -import npa from "npm-package-arg" import { Effect, Schema, Context, Layer, Option, FileSystem } from "effect" import * as NodeFileSystem from "@effect/platform-node/NodeFileSystem" import { FSUtil } from "./fs-util.js" @@ -111,6 +110,7 @@ const layer = Layer.effect( ) const add = Effect.fn("Npm.add")(function* (pkg: string, options?: { readonly subpaths?: readonly string[] }) { + const { default: npa } = yield* Effect.promise(() => import("npm-package-arg")) const dir = directory(pkg) const name = (() => { try { diff --git a/packages/workerd-spike/vitest.config.ts b/packages/workerd-spike/vitest.config.ts index 044a057938e..cc838a577f1 100644 --- a/packages/workerd-spike/vitest.config.ts +++ b/packages/workerd-spike/vitest.config.ts @@ -52,7 +52,7 @@ export default defineWorkersConfig({ // lookup surface but back it with a static shim. { find: /^mime-types$/, replacement: new URL("./test/shims/mime-types.mjs", import.meta.url).pathname }, // Plugin installs never happen in the workerd profile (plugin discovery - // is precompiled-only), so mock the package installation toolchain. + // is precompiled-only), so mock package installation when it is loaded. { find: /^@npmcli\/arborist(\/.*)?$/, replacement: mockProxy }, { find: /^pacote(\/.*)?$/, replacement: mockProxy }, ],