From 6bad808712aeb68b9d2aca6430a908b2e52c90a9 Mon Sep 17 00:00:00 2001 From: "pullfrog[bot]" <226033991+pullfrog[bot]@users.noreply.github.com> Date: Thu, 27 Aug 2026 07:27:49 +0000 Subject: [PATCH] runtime: memoize vendored-package resolution in resolveSpec resolveSpec resolved every @oxc-project/runtime helper specifier through __require.resolve on each import site. That require has a nub-internal parent, so it re-entered the registered resolve hook and paid a createRequire plus a nested hook round trip per call. Transpiled decorator output emits three helper imports per decorated file, so the cost landed on every file of a decorator-heavy tree. Cache the resolved URL per specifier; a vendored package lives in nub's own distribution and cannot move under a running process. --- runtime/transform-core.mjs | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/runtime/transform-core.mjs b/runtime/transform-core.mjs index 7cf8c7b96..1f63327fe 100644 --- a/runtime/transform-core.mjs +++ b/runtime/transform-core.mjs @@ -366,6 +366,19 @@ function safeRequireResolve(specifier) { try { return __require.resolve(specifier); } catch { return null; } } +// Resolved URL per vendored specifier (null = unresolvable), memoized for the +// life of the process. A vendored package lives in nub's OWN distribution, so +// its location cannot change under a running process — but the resolve is far +// from free: `__require` has a nub-internal parent, so each call re-enters the +// registered resolve hook, which takes the isNubInternalParent branch and pays a +// `createRequire` plus a nested hook round trip. Transpiled decorator output +// imports three helpers (`decorate`/`decorateMetadata`/`decorateParam`) per +// decorated file, so a NestJS-shaped tree repeated that on every import site: +// ~18ms each, ~54ms per file, 10.8s to load a 200-file tree that costs 0.2s +// undecorated (#795). Distinct specifiers number in the low tens; importers do +// not. +const vendoredResolutions = new Map(); + export function barePkg(specifier) { return specifier.startsWith("@") ? specifier.split("/").slice(0, 2).join("/") @@ -495,8 +508,13 @@ export function resolveSpec(specifier, parentURL) { // 2. Vendored packages (e.g. @oxc-project/runtime). const bare = barePkg(specifier); if (VENDORED_PACKAGES.has(bare)) { - const resolved = safeRequireResolve(specifier); - if (resolved) return { url: pathToFileURL(resolved).href, shortCircuit: true }; + let url = vendoredResolutions.get(specifier); + if (url === undefined) { + const resolved = safeRequireResolve(specifier); + url = resolved ? pathToFileURL(resolved).href : null; + vendoredResolutions.set(specifier, url); + } + if (url) return { url, shortCircuit: true }; } // 3. Package clobbering.