Skip to content

Commit 3fdb1dc

Browse files
committed
feat: using oxc transfomer
1 parent 63b2e38 commit 3fdb1dc

File tree

20 files changed

+515
-383
lines changed

20 files changed

+515
-383
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@
5353
"simple-git-hooks": "^2.11.1",
5454
"tsx": "^4.19.1",
5555
"typescript": "^5.6.2",
56-
"vite": "^5.4.8",
56+
"rolldown-vite": "https://pkg.pr.new/rolldown/vite@43",
5757
"vitest": "^2.1.1"
5858
},
5959
"simple-git-hooks": {

packages/plugin-react/package.json

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,10 @@
3838
},
3939
"homepage": "https://github.com/vitejs/vite-plugin-react/tree/main/packages/plugin-react#readme",
4040
"dependencies": {
41-
"@babel/core": "^7.25.2",
42-
"@babel/plugin-transform-react-jsx-self": "^7.24.7",
43-
"@babel/plugin-transform-react-jsx-source": "^7.24.7",
44-
"@types/babel__core": "^7.20.5",
4541
"react-refresh": "^0.14.2"
4642
},
4743
"peerDependencies": {
48-
"vite": "^4.2.0 || ^5.0.0"
44+
"rolldown-vite": "https://pkg.pr.new/rolldown/vite@43"
4945
},
5046
"devDependencies": {
5147
"unbuild": "^2.0.0"

packages/plugin-react/src/babel.d.ts

Lines changed: 0 additions & 3 deletions
This file was deleted.

packages/plugin-react/src/index.ts

Lines changed: 21 additions & 247 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,10 @@
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'
62
import type {
73
BuildOptions,
84
Plugin,
95
PluginOption,
10-
ResolvedConfig,
116
UserConfig,
12-
} from 'vite'
7+
} from 'rolldown-vite'
138
import {
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-
3016
export 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

9032
const reactCompRE = /extends\s+(?:React\.)?(?:Pure)?Component/
9133
const refreshContentRE = /\$Refresh(?:Reg|Sig)\$\(/
9234
const defaultIncludeRE = /\.[tj]sx?$/
93-
const tsRE = /\.tsx?$/
9435

9536
export 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 = /\bimport\s+(?:\*\s+as\s+)?React\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-
}

playground/class-components/vite.config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { defineConfig } from 'vite'
1+
import { defineConfig } from 'rolldown-vite'
22
import react from '@vitejs/plugin-react'
33

44
export default defineConfig({

0 commit comments

Comments
 (0)