Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 41 additions & 8 deletions packages/next/src/build/babel/loader/get-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,18 @@ interface CharacteristicsGermaneToCaching {
configFilePath: string | undefined
}

function shouldSkipBabel(
transformMode: 'standalone' | 'default',
configFilePath: string | undefined,
hasReactCompiler: boolean
) {
return (
transformMode === 'standalone' &&
configFilePath == null &&
!hasReactCompiler
)
}

const fileExtensionRegex = /\.([a-z]+)$/
async function getCacheCharacteristics(
loaderOptions: NextBabelLoaderOptions,
Expand Down Expand Up @@ -91,19 +103,39 @@ async function getCacheCharacteristics(
const hasModuleExports = source.indexOf('module.exports') !== -1
const fileExt = fileExtensionRegex.exec(filename)?.[1] || 'unknown'

let {
reactCompilerPlugins,
reactCompilerExclude,
configFile: configFilePath,
transformMode,
} = loaderOptions

// Compute `hasReactCompiler` as part of the cache characteristics / key,
// rather than inside of `getFreshConfig`:
// - `isReactCompilerRequired` depends on the file contents
// - `node_modules` and `reactCompilerExclude` depend on the file path, which
// isn't part of the cache characteristics
let { reactCompilerPlugins, reactCompilerExclude } = loaderOptions
reactCompilerPlugins ??= []
const hasReactCompiler =
let hasReactCompiler =
reactCompilerPlugins != null &&
reactCompilerPlugins.length !== 0 &&
!loaderOptions.isServer &&
!/[/\\]node_modules[/\\]/.test(filename) &&
!reactCompilerExclude?.(filename) &&
(await isReactCompilerRequired(filename))
// Assumption: `reactCompilerExclude` is cheap because it should only
// operate on the file path and *not* the file contents (it's sync)
!reactCompilerExclude?.(filename)

// `isReactCompilerRequired` is expensive to run (parses/visits with SWC), so
// only run it if there's a good chance we might be able to skip calling Babel
// entirely (speculatively call `shouldSkipBabel`).
//
// Otherwise, we can let react compiler handle this logic for us. It should
// behave equivalently.
if (
hasReactCompiler &&
shouldSkipBabel(transformMode, configFilePath, /*hasReactCompiler*/ false)
) {
hasReactCompiler &&= await isReactCompilerRequired(filename)
}

return {
isStandalone,
Expand All @@ -113,7 +145,7 @@ async function getCacheCharacteristics(
hasModuleExports,
hasReactCompiler,
fileExt,
configFilePath: loaderOptions.configFile,
configFilePath,
}
}

Expand Down Expand Up @@ -336,8 +368,9 @@ async function getFreshConfig(
const { hasReactCompiler, configFilePath, fileExt } = cacheCharacteristics

let customConfig = configFilePath && getCustomBabelConfig(configFilePath)
if (transformMode === 'standalone' && !customConfig && !hasReactCompiler) {
// Optimization: There's nothing useful to do, bail out and skip babel on this file
if (shouldSkipBabel(transformMode, configFilePath, hasReactCompiler)) {
// Optimization: There's nothing useful to do, bail out and skip babel on
// this file
return null
}

Expand Down
Loading