@@ -18,8 +18,10 @@ import picomatch from 'next/dist/compiled/picomatch'
18
18
import { getModuleBuildInfo } from '../loaders/get-module-build-info'
19
19
import { getPageFilePath } from '../../entries'
20
20
import { resolveExternal } from '../../handle-externals'
21
+ import swcLoader , { type SWCLoaderOptions } from '../loaders/next-swc-loader'
21
22
import { isMetadataRouteFile } from '../../../lib/metadata/is-metadata-route'
22
23
import { getCompilationSpan } from '../utils'
24
+ import { isClientComponentEntryModule } from '../loaders/utils'
23
25
24
26
const PLUGIN_NAME = 'TraceEntryPointsPlugin'
25
27
export const TRACE_IGNORES = [
@@ -137,6 +139,10 @@ export class TraceEntryPointsPlugin implements webpack.WebpackPluginInstance {
137
139
private traceIgnores : string [ ]
138
140
private esmExternals ?: NextConfigComplete [ 'experimental' ] [ 'esmExternals' ]
139
141
private compilerType : CompilerNameValues
142
+ private swcLoaderConfig : {
143
+ loader : string
144
+ options : Partial < SWCLoaderOptions >
145
+ }
140
146
141
147
constructor ( {
142
148
rootDir,
@@ -147,6 +153,7 @@ export class TraceEntryPointsPlugin implements webpack.WebpackPluginInstance {
147
153
traceIgnores,
148
154
esmExternals,
149
155
outputFileTracingRoot,
156
+ swcLoaderConfig,
150
157
} : {
151
158
rootDir : string
152
159
compilerType : CompilerNameValues
@@ -156,6 +163,7 @@ export class TraceEntryPointsPlugin implements webpack.WebpackPluginInstance {
156
163
traceIgnores ?: string [ ]
157
164
outputFileTracingRoot ?: string
158
165
esmExternals ?: NextConfigComplete [ 'experimental' ] [ 'esmExternals' ]
166
+ swcLoaderConfig : TraceEntryPointsPlugin [ 'swcLoaderConfig' ]
159
167
} ) {
160
168
this . rootDir = rootDir
161
169
this . appDir = appDir
@@ -166,6 +174,7 @@ export class TraceEntryPointsPlugin implements webpack.WebpackPluginInstance {
166
174
this . traceIgnores = traceIgnores || [ ]
167
175
this . tracingRoot = outputFileTracingRoot || rootDir
168
176
this . compilerType = compilerType
177
+ this . swcLoaderConfig = swcLoaderConfig
169
178
}
170
179
171
180
// Here we output all traced assets and webpack chunks to a
@@ -400,6 +409,18 @@ export class TraceEntryPointsPlugin implements webpack.WebpackPluginInstance {
400
409
}
401
410
} )
402
411
412
+ const readOriginalSource = ( path : string ) => {
413
+ return new Promise < string | Buffer > ( ( resolve ) => {
414
+ compilation . inputFileSystem . readFile ( path , ( err , result ) => {
415
+ if ( err ) {
416
+ // we can't throw here as that crashes build un-necessarily
417
+ return resolve ( '' )
418
+ }
419
+ resolve ( result || '' )
420
+ } )
421
+ } )
422
+ }
423
+
403
424
const readFile = async (
404
425
path : string
405
426
) : Promise < Buffer | string | null > => {
@@ -408,6 +429,60 @@ export class TraceEntryPointsPlugin implements webpack.WebpackPluginInstance {
408
429
// map the transpiled source when available to avoid
409
430
// parse errors in node-file-trace
410
431
let source : Buffer | string = mod ?. originalSource ?.( ) ?. buffer ( )
432
+
433
+ try {
434
+ // fallback to reading raw source file, this may fail
435
+ // due to unsupported syntax but best effort attempt
436
+ let usingOriginalSource = false
437
+ if ( ! source || isClientComponentEntryModule ( mod ) ) {
438
+ source = await readOriginalSource ( path )
439
+ usingOriginalSource = true
440
+ }
441
+ const sourceString = source . toString ( )
442
+
443
+ // If this is a client component we need to trace the
444
+ // original transpiled source not the client proxy which is
445
+ // applied before this plugin is run due to the
446
+ // client-module-loader
447
+ if (
448
+ usingOriginalSource &&
449
+ // don't attempt transpiling CSS or image imports
450
+ path . match ( / \. ( t s x | t s | j s | c j s | m j s | j s x ) $ / )
451
+ ) {
452
+ let transformResolve : ( result : string ) => void
453
+ let transformReject : ( error : unknown ) => void
454
+ const transformPromise = new Promise < string > (
455
+ ( resolve , reject ) => {
456
+ transformResolve = resolve
457
+ transformReject = reject
458
+ }
459
+ )
460
+
461
+ // TODO: should we apply all loaders except the
462
+ // client-module-loader?
463
+ swcLoader . apply (
464
+ {
465
+ resourcePath : path ,
466
+ getOptions : ( ) => {
467
+ return this . swcLoaderConfig . options
468
+ } ,
469
+ async : ( ) => {
470
+ return ( err : unknown , result : string ) => {
471
+ if ( err ) {
472
+ return transformReject ( err )
473
+ }
474
+ return transformResolve ( result )
475
+ }
476
+ } ,
477
+ } ,
478
+ [ sourceString , undefined ]
479
+ )
480
+ source = await transformPromise
481
+ }
482
+ } catch {
483
+ /* non-fatal */
484
+ }
485
+
411
486
return source || ''
412
487
}
413
488
0 commit comments