소스 검색

refactor(util): load npm package parser lazily (#42467)

Kit Langton 2 일 전
부모
커밋
de28ca9f0e
3개의 변경된 파일45개의 추가작업 그리고 3개의 파일을 삭제
  1. 43 1
      packages/core/test/npm.test.ts
  2. 1 1
      packages/util/src/npm.ts
  3. 1 1
      packages/workerd-spike/vitest.config.ts

+ 43 - 1
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"))

+ 1 - 1
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 {

+ 1 - 1
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 },
     ],