@@ -7,8 +7,17 @@ import { transformRequest } from '../server/transformRequest'
7
7
import type { InternalResolveOptionsWithOverrideConditions } from '../plugins/resolve'
8
8
import { tryNodeResolve } from '../plugins/resolve'
9
9
import { genSourceMapUrl } from '../server/sourcemap'
10
- import type { PackageCache } from '../packages'
11
- import { unwrapId } from '../../shared/utils'
10
+ import {
11
+ AsyncFunction ,
12
+ asyncFunctionDeclarationPaddingLineCount ,
13
+ unwrapId ,
14
+ } from '../../shared/utils'
15
+ import {
16
+ type SSRImportBaseMetadata ,
17
+ analyzeImportedModDifference ,
18
+ proxyGuardOnlyEsm ,
19
+ } from '../../shared/ssrTransform'
20
+ import { SOURCEMAPPING_URL } from '../../shared/constants'
12
21
import {
13
22
ssrDynamicImportKey ,
14
23
ssrExportAllKey ,
@@ -27,31 +36,6 @@ type SSRModule = Record<string, any>
27
36
interface NodeImportResolveOptions
28
37
extends InternalResolveOptionsWithOverrideConditions {
29
38
legacyProxySsrExternalModules ?: boolean
30
- packageCache ?: PackageCache
31
- }
32
-
33
- interface SSRImportMetadata {
34
- isDynamicImport ?: boolean
35
- /**
36
- * Imported names before being transformed to `ssrImportKey`
37
- *
38
- * import foo, { bar as baz, qux } from 'hello'
39
- * => ['default', 'bar', 'qux']
40
- *
41
- * import * as namespace from 'world
42
- * => undefined
43
- */
44
- importedNames ?: string [ ]
45
- }
46
-
47
- // eslint-disable-next-line @typescript-eslint/no-empty-function
48
- const AsyncFunction = async function ( ) { } . constructor as typeof Function
49
- let fnDeclarationLineCount = 0
50
- {
51
- const body = '/*code*/'
52
- const source = new AsyncFunction ( 'a' , 'b' , body ) . toString ( )
53
- fnDeclarationLineCount =
54
- source . slice ( 0 , source . indexOf ( body ) ) . split ( '\n' ) . length - 1
55
39
}
56
40
57
41
const pendingModules = new Map < string , Promise < SSRModule > > ( )
@@ -165,7 +149,7 @@ async function instantiateModule(
165
149
// account for multiple pending deps and duplicate imports.
166
150
const pendingDeps : string [ ] = [ ]
167
151
168
- const ssrImport = async ( dep : string , metadata ?: SSRImportMetadata ) => {
152
+ const ssrImport = async ( dep : string , metadata ?: SSRImportBaseMetadata ) => {
169
153
try {
170
154
if ( dep [ 0 ] !== '.' && dep [ 0 ] !== '/' ) {
171
155
return await nodeImport ( dep , mod . file ! , resolveOptions , metadata )
@@ -227,12 +211,11 @@ async function instantiateModule(
227
211
let sourceMapSuffix = ''
228
212
if ( result . map && 'version' in result . map ) {
229
213
const moduleSourceMap = Object . assign ( { } , result . map , {
230
- // currently we need to offset the line
231
- // https://github.com/nodejs/node/issues/43047#issuecomment-1180632750
232
- mappings : ';' . repeat ( fnDeclarationLineCount ) + result . map . mappings ,
214
+ mappings :
215
+ ';' . repeat ( asyncFunctionDeclarationPaddingLineCount ) +
216
+ result . map . mappings ,
233
217
} )
234
- sourceMapSuffix =
235
- '\n//# sourceMappingURL=' + genSourceMapUrl ( moduleSourceMap )
218
+ sourceMapSuffix = `\n//# ${ SOURCEMAPPING_URL } =${ genSourceMapUrl ( moduleSourceMap ) } `
236
219
}
237
220
238
221
try {
@@ -289,7 +272,7 @@ async function nodeImport(
289
272
id : string ,
290
273
importer : string ,
291
274
resolveOptions : NodeImportResolveOptions ,
292
- metadata ?: SSRImportMetadata ,
275
+ metadata ?: SSRImportBaseMetadata ,
293
276
) {
294
277
let url : string
295
278
let filePath : string | undefined
@@ -322,10 +305,11 @@ async function nodeImport(
322
305
} else if ( filePath ) {
323
306
analyzeImportedModDifference (
324
307
mod ,
325
- filePath ,
326
308
id ,
309
+ isFilePathESM ( filePath , resolveOptions . packageCache )
310
+ ? 'module'
311
+ : undefined ,
327
312
metadata ,
328
- resolveOptions . packageCache ,
329
313
)
330
314
return proxyGuardOnlyEsm ( mod , id )
331
315
} else {
@@ -358,63 +342,3 @@ function proxyESM(mod: any) {
358
342
function isPrimitive ( value : any ) {
359
343
return ! value || ( typeof value !== 'object' && typeof value !== 'function' )
360
344
}
361
-
362
- /**
363
- * Vite converts `import { } from 'foo'` to `const _ = __vite_ssr_import__('foo')`.
364
- * Top-level imports and dynamic imports work slightly differently in Node.js.
365
- * This function normalizes the differences so it matches prod behaviour.
366
- */
367
- function analyzeImportedModDifference (
368
- mod : any ,
369
- filePath : string ,
370
- rawId : string ,
371
- metadata ?: SSRImportMetadata ,
372
- packageCache ?: PackageCache ,
373
- ) {
374
- // No normalization needed if the user already dynamic imports this module
375
- if ( metadata ?. isDynamicImport ) return
376
- // If file path is ESM, everything should be fine
377
- if ( isFilePathESM ( filePath , packageCache ) ) return
378
-
379
- // For non-ESM, named imports is done via static analysis with cjs-module-lexer in Node.js.
380
- // If the user named imports a specifier that can't be analyzed, error.
381
- if ( metadata ?. importedNames ?. length ) {
382
- const missingBindings = metadata . importedNames . filter ( ( s ) => ! ( s in mod ) )
383
- if ( missingBindings . length ) {
384
- const lastBinding = missingBindings [ missingBindings . length - 1 ]
385
- // Copied from Node.js
386
- throw new SyntaxError ( `\
387
- [vite] Named export '${ lastBinding } ' not found. The requested module '${ rawId } ' is a CommonJS module, which may not support all module.exports as named exports.
388
- CommonJS modules can always be imported via the default export, for example using:
389
-
390
- import pkg from '${ rawId } ';
391
- const {${ missingBindings . join ( ', ' ) } } = pkg;
392
- ` )
393
- }
394
- }
395
- }
396
-
397
- /**
398
- * Guard invalid named exports only, similar to how Node.js errors for top-level imports.
399
- * But since we transform as dynamic imports, we need to emulate the error manually.
400
- */
401
- function proxyGuardOnlyEsm (
402
- mod : any ,
403
- rawId : string ,
404
- metadata ?: SSRImportMetadata ,
405
- ) {
406
- // If the module doesn't import anything explicitly, e.g. `import 'foo'` or
407
- // `import * as foo from 'foo'`, we can skip the proxy guard.
408
- if ( ! metadata ?. importedNames ?. length ) return mod
409
-
410
- return new Proxy ( mod , {
411
- get ( mod , prop ) {
412
- if ( prop !== 'then' && ! ( prop in mod ) ) {
413
- throw new SyntaxError (
414
- `[vite] The requested module '${ rawId } ' does not provide an export named '${ prop . toString ( ) } '` ,
415
- )
416
- }
417
- return mod [ prop ]
418
- } ,
419
- } )
420
- }
0 commit comments