@@ -41,7 +41,9 @@ export interface Options {
4141 /**
4242 * Babel configuration applied in both dev and prod.
4343 */
44- babel ?: BabelOptions
44+ babel ?:
45+ | BabelOptions
46+ | ( ( id : string , options : { ssr ?: boolean } ) => BabelOptions )
4547}
4648
4749export type BabelOptions = Omit <
@@ -67,13 +69,21 @@ export interface ReactBabelOptions extends BabelOptions {
6769 }
6870}
6971
72+ type ReactBabelHook = (
73+ babelConfig : ReactBabelOptions ,
74+ context : ReactBabelHookContext ,
75+ config : ResolvedConfig
76+ ) => void
77+
78+ type ReactBabelHookContext = { ssr : boolean ; id : string }
79+
7080declare module 'vite' {
7181 export interface Plugin {
7282 api ?: {
7383 /**
7484 * Manipulate the Babel options of `@vitejs/plugin-react`
7585 */
76- reactBabel ?: ( options : ReactBabelOptions , config : ResolvedConfig ) => void
86+ reactBabel ?: ReactBabelHook
7787 }
7888 }
7989}
@@ -86,21 +96,14 @@ export default function viteReact(opts: Options = {}): PluginOption[] {
8696 let projectRoot = process . cwd ( )
8797 let skipFastRefresh = opts . fastRefresh === false
8898 let skipReactImport = false
99+ let runPluginOverrides = (
100+ options : ReactBabelOptions ,
101+ context : ReactBabelHookContext
102+ ) => false
103+ let staticBabelOptions : ReactBabelOptions | undefined
89104
90105 const useAutomaticRuntime = opts . jsxRuntime !== 'classic'
91106
92- const babelOptions = {
93- babelrc : false ,
94- configFile : false ,
95- ...opts . babel
96- } as ReactBabelOptions
97-
98- babelOptions . plugins ||= [ ]
99- babelOptions . presets ||= [ ]
100- babelOptions . overrides ||= [ ]
101- babelOptions . parserOpts ||= { } as any
102- babelOptions . parserOpts . plugins ||= [ ]
103-
104107 // Support patterns like:
105108 // - import * as React from 'react';
106109 // - import React from 'react';
@@ -141,11 +144,22 @@ export default function viteReact(opts: Options = {}): PluginOption[] {
141144 `[@vitejs/plugin-react] You should stop using "${ plugin . name } " ` +
142145 `since this plugin conflicts with it.`
143146 )
147+ } )
148+
149+ runPluginOverrides = ( babelOptions , context ) => {
150+ const hooks = config . plugins
151+ . map ( ( plugin ) => plugin . api ?. reactBabel )
152+ . filter ( Boolean ) as ReactBabelHook [ ]
144153
145- if ( plugin . api ?. reactBabel ) {
146- plugin . api . reactBabel ( babelOptions , config )
154+ if ( hooks . length > 0 ) {
155+ return ( runPluginOverrides = ( babelOptions ) => {
156+ hooks . forEach ( ( hook ) => hook ( babelOptions , context , config ) )
157+ return true
158+ } ) ( babelOptions )
147159 }
148- } )
160+ runPluginOverrides = ( ) => false
161+ return false
162+ }
149163 } ,
150164 async transform ( code , id , options ) {
151165 const ssr = typeof options === 'boolean' ? options : options ?. ssr === true
@@ -162,6 +176,18 @@ export default function viteReact(opts: Options = {}): PluginOption[] {
162176 const isProjectFile =
163177 ! isNodeModules && ( id [ 0 ] === '\0' || id . startsWith ( projectRoot + '/' ) )
164178
179+ let babelOptions = staticBabelOptions
180+ if ( typeof opts . babel === 'function' ) {
181+ const rawOptions = opts . babel ( id , { ssr } )
182+ babelOptions = createBabelOptions ( rawOptions )
183+ runPluginOverrides ( babelOptions , { ssr, id : id } )
184+ } else if ( ! babelOptions ) {
185+ babelOptions = createBabelOptions ( opts . babel )
186+ if ( ! runPluginOverrides ( babelOptions , { ssr, id : id } ) ) {
187+ staticBabelOptions = babelOptions
188+ }
189+ }
190+
165191 const plugins = isProjectFile ? [ ...babelOptions . plugins ] : [ ]
166192
167193 let useFastRefresh = false
@@ -368,3 +394,19 @@ viteReact.preambleCode = preambleCode
368394function loadPlugin ( path : string ) : Promise < any > {
369395 return import ( path ) . then ( ( module ) => module . default || module )
370396}
397+
398+ function createBabelOptions ( rawOptions ?: BabelOptions ) {
399+ const babelOptions = {
400+ babelrc : false ,
401+ configFile : false ,
402+ ...rawOptions
403+ } as ReactBabelOptions
404+
405+ babelOptions . plugins ||= [ ]
406+ babelOptions . presets ||= [ ]
407+ babelOptions . overrides ||= [ ]
408+ babelOptions . parserOpts ||= { } as any
409+ babelOptions . parserOpts . plugins ||= [ ]
410+
411+ return babelOptions
412+ }
0 commit comments