@@ -64,6 +64,18 @@ interface CharacteristicsGermaneToCaching {
6464 configFilePath : string | undefined
6565}
6666
67+ function shouldSkipBabel (
68+ transformMode : 'standalone' | 'default' ,
69+ configFilePath : string | undefined ,
70+ hasReactCompiler : boolean
71+ ) {
72+ return (
73+ transformMode === 'standalone' &&
74+ configFilePath == null &&
75+ ! hasReactCompiler
76+ )
77+ }
78+
6779const fileExtensionRegex = / \. ( [ a - z ] + ) $ /
6880async function getCacheCharacteristics (
6981 loaderOptions : NextBabelLoaderOptions ,
@@ -91,19 +103,39 @@ async function getCacheCharacteristics(
91103 const hasModuleExports = source . indexOf ( 'module.exports' ) !== - 1
92104 const fileExt = fileExtensionRegex . exec ( filename ) ?. [ 1 ] || 'unknown'
93105
106+ let {
107+ reactCompilerPlugins,
108+ reactCompilerExclude,
109+ configFile : configFilePath ,
110+ transformMode,
111+ } = loaderOptions
112+
94113 // Compute `hasReactCompiler` as part of the cache characteristics / key,
95114 // rather than inside of `getFreshConfig`:
96115 // - `isReactCompilerRequired` depends on the file contents
97116 // - `node_modules` and `reactCompilerExclude` depend on the file path, which
98117 // isn't part of the cache characteristics
99- let { reactCompilerPlugins, reactCompilerExclude } = loaderOptions
100- reactCompilerPlugins ??= [ ]
101- const hasReactCompiler =
118+ let hasReactCompiler =
119+ reactCompilerPlugins != null &&
102120 reactCompilerPlugins . length !== 0 &&
103121 ! loaderOptions . isServer &&
104122 ! / [ / \\ ] n o d e _ m o d u l e s [ / \\ ] / . test ( filename ) &&
105- ! reactCompilerExclude ?.( filename ) &&
106- ( await isReactCompilerRequired ( filename ) )
123+ // Assumption: `reactCompilerExclude` is cheap because it should only
124+ // operate on the file path and *not* the file contents (it's sync)
125+ ! reactCompilerExclude ?.( filename )
126+
127+ // `isReactCompilerRequired` is expensive to run (parses/visits with SWC), so
128+ // only run it if there's a good chance we might be able to skip calling Babel
129+ // entirely (speculatively call `shouldSkipBabel`).
130+ //
131+ // Otherwise, we can let react compiler handle this logic for us. It should
132+ // behave equivalently.
133+ if (
134+ hasReactCompiler &&
135+ shouldSkipBabel ( transformMode , configFilePath , /*hasReactCompiler*/ false )
136+ ) {
137+ hasReactCompiler &&= await isReactCompilerRequired ( filename )
138+ }
107139
108140 return {
109141 isStandalone,
@@ -113,7 +145,7 @@ async function getCacheCharacteristics(
113145 hasModuleExports,
114146 hasReactCompiler,
115147 fileExt,
116- configFilePath : loaderOptions . configFile ,
148+ configFilePath,
117149 }
118150}
119151
@@ -336,8 +368,9 @@ async function getFreshConfig(
336368 const { hasReactCompiler, configFilePath, fileExt } = cacheCharacteristics
337369
338370 let customConfig = configFilePath && getCustomBabelConfig ( configFilePath )
339- if ( transformMode === 'standalone' && ! customConfig && ! hasReactCompiler ) {
340- // Optimization: There's nothing useful to do, bail out and skip babel on this file
371+ if ( shouldSkipBabel ( transformMode , configFilePath , hasReactCompiler ) ) {
372+ // Optimization: There's nothing useful to do, bail out and skip babel on
373+ // this file
341374 return null
342375 }
343376
0 commit comments