@@ -6,44 +6,66 @@ import { fileURLToPath, pathToFileURL } from 'node:url'
66type RegisteredModule = {
77 source : string
88 loaded : boolean
9- filename : string
9+ filepath : string
10+ // lazily parsed json string
11+ parsedJson ?: any
1012}
1113const registeredModules = new Map < string , RegisteredModule > ( )
1214
1315const require = createRequire ( import . meta. url )
1416
1517let hookedIn = false
1618
19+ function parseJson ( matchedModule : RegisteredModule ) {
20+ if ( matchedModule . parsedJson ) {
21+ return matchedModule . parsedJson
22+ }
23+
24+ try {
25+ const jsonContent = JSON . parse ( matchedModule . source )
26+ matchedModule . parsedJson = jsonContent
27+ return jsonContent
28+ } catch ( error ) {
29+ throw new Error ( `Failed to parse JSON module: ${ matchedModule . filepath } ` , { cause : error } )
30+ }
31+ }
32+
1733function seedCJSModuleCacheAndReturnTarget ( matchedModule : RegisteredModule , parent : Module ) {
1834 if ( matchedModule . loaded ) {
19- return matchedModule . filename
35+ return matchedModule . filepath
2036 }
21- const { source, filename } = matchedModule
37+ const { source, filepath } = matchedModule
2238
23- const mod = new Module ( filename )
39+ const mod = new Module ( filepath )
2440 mod . parent = parent
25- mod . filename = filename
26- mod . path = dirname ( filename )
41+ mod . filename = filepath
42+ mod . path = dirname ( filepath )
2743 // @ts -expect-error - private untyped API
2844 mod . paths = Module . _nodeModulePaths ( mod . path )
29- require . cache [ filename ] = mod
45+ require . cache [ filepath ] = mod
3046
31- const wrappedSource = `(function (exports, require, module, __filename, __dirname) { ${ source } \n});`
3247 try {
33- const compiled = vm . runInThisContext ( wrappedSource , {
34- filename,
35- lineOffset : 0 ,
36- displayErrors : true ,
37- } )
38- compiled ( mod . exports , createRequire ( pathToFileURL ( filename ) ) , mod , filename , dirname ( filename ) )
48+ if ( filepath . endsWith ( '.json' ) ) {
49+ Object . assign ( mod . exports , parseJson ( matchedModule ) )
50+ } else {
51+ const wrappedSource = `(function (exports, require, module, __filename, __dirname) { ${ source } \n});`
52+ const compiled = vm . runInThisContext ( wrappedSource , {
53+ filename : filepath ,
54+ lineOffset : 0 ,
55+ displayErrors : true ,
56+ } )
57+ const modRequire = createRequire ( pathToFileURL ( filepath ) )
58+ compiled ( mod . exports , modRequire , mod , filepath , dirname ( filepath ) )
59+ }
3960 mod . loaded = matchedModule . loaded = true
4061 } catch ( error ) {
41- throw new Error ( `Failed to compile CJS module: ${ filename } ` , { cause : error } )
62+ throw new Error ( `Failed to compile CJS module: ${ filepath } ` , { cause : error } )
4263 }
4364
44- return filename
65+ return filepath
4566}
4667
68+ // ideally require.extensions could be used, but it does NOT include '.cjs', so hardcoding instead
4769const exts = [ '.js' , '.cjs' , '.json' ]
4870
4971function tryWithExtensions ( filename : string ) {
@@ -80,7 +102,7 @@ export function registerCJSModules(baseUrl: URL, modules: Map<string, string>) {
80102 for ( const [ filename , source ] of modules . entries ( ) ) {
81103 const target = join ( basePath , filename )
82104
83- registeredModules . set ( target , { source, loaded : false , filename : target } )
105+ registeredModules . set ( target , { source, loaded : false , filepath : target } )
84106 }
85107
86108 if ( ! hookedIn ) {
@@ -101,8 +123,30 @@ export function registerCJSModules(baseUrl: URL, modules: Map<string, string>) {
101123 let matchedModule = tryMatchingWithIndex ( target )
102124
103125 if ( ! isRelative && ! target . startsWith ( '/' ) ) {
126+ const packageName = target . startsWith ( '@' )
127+ ? target . split ( '/' ) . slice ( 0 , 2 ) . join ( '/' )
128+ : target . split ( '/' ) [ 0 ]
129+ const moduleInPackagePath = target . slice ( packageName . length + 1 )
130+
104131 for ( const nodeModulePaths of args [ 1 ] . paths ) {
105- const potentialPath = join ( nodeModulePaths , target )
132+ const potentialPackageJson = join ( nodeModulePaths , packageName , 'package.json' )
133+
134+ const maybePackageJson = registeredModules . get ( potentialPackageJson )
135+
136+ let relativeTarget = moduleInPackagePath
137+
138+ let pkgJson : any = null
139+ if ( maybePackageJson ) {
140+ pkgJson = parseJson ( maybePackageJson )
141+
142+ // TODO: exports and anything else like that
143+ if ( moduleInPackagePath . length === 0 && pkgJson . main ) {
144+ relativeTarget = pkgJson . main
145+ }
146+ }
147+
148+ const potentialPath = join ( nodeModulePaths , packageName , relativeTarget )
149+
106150 matchedModule = tryMatchingWithIndex ( potentialPath )
107151 if ( matchedModule ) {
108152 break
0 commit comments