1- // eslint-disable-next-line import/no-duplicates
2- import type * as babelCore from '@babel/core'
3- // eslint-disable-next-line import/no-duplicates
4- import type { ParserOptions , TransformOptions } from '@babel/core'
5- import { createFilter } from 'vite'
1+ import { createFilter } from 'rolldown-vite'
62import type {
73 BuildOptions ,
84 Plugin ,
95 PluginOption ,
10- ResolvedConfig ,
116 UserConfig ,
12- } from 'vite'
7+ } from 'rolldown- vite'
138import {
149 addClassComponentRefreshWrapper ,
1510 addRefreshWrapper ,
@@ -18,15 +13,6 @@ import {
1813 runtimePublicPath ,
1914} from './fast-refresh'
2015
21- // lazy load babel since it's not used during build if plugins are not used
22- let babel : typeof babelCore | undefined
23- async function loadBabel ( ) {
24- if ( ! babel ) {
25- babel = await import ( '@babel/core' )
26- }
27- return babel
28- }
29-
3016export interface Options {
3117 include ?: string | RegExp | Array < string | RegExp >
3218 exclude ?: string | RegExp | Array < string | RegExp >
@@ -41,56 +27,11 @@ export interface Options {
4127 * @default "automatic"
4228 */
4329 jsxRuntime ?: 'classic' | 'automatic'
44- /**
45- * Babel configuration applied in both dev and prod.
46- */
47- babel ?:
48- | BabelOptions
49- | ( ( id : string , options : { ssr ?: boolean } ) => BabelOptions )
50- }
51-
52- export type BabelOptions = Omit <
53- TransformOptions ,
54- | 'ast'
55- | 'filename'
56- | 'root'
57- | 'sourceFileName'
58- | 'sourceMaps'
59- | 'inputSourceMap'
60- >
61-
62- /**
63- * The object type used by the `options` passed to plugins with
64- * an `api.reactBabel` method.
65- */
66- export interface ReactBabelOptions extends BabelOptions {
67- plugins : Extract < BabelOptions [ 'plugins' ] , any [ ] >
68- presets : Extract < BabelOptions [ 'presets' ] , any [ ] >
69- overrides : Extract < BabelOptions [ 'overrides' ] , any [ ] >
70- parserOpts : ParserOptions & {
71- plugins : Extract < ParserOptions [ 'plugins' ] , any [ ] >
72- }
73- }
74-
75- type ReactBabelHook = (
76- babelConfig : ReactBabelOptions ,
77- context : ReactBabelHookContext ,
78- config : ResolvedConfig ,
79- ) => void
80-
81- type ReactBabelHookContext = { ssr : boolean ; id : string }
82-
83- export type ViteReactPluginApi = {
84- /**
85- * Manipulate the Babel options of `@vitejs/plugin-react`
86- */
87- reactBabel ?: ReactBabelHook
8830}
8931
9032const reactCompRE = / e x t e n d s \s + (?: R e a c t \. ) ? (?: P u r e ) ? C o m p o n e n t /
9133const refreshContentRE = / \$ R e f r e s h (?: R e g | S i g ) \$ \( /
9234const defaultIncludeRE = / \. [ t j ] s x ? $ /
93- const tsRE = / \. t s x ? $ /
9435
9536export default function viteReact ( opts : Options = { } ) : PluginOption [ ] {
9637 // Provide default values for Rollup compat.
@@ -99,13 +40,7 @@ export default function viteReact(opts: Options = {}): PluginOption[] {
9940 const jsxImportSource = opts . jsxImportSource ?? 'react'
10041 const jsxImportRuntime = `${ jsxImportSource } /jsx-runtime`
10142 const jsxImportDevRuntime = `${ jsxImportSource } /jsx-dev-runtime`
102- let isProduction = true
103- let projectRoot = process . cwd ( )
10443 let skipFastRefresh = false
105- let runPluginOverrides :
106- | ( ( options : ReactBabelOptions , context : ReactBabelHookContext ) => void )
107- | undefined
108- let staticBabelOptions : ReactBabelOptions | undefined
10944
11045 // Support patterns like:
11146 // - import * as React from 'react';
@@ -114,54 +49,27 @@ export default function viteReact(opts: Options = {}): PluginOption[] {
11449 const importReactRE = / \b i m p o r t \s + (?: \* \s + a s \s + ) ? R e a c t \b /
11550
11651 const viteBabel : Plugin = {
117- name : 'vite:react-babel' ,
118- enforce : 'pre' ,
119- config ( ) {
120- if ( opts . jsxRuntime === 'classic' ) {
121- return {
122- esbuild : {
123- jsx : 'transform' ,
124- } ,
125- }
126- } else {
127- return {
128- esbuild : {
129- jsx : 'automatic' ,
130- jsxImportSource : opts . jsxImportSource ,
52+ name : 'vite:react' ,
53+ config ( config , env ) {
54+ const runtime = opts . jsxRuntime ?? 'automatic'
55+ return {
56+ oxc : {
57+ jsx : {
58+ runtime,
59+ importSource : runtime === 'automatic' ? jsxImportSource : undefined ,
60+ refresh : env . command === 'serve' ,
61+ development : env . command === 'serve' ,
13162 } ,
132- optimizeDeps : { esbuildOptions : { jsx : 'automatic' } } ,
133- }
63+ } ,
64+ // optimizeDeps: { esbuildOptions: { jsx: 'automatic' } },
13465 }
13566 } ,
13667 configResolved ( config ) {
13768 devBase = config . base
138- projectRoot = config . root
139- isProduction = config . isProduction
14069 skipFastRefresh =
141- isProduction ||
70+ config . isProduction ||
14271 config . command === 'build' ||
14372 config . server . hmr === false
144-
145- if ( 'jsxPure' in opts ) {
146- config . logger . warnOnce (
147- '[@vitejs/plugin-react] jsxPure was removed. You can configure esbuild.jsxSideEffects directly.' ,
148- )
149- }
150-
151- const hooks : ReactBabelHook [ ] = config . plugins
152- . map ( ( plugin ) => plugin . api ?. reactBabel )
153- . filter ( defined )
154-
155- if ( hooks . length > 0 ) {
156- runPluginOverrides = ( babelOptions , context ) => {
157- hooks . forEach ( ( hook ) => hook ( babelOptions , context , config ) )
158- }
159- } else if ( typeof opts . babel !== 'function' ) {
160- // Because hooks and the callback option can mutate the Babel options
161- // we only create static option in this case and re-create them
162- // each time otherwise
163- staticBabelOptions = createBabelOptions ( opts . babel )
164- }
16573 } ,
16674 async transform ( code , id , options ) {
16775 if ( id . includes ( '/node_modules/' ) ) return
@@ -170,17 +78,6 @@ export default function viteReact(opts: Options = {}): PluginOption[] {
17078 if ( ! filter ( filepath ) ) return
17179
17280 const ssr = options ?. ssr === true
173- const babelOptions = ( ( ) => {
174- if ( staticBabelOptions ) return staticBabelOptions
175- const newBabelOptions = createBabelOptions (
176- typeof opts . babel === 'function'
177- ? opts . babel ( id , { ssr } )
178- : opts . babel ,
179- )
180- runPluginOverrides ?.( newBabelOptions , { id, ssr } )
181- return newBabelOptions
182- } ) ( )
183- const plugins = [ ...babelOptions . plugins ]
18481
18582 const isJSX = filepath . endsWith ( 'x' )
18683 const useFastRefresh =
@@ -191,79 +88,14 @@ export default function viteReact(opts: Options = {}): PluginOption[] {
19188 ? importReactRE . test ( code )
19289 : code . includes ( jsxImportDevRuntime ) ||
19390 code . includes ( jsxImportRuntime ) ) )
194- if ( useFastRefresh ) {
195- plugins . push ( [
196- await loadPlugin ( 'react-refresh/babel' ) ,
197- { skipEnvCheck : true } ,
198- ] )
199- }
200-
201- if ( opts . jsxRuntime === 'classic' && isJSX ) {
202- if ( ! isProduction ) {
203- // These development plugins are only needed for the classic runtime.
204- plugins . push (
205- await loadPlugin ( '@babel/plugin-transform-react-jsx-self' ) ,
206- await loadPlugin ( '@babel/plugin-transform-react-jsx-source' ) ,
207- )
208- }
209- }
210-
211- // Avoid parsing if no special transformation is needed
212- if (
213- ! plugins . length &&
214- ! babelOptions . presets . length &&
215- ! babelOptions . configFile &&
216- ! babelOptions . babelrc
217- ) {
218- return
219- }
220-
221- const parserPlugins = [ ...babelOptions . parserOpts . plugins ]
222-
223- if ( ! filepath . endsWith ( '.ts' ) ) {
224- parserPlugins . push ( 'jsx' )
225- }
226-
227- if ( tsRE . test ( filepath ) ) {
228- parserPlugins . push ( 'typescript' )
229- }
230-
231- const babel = await loadBabel ( )
232- const result = await babel . transformAsync ( code , {
233- ...babelOptions ,
234- root : projectRoot ,
235- filename : id ,
236- sourceFileName : filepath ,
237- // Required for esbuild.jsxDev to provide correct line numbers
238- // This crates issues the react compiler because the re-order is too important
239- // People should use @babel /plugin-transform-react-jsx-development to get back good line numbers
240- retainLines : hasCompiler ( plugins )
241- ? false
242- : ! isProduction && isJSX && opts . jsxRuntime !== 'classic' ,
243- parserOpts : {
244- ...babelOptions . parserOpts ,
245- sourceType : 'module' ,
246- allowAwaitOutsideFunction : true ,
247- plugins : parserPlugins ,
248- } ,
249- generatorOpts : {
250- ...babelOptions . generatorOpts ,
251- decoratorsBeforeExport : true ,
252- } ,
253- plugins,
254- sourceMaps : true ,
255- } )
25691
257- if ( result ) {
258- let code = result . code !
259- if ( useFastRefresh ) {
260- if ( refreshContentRE . test ( code ) ) {
261- code = addRefreshWrapper ( code , id )
262- } else if ( reactCompRE . test ( code ) ) {
263- code = addClassComponentRefreshWrapper ( code , id )
264- }
92+ if ( useFastRefresh ) {
93+ if ( refreshContentRE . test ( code ) ) {
94+ code = addRefreshWrapper ( code , id )
95+ } else if ( reactCompRE . test ( code ) ) {
96+ code = addClassComponentRefreshWrapper ( code , id )
26597 }
266- return { code, map : result . map }
98+ return { code }
26799 }
268100 } ,
269101 }
@@ -272,11 +104,6 @@ export default function viteReact(opts: Options = {}): PluginOption[] {
272104 // for React 18 while it's `react-dom` for React 17. We'd need to detect
273105 // what React version the user has installed.
274106 const dependencies = [ 'react' , jsxImportDevRuntime , jsxImportRuntime ]
275- const staticBabelPlugins =
276- typeof opts . babel === 'object' ? opts . babel ?. plugins ?? [ ] : [ ]
277- if ( hasCompilerWithDefaultRuntime ( staticBabelPlugins ) ) {
278- dependencies . push ( 'react/compiler-runtime' )
279- }
280107
281108 const viteReactRefresh : Plugin = {
282109 name : 'vite:react-refresh' ,
@@ -342,56 +169,3 @@ const silenceUseClientWarning = (userConfig: UserConfig): BuildOptions => ({
342169 } ,
343170 } ,
344171} )
345-
346- const loadedPlugin = new Map < string , any > ( )
347- function loadPlugin ( path : string ) : any {
348- const cached = loadedPlugin . get ( path )
349- if ( cached ) return cached
350-
351- const promise = import ( path ) . then ( ( module ) => {
352- const value = module . default || module
353- loadedPlugin . set ( path , value )
354- return value
355- } )
356- loadedPlugin . set ( path , promise )
357- return promise
358- }
359-
360- function createBabelOptions ( rawOptions ?: BabelOptions ) {
361- const babelOptions = {
362- babelrc : false ,
363- configFile : false ,
364- ...rawOptions ,
365- } as ReactBabelOptions
366-
367- babelOptions . plugins ||= [ ]
368- babelOptions . presets ||= [ ]
369- babelOptions . overrides ||= [ ]
370- babelOptions . parserOpts ||= { } as any
371- babelOptions . parserOpts . plugins ||= [ ]
372-
373- return babelOptions
374- }
375-
376- function defined < T > ( value : T | undefined ) : value is T {
377- return value !== undefined
378- }
379-
380- function hasCompiler ( plugins : ReactBabelOptions [ 'plugins' ] ) {
381- return plugins . some (
382- ( p ) =>
383- p === 'babel-plugin-react-compiler' ||
384- ( Array . isArray ( p ) && p [ 0 ] === 'babel-plugin-react-compiler' ) ,
385- )
386- }
387-
388- // https://gist.github.com/poteto/37c076bf112a07ba39d0e5f0645fec43
389- function hasCompilerWithDefaultRuntime ( plugins : ReactBabelOptions [ 'plugins' ] ) {
390- return plugins . some (
391- ( p ) =>
392- p === 'babel-plugin-react-compiler' ||
393- ( Array . isArray ( p ) &&
394- p [ 0 ] === 'babel-plugin-react-compiler' &&
395- p [ 1 ] ?. runtimeModule === undefined ) ,
396- )
397- }
0 commit comments