Skip to content

Commit abc0c03

Browse files
committed
babel-loader: Avoid calling expensive isReactCompilerRequired check when we must run Babel anyways
1 parent 446a671 commit abc0c03

File tree

1 file changed

+41
-8
lines changed

1 file changed

+41
-8
lines changed

packages/next/src/build/babel/loader/get-config.ts

Lines changed: 41 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
6779
const fileExtensionRegex = /\.([a-z]+)$/
6880
async 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
!/[/\\]node_modules[/\\]/.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

Comments
 (0)