diff --git a/lib/follow.ts b/lib/follow.ts index 861bf9f9..f2719c30 100644 --- a/lib/follow.ts +++ b/lib/follow.ts @@ -73,7 +73,7 @@ export function follow(x: string, opts: FollowOptions) { } else if (opts.extensions) { extensions = [opts.extensions as string]; } else { - extensions = ['.js', '.json', '.node']; + extensions = ['.js', '.json', '.node', '.mjs', '.cjs']; } const result = resolveModule(x, { @@ -81,11 +81,11 @@ export function follow(x: string, opts: FollowOptions) { extensions, }); - // Only use ESM resolution result if it's an actual ESM package - // For CJS packages, fall through to standard CommonJS resolution - // to ensure all callbacks (catchReadFile, catchPackageFilter) are handled correctly - if (result.isESM) { - // This is a real ESM package, handle it here + // Use the exports-aware resolver result whenever it succeeds, + // regardless of whether the resolved file is ESM or CJS. + // The "exports" field is a package-level feature, not ESM-only — + // dual-format packages use it to point require() to .cjs files. + if (result.resolvedViaExports) { if (opts.catchReadFile) { // Find the package.json for this resolved module let currentDir = path.dirname(result.resolved); @@ -132,13 +132,12 @@ export function follow(x: string, opts: FollowOptions) { } } - // ESM package resolved successfully + // Exports-aware resolver succeeded resolve(result.resolved); return; } - // CJS package - fall through to standard CommonJS resolution - // to handle all callbacks properly + // No exports field found - fall through to standard CommonJS resolution } catch (_error) { // ESM resolution failed - fall through to standard CommonJS resolution } diff --git a/lib/resolver.ts b/lib/resolver.ts index ef26a98b..61674fca 100644 --- a/lib/resolver.ts +++ b/lib/resolver.ts @@ -21,6 +21,7 @@ interface ResolveOptions { interface ResolveResult { resolved: string; isESM: boolean; + resolvedViaExports: boolean; } /** @@ -149,7 +150,7 @@ export function resolveModule( specifier: string, options: ResolveOptions, ): ResolveResult { - const { basedir, extensions = ['.js', '.json', '.node'] } = options; + const { basedir, extensions = ['.js', '.json', '.node', '.mjs', '.cjs'] } = options; // First, try ESM-style resolution with exports field const esmResolved = tryResolveESM(specifier, basedir); @@ -158,6 +159,7 @@ export function resolveModule( return { resolved: esmResolved, isESM: isESMFile(esmResolved), + resolvedViaExports: true, }; } @@ -170,5 +172,6 @@ export function resolveModule( return { resolved, isESM: false, // CJS resolution + resolvedViaExports: false, }; } diff --git a/lib/walker.ts b/lib/walker.ts index 2b2429fc..4b0d18da 100644 --- a/lib/walker.ts +++ b/lib/walker.ts @@ -26,7 +26,7 @@ import { pc } from './colors'; import { follow } from './follow'; import { log, wasReported } from './log'; import * as detector from './detector'; -import { transformESMtoCJS, rewriteMjsRequirePaths } from './esm-transformer'; +import { transformESMtoCJS } from './esm-transformer'; import { ConfigDictionary, FileRecord, @@ -77,7 +77,7 @@ const win32 = process.platform === 'win32'; // Extensions to try when resolving modules // Includes .mjs to support ESM files that get transformed to .js -const MODULE_RESOLVE_EXTENSIONS = ['.js', '.json', '.node', '.mjs']; +const MODULE_RESOLVE_EXTENSIONS = ['.js', '.json', '.node', '.mjs', '.cjs']; /** * Checks if a module is a core module @@ -1121,15 +1121,6 @@ class Walker { const derivatives2: Derivative[] = []; stepDetect(record, marker, derivatives2); await this.stepDerivatives(record, marker, derivatives2); - - // After dependencies are resolved, rewrite .mjs require paths to .js - // since the packer renames .mjs files to .js in the snapshot - if (record.wasTransformed && record.body) { - record.body = Buffer.from( - rewriteMjsRequirePaths(record.body.toString('utf8')), - 'utf8', - ); - } } }