Repository: vercel/next.js
Pull request: [turbopack] Ensure React Compiler options are based dev vs prod

This is restoring the forking of React Compiler options. We'll need this to enable naming of anonymous functions in dev.

The plumbing stretches more files than for Turbopack so I filed this separately.

Changed files:
filename: packages/next/src/build/babel/loader/types.d.ts
patch: @@ -1,4 +1,5 @@
 import type { webpack } from 'next/dist/compiled/webpack/webpack'
+import type { JSONValue } from '../../../server/config-shared'
 import type { Span } from '../../../trace'
 
 export interface NextJsLoaderContext extends webpack.LoaderContext<{}> {
@@ -17,7 +18,7 @@ export interface NextBabelLoaderBaseOptions {
   /**
    * Custom plugins to be added to the generated babel options.
    */
-  reactCompilerPlugins?: Array<any>
+  reactCompilerPlugins?: Array<JSONValue>
 
   /**
    * Paths that the loader should not apply the react-compiler to.

filename: packages/next/src/build/get-babel-loader-config.ts
patch: @@ -1,5 +1,5 @@
 import path from 'path'
-import type { ReactCompilerOptions } from '../server/config-shared'
+import type { JSONValue, ReactCompilerOptions } from '../server/config-shared'
 import type { NextBabelLoaderOptions } from './babel/loader/types'
 
 function getReactCompiler() {
@@ -15,27 +15,26 @@ function getReactCompiler() {
 }
 
 const getReactCompilerPlugins = (
-  options: boolean | ReactCompilerOptions | undefined,
-  isServer: boolean
-) => {
-  if (!options || isServer) {
+  maybeOptions: boolean | ReactCompilerOptions | undefined,
+  isServer: boolean,
+  isDev: boolean
+): undefined | JSONValue[] => {
+  if (!maybeOptions || isServer) {
     return undefined
   }
 
-  const compilerOptions = typeof options === 'boolean' ? {} : options
-  if (options) {
-    return [
-      [
-        getReactCompiler(),
-        {
-          // https://react.dev/reference/react-compiler/panicThreshold
-          panicThreshold: 'none',
-          ...compilerOptions,
-        },
-      ],
-    ]
+  const defaultOptions: ReactCompilerOptions = isDev
+    ? {
+        // TODO: enable `environment.enableNameAnonymousFunctions`Ï
+      }
+    : {}
+  const options: ReactCompilerOptions =
+    typeof maybeOptions === 'boolean' ? {} : maybeOptions
+  const compilerOptions: JSONValue = {
+    ...defaultOptions,
+    ...options,
   }
-  return undefined
+  return [[getReactCompiler(), compilerOptions]]
 }
 
 const getBabelLoader = (
@@ -67,7 +66,8 @@ const getBabelLoader = (
       hasJsxRuntime: true,
       reactCompilerPlugins: getReactCompilerPlugins(
         reactCompilerOptions,
-        isServer
+        isServer,
+        dev
       ),
       reactCompilerExclude,
     }
@@ -90,11 +90,13 @@ const getReactCompilerLoader = (
   reactCompilerOptions: boolean | ReactCompilerOptions | undefined,
   cwd: string,
   isServer: boolean,
-  reactCompilerExclude: ((excludePath: string) => boolean) | undefined
+  reactCompilerExclude: ((excludePath: string) => boolean) | undefined,
+  isDev: boolean
 ) => {
   const reactCompilerPlugins = getReactCompilerPlugins(
     reactCompilerOptions,
-    isServer
+    isServer,
+    isDev
   )
   if (!reactCompilerPlugins) {
     return undefined

filename: packages/next/src/build/webpack-config.ts
patch: @@ -492,7 +492,8 @@ export default async function getBaseWebpackConfig(
         config.experimental?.reactCompiler,
         dir,
         isNodeOrEdgeCompilation,
-        codeCondition.exclude
+        codeCondition.exclude,
+        dev
       )
 
   let swcTraceProfilingInitialized = false

filename: packages/next/src/server/config-shared.ts
patch: @@ -88,7 +88,7 @@ export interface StyledComponentsConfig {
   cssProp?: boolean
 }
 
-type JSONValue =
+export type JSONValue =
   | string
   | number
   | boolean