@vitejs/plugin-react 5.2.0 → 6.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -4,7 +4,6 @@ The default Vite plugin for React projects.
4
4
 
5
5
  - enable [Fast Refresh](https://www.npmjs.com/package/react-refresh) in development (requires react >= 16.9)
6
6
  - use the [automatic JSX runtime](https://legacy.reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html)
7
- - use custom Babel plugins/presets
8
7
  - small installation size
9
8
 
10
9
  ```js
@@ -68,55 +67,58 @@ By default, the plugin uses the [automatic JSX runtime](https://legacy.reactjs.o
68
67
  react({ jsxRuntime: 'classic' })
69
68
  ```
70
69
 
71
- ### babel
70
+ ### reactRefreshHost
72
71
 
73
- The `babel` option lets you add plugins, presets, and [other configuration](https://babeljs.io/docs/en/options) to the Babel transformation performed on each included file.
72
+ The `reactRefreshHost` option is only necessary in a module federation context. It enables HMR to work between a remote & host application. In your remote Vite config, you would add your host origin:
74
73
 
75
74
  ```js
76
- react({
77
- babel: {
78
- presets: [...],
79
- // Your plugins run before any built-in transform (eg: Fast Refresh)
80
- plugins: [...],
81
- // Use .babelrc files
82
- babelrc: true,
83
- // Use babel.config.js files
84
- configFile: true,
85
- }
86
- })
75
+ react({ reactRefreshHost: 'http://localhost:3000' })
87
76
  ```
88
77
 
89
- Note: When not using plugins, only esbuild is used for production builds, resulting in faster builds.
78
+ Under the hood, this simply updates the React Fash Refresh runtime URL from `/@react-refresh` to `http://localhost:3000/@react-refresh` to ensure there is only one Refresh runtime across the whole application. Note that if you define `base` option in the host application, you need to include it in the option, like: `http://localhost:3000/{base}`.
90
79
 
91
- #### Proposed syntax
80
+ ## React Compiler
92
81
 
93
- If you are using ES syntax that are still in proposal status (e.g. class properties), you can selectively enable them with the `babel.parserOpts.plugins` option:
82
+ [React Compiler](https://react.dev/learn/react-compiler) support is available via the exported `reactCompilerPreset` helper, which requires [`@rolldown/plugin-babel`](https://npmx.dev/package/@rolldown/plugin-babel) and [`babel-plugin-react-compiler`](https://npmx.dev/package/babel-plugin-react-compiler) as peer dependencies:
94
83
 
95
- ```js
96
- react({
97
- babel: {
98
- parserOpts: {
99
- plugins: ['decorators-legacy'],
100
- },
101
- },
102
- })
84
+ ```sh
85
+ npm install -D @rolldown/plugin-babel babel-plugin-react-compiler
103
86
  ```
104
87
 
105
- This option does not enable _code transformation_. That is handled by esbuild.
106
-
107
- **Note:** TypeScript syntax is handled automatically.
88
+ ```js
89
+ // vite.config.js
90
+ import { defineConfig } from 'vite'
91
+ import react, { reactCompilerPreset } from '@vitejs/plugin-react'
92
+ import babel from '@rolldown/plugin-babel'
108
93
 
109
- Here's the [complete list of Babel parser plugins](https://babeljs.io/docs/en/babel-parser#ecmascript-proposalshttpsgithubcombabelproposals).
94
+ export default defineConfig({
95
+ plugins: [react(), babel({ presets: [reactCompilerPreset()] })],
96
+ })
97
+ ```
110
98
 
111
- ### reactRefreshHost
99
+ The `reactCompilerPreset` accepts an optional options object with the following properties:
112
100
 
113
- The `reactRefreshHost` option is only necessary in a module federation context. It enables HMR to work between a remote & host application. In your remote Vite config, you would add your host origin:
101
+ - `compilationMode` Set to `'annotation'` to only compile components annotated with `"use memo"`.
102
+ - `target` — Set to `'17'` or `'18'` to target older React versions (uses `react-compiler-runtime` instead of `react/compiler-runtime`).
114
103
 
115
104
  ```js
116
- react({ reactRefreshHost: 'http://localhost:3000' })
105
+ babel({
106
+ presets: [reactCompilerPreset({ compilationMode: 'annotation' })],
107
+ })
117
108
  ```
118
109
 
119
- Under the hood, this simply updates the React Fash Refresh runtime URL from `/@react-refresh` to `http://localhost:3000/@react-refresh` to ensure there is only one Refresh runtime across the whole application. Note that if you define `base` option in the host application, you need to include it in the option, like: `http://localhost:3000/{base}`.
110
+ > [!TIP]
111
+ >
112
+ > `reactCompilerPreset` is only a convenient helper with a preconfigured filter. You can configure override the filters to fit your project structure or code. For example, if you know a large portion of your files are never React/hook-related or won't benefit from the React Compiler, you can aggressively exclude them via `rolldown.filter`:
113
+ >
114
+ > ```js
115
+ > const myPreset = reactCompilerPreset()
116
+ > myPreset.rolldown.filter.id.exclude = ['src/legacy/**', 'src/utils/**']
117
+ >
118
+ > babel({
119
+ > presets: [myPreset],
120
+ > })
121
+ > ```
120
122
 
121
123
  ## `@vitejs/plugin-react/preamble`
122
124
 
@@ -156,4 +158,4 @@ For React refresh to work correctly, your file should only export React componen
156
158
 
157
159
  If an incompatible change in exports is found, the module will be invalidated and HMR will propagate. To make it easier to export simple constants alongside your component, the module is only invalidated when their value changes.
158
160
 
159
- You can catch mistakes and get more detailed warning with this [eslint rule](https://github.com/ArnaudBarre/eslint-plugin-react-refresh).
161
+ You can catch mistakes and get more detailed warnings with this [ESLint rule](https://github.com/ArnaudBarre/eslint-plugin-react-refresh), or the equivalent [Oxlint rule](https://oxc.rs/docs/guide/usage/linter/rules/react/only-export-components.html).
package/dist/index.d.ts CHANGED
@@ -1,6 +1,9 @@
1
- import { Plugin, ResolvedConfig } from "vite";
2
- import { ParserOptions, TransformOptions } from "@babel/core";
1
+ import { Plugin } from "vite";
2
+ import { ReactCompilerBabelPluginOptions, RolldownBabelPreset } from "#optionalTypes";
3
3
 
4
+ //#region src/reactCompilerPreset.d.ts
5
+ declare const reactCompilerPreset: (options?: Pick<ReactCompilerBabelPluginOptions, "compilationMode" | "target">) => RolldownBabelPreset;
6
+ //#endregion
4
7
  //#region src/index.d.ts
5
8
  interface Options {
6
9
  /**
@@ -18,7 +21,7 @@ interface Options {
18
21
  exclude?: string | RegExp | Array<string | RegExp>;
19
22
  /**
20
23
  * Control where the JSX factory is imported from.
21
- * https://esbuild.github.io/api/#jsx-import-source
24
+ * https://oxc.rs/docs/guide/usage/transformer/jsx.html#import-source
22
25
  * @default 'react'
23
26
  */
24
27
  jsxImportSource?: string;
@@ -27,12 +30,6 @@ interface Options {
27
30
  * @default "automatic"
28
31
  */
29
32
  jsxRuntime?: 'classic' | 'automatic';
30
- /**
31
- * Babel configuration applied in both dev and prod.
32
- */
33
- babel?: BabelOptions | ((id: string, options: {
34
- ssr?: boolean;
35
- }) => BabelOptions);
36
33
  /**
37
34
  * React Fast Refresh runtime URL prefix.
38
35
  * Useful in a module federation context to enable HMR by specifying
@@ -42,34 +39,10 @@ interface Options {
42
39
  */
43
40
  reactRefreshHost?: string;
44
41
  }
45
- type BabelOptions = Omit<TransformOptions, 'ast' | 'filename' | 'root' | 'sourceFileName' | 'sourceMaps' | 'inputSourceMap'>;
46
- /**
47
- * The object type used by the `options` passed to plugins with
48
- * an `api.reactBabel` method.
49
- */
50
- interface ReactBabelOptions extends BabelOptions {
51
- plugins: Extract<BabelOptions['plugins'], any[]>;
52
- presets: Extract<BabelOptions['presets'], any[]>;
53
- overrides: Extract<BabelOptions['overrides'], any[]>;
54
- parserOpts: ParserOptions & {
55
- plugins: Extract<ParserOptions['plugins'], any[]>;
56
- };
57
- }
58
- type ReactBabelHook = (babelConfig: ReactBabelOptions, context: ReactBabelHookContext, config: ResolvedConfig) => void;
59
- type ReactBabelHookContext = {
60
- ssr: boolean;
61
- id: string;
62
- };
63
- type ViteReactPluginApi = {
64
- /**
65
- * Manipulate the Babel options of `@vitejs/plugin-react`
66
- */
67
- reactBabel?: ReactBabelHook;
68
- };
69
42
  declare function viteReact(opts?: Options): Plugin[];
70
43
  declare namespace viteReact {
71
44
  var preambleCode: string;
72
45
  }
73
46
  declare function viteReactForCjs(this: unknown, options: Options): Plugin[];
74
47
  //#endregion
75
- export { BabelOptions, Options, ReactBabelOptions, ViteReactPluginApi, viteReact as default, viteReactForCjs as "module.exports" };
48
+ export { Options, viteReact as default, viteReactForCjs as "module.exports", reactCompilerPreset };
package/dist/index.js CHANGED
@@ -2,49 +2,14 @@ import { readFileSync } from "node:fs";
2
2
  import { dirname, join } from "node:path";
3
3
  import { fileURLToPath } from "node:url";
4
4
  import { exactRegex, makeIdFiltersToMatchWithQuery } from "@rolldown/pluginutils";
5
- import * as vite from "vite";
6
- import { createFilter } from "vite";
7
-
5
+ import { reactRefreshWrapperPlugin } from "vite/internal";
8
6
  //#region ../common/refresh-utils.ts
9
7
  const runtimePublicPath = "/@react-refresh";
10
- const reactCompRE = /extends\s+(?:React\.)?(?:Pure)?Component/;
11
- const refreshContentRE = /\$RefreshReg\$\(/;
12
8
  const preambleCode = `import { injectIntoGlobalHook } from "__BASE__${runtimePublicPath.slice(1)}";
13
9
  injectIntoGlobalHook(window);
14
10
  window.$RefreshReg$ = () => {};
15
11
  window.$RefreshSig$ = () => (type) => type;`;
16
12
  const getPreambleCode = (base) => preambleCode.replace("__BASE__", base);
17
- function addRefreshWrapper(code, pluginName, id, reactRefreshHost = "") {
18
- const hasRefresh = refreshContentRE.test(code);
19
- const onlyReactComp = !hasRefresh && reactCompRE.test(code);
20
- if (!hasRefresh && !onlyReactComp) return void 0;
21
- let newCode = code;
22
- newCode += `
23
-
24
- import * as RefreshRuntime from "${reactRefreshHost}${runtimePublicPath}";
25
- const inWebWorker = typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope;
26
- if (import.meta.hot && !inWebWorker) {
27
- if (!window.$RefreshReg$) {
28
- throw new Error(
29
- "${pluginName} can't detect preamble. Something is wrong."
30
- );
31
- }
32
-
33
- RefreshRuntime.__hmr_import(import.meta.url).then((currentExports) => {
34
- RefreshRuntime.registerExportsForReactRefresh(${JSON.stringify(id)}, currentExports);
35
- import.meta.hot.accept((nextExports) => {
36
- if (!nextExports) return;
37
- const invalidateMessage = RefreshRuntime.validateRefreshBoundaryAndEnqueueUpdate(${JSON.stringify(id)}, currentExports, nextExports);
38
- if (invalidateMessage) import.meta.hot.invalidate(invalidateMessage);
39
- });
40
- });
41
- }
42
- `;
43
- if (hasRefresh) newCode += `function $RefreshReg$(type, id) { return RefreshRuntime.register(type, ${JSON.stringify(id)} + ' ' + id) }
44
- function $RefreshSig$() { return RefreshRuntime.createSignatureFunctionForTransform(); }
45
- `;
46
- return newCode;
47
- }
48
13
  function virtualPreamblePlugin({ name, isEnabled }) {
49
14
  return {
50
15
  name: "vite:react-virtual-preamble",
@@ -66,7 +31,6 @@ function virtualPreamblePlugin({ name, isEnabled }) {
66
31
  }
67
32
  };
68
33
  }
69
-
70
34
  //#endregion
71
35
  //#region ../common/warning.ts
72
36
  const silenceUseClientWarning = (userConfig) => ({ rollupOptions: { onwarn(warning, defaultHandler) {
@@ -75,45 +39,40 @@ const silenceUseClientWarning = (userConfig) => ({ rollupOptions: { onwarn(warni
75
39
  if (userConfig.build?.rollupOptions?.onwarn) userConfig.build.rollupOptions.onwarn(warning, defaultHandler);
76
40
  else defaultHandler(warning);
77
41
  } } });
78
-
42
+ //#endregion
43
+ //#region src/reactCompilerPreset.ts
44
+ const reactCompilerPreset = (options = {}) => ({
45
+ preset: () => ({ plugins: [["babel-plugin-react-compiler", options]] }),
46
+ rolldown: {
47
+ filter: { code: options.compilationMode === "annotation" ? /['"]use memo['"]/ : /\b[A-Z]|\buse/ },
48
+ applyToEnvironmentHook: (env) => env.config.consumer === "client",
49
+ optimizeDeps: { include: options.target === "17" || options.target === "18" ? ["react-compiler-runtime"] : ["react/compiler-runtime"] }
50
+ }
51
+ });
79
52
  //#endregion
80
53
  //#region src/index.ts
81
54
  const refreshRuntimePath = join(dirname(fileURLToPath(import.meta.url)), "refresh-runtime.js");
82
- let babel;
83
- async function loadBabel() {
84
- if (!babel) babel = await import("@babel/core");
85
- return babel;
86
- }
87
55
  const defaultIncludeRE = /\.[tj]sx?$/;
88
56
  const defaultExcludeRE = /\/node_modules\//;
89
- const tsRE = /\.tsx?$/;
90
- const compilerAnnotationRE = /['"]use memo['"]/;
91
57
  function viteReact(opts = {}) {
92
58
  const include = opts.include ?? defaultIncludeRE;
93
59
  const exclude = opts.exclude ?? defaultExcludeRE;
94
- const filter = createFilter(include, exclude);
95
60
  const jsxImportSource = opts.jsxImportSource ?? "react";
96
61
  const jsxImportRuntime = `${jsxImportSource}/jsx-runtime`;
97
62
  const jsxImportDevRuntime = `${jsxImportSource}/jsx-dev-runtime`;
98
- const isRolldownVite = "rolldownVersion" in vite;
99
63
  let runningInVite = false;
100
64
  let isProduction = true;
101
- let projectRoot = process.cwd();
102
65
  let skipFastRefresh = true;
103
66
  let base;
104
67
  let isBundledDev = false;
105
- let runPluginOverrides;
106
- let staticBabelOptions;
107
- const importReactRE = /\bimport\s+(?:\*\s+as\s+)?React\b/;
108
68
  const viteBabel = {
109
69
  name: "vite:react-babel",
110
70
  enforce: "pre",
111
71
  config(_userConfig, { command }) {
112
- if ("rolldownVersion" in vite) if (opts.jsxRuntime === "classic") return { oxc: {
72
+ if (opts.jsxRuntime === "classic") return { oxc: {
113
73
  jsx: {
114
74
  runtime: "classic",
115
- refresh: command === "serve",
116
- development: false
75
+ refresh: command === "serve"
117
76
  },
118
77
  jsxRefreshInclude: makeIdFiltersToMatchWithQuery(include),
119
78
  jsxRefreshExclude: makeIdFiltersToMatchWithQuery(exclude)
@@ -130,30 +89,13 @@ function viteReact(opts = {}) {
130
89
  },
131
90
  optimizeDeps: { rolldownOptions: { transform: { jsx: { runtime: "automatic" } } } }
132
91
  };
133
- if (opts.jsxRuntime === "classic") return { esbuild: { jsx: "transform" } };
134
- else return {
135
- esbuild: {
136
- jsx: "automatic",
137
- jsxImportSource: opts.jsxImportSource
138
- },
139
- optimizeDeps: { esbuildOptions: { jsx: "automatic" } }
140
- };
141
92
  },
142
93
  configResolved(config) {
143
94
  runningInVite = true;
144
95
  base = config.base;
145
96
  if (config.experimental.bundledDev) isBundledDev = true;
146
- projectRoot = config.root;
147
97
  isProduction = config.isProduction;
148
98
  skipFastRefresh = isProduction || config.command === "build" || config.server.hmr === false;
149
- const hooks = config.plugins.map((plugin) => plugin.api?.reactBabel).filter(defined);
150
- if (hooks.length > 0) runPluginOverrides = (babelOptions, context) => {
151
- hooks.forEach((hook) => hook(babelOptions, context, config));
152
- };
153
- else if (typeof opts.babel !== "function") {
154
- staticBabelOptions = createBabelOptions(opts.babel);
155
- if ((isRolldownVite || skipFastRefresh) && canSkipBabel(staticBabelOptions.plugins, staticBabelOptions) && (opts.jsxRuntime === "classic" ? isProduction : true)) delete viteBabel.transform;
156
- }
157
99
  },
158
100
  options(options) {
159
101
  if (!runningInVite) {
@@ -164,76 +106,6 @@ function viteReact(opts = {}) {
164
106
  };
165
107
  return options;
166
108
  }
167
- },
168
- transform: {
169
- filter: { id: {
170
- include: makeIdFiltersToMatchWithQuery(include),
171
- exclude: makeIdFiltersToMatchWithQuery(exclude)
172
- } },
173
- async handler(code, id, options) {
174
- const [filepath] = id.split("?");
175
- if (!filter(filepath)) return;
176
- const ssr = options?.ssr === true;
177
- const babelOptions = (() => {
178
- if (staticBabelOptions) return staticBabelOptions;
179
- const newBabelOptions = createBabelOptions(typeof opts.babel === "function" ? opts.babel(id, { ssr }) : opts.babel);
180
- runPluginOverrides?.(newBabelOptions, {
181
- id,
182
- ssr
183
- });
184
- return newBabelOptions;
185
- })();
186
- const plugins = [...babelOptions.plugins];
187
- let reactCompilerPlugin = getReactCompilerPlugin(plugins);
188
- if (reactCompilerPlugin && ssr) {
189
- plugins.splice(plugins.indexOf(reactCompilerPlugin), 1);
190
- reactCompilerPlugin = void 0;
191
- }
192
- if (Array.isArray(reactCompilerPlugin) && reactCompilerPlugin[1]?.compilationMode === "annotation" && !compilerAnnotationRE.test(code)) {
193
- plugins.splice(plugins.indexOf(reactCompilerPlugin), 1);
194
- reactCompilerPlugin = void 0;
195
- }
196
- const isJSX = filepath.endsWith("x");
197
- const useFastRefresh = !(isRolldownVite || skipFastRefresh) && !ssr && (isJSX || (opts.jsxRuntime === "classic" ? importReactRE.test(code) : code.includes(jsxImportDevRuntime) || code.includes(jsxImportRuntime)));
198
- if (useFastRefresh) plugins.push([await loadPlugin("react-refresh/babel"), { skipEnvCheck: true }]);
199
- if (opts.jsxRuntime === "classic" && isJSX) {
200
- if (!isProduction) plugins.push(await loadPlugin("@babel/plugin-transform-react-jsx-self"), await loadPlugin("@babel/plugin-transform-react-jsx-source"));
201
- }
202
- if (canSkipBabel(plugins, babelOptions)) return;
203
- const parserPlugins = [...babelOptions.parserOpts.plugins];
204
- if (!filepath.endsWith(".ts")) parserPlugins.push("jsx");
205
- if (tsRE.test(filepath)) parserPlugins.push("typescript");
206
- const result = await (await loadBabel()).transformAsync(code, {
207
- ...babelOptions,
208
- root: projectRoot,
209
- filename: id,
210
- sourceFileName: filepath,
211
- retainLines: reactCompilerPlugin ? false : !isProduction && isJSX && opts.jsxRuntime !== "classic",
212
- parserOpts: {
213
- ...babelOptions.parserOpts,
214
- sourceType: "module",
215
- allowAwaitOutsideFunction: true,
216
- plugins: parserPlugins
217
- },
218
- generatorOpts: {
219
- ...babelOptions.generatorOpts,
220
- importAttributesKeyword: "with",
221
- decoratorsBeforeExport: true
222
- },
223
- plugins,
224
- sourceMaps: true
225
- });
226
- if (result) {
227
- if (!useFastRefresh) return {
228
- code: result.code,
229
- map: result.map
230
- };
231
- return {
232
- code: addRefreshWrapper(result.code, "@vitejs/plugin-react", id, opts.reactRefreshHost) ?? result.code,
233
- map: result.map
234
- };
235
- }
236
- }
237
109
  }
238
110
  };
239
111
  const viteRefreshWrapper = {
@@ -241,40 +113,13 @@ function viteReact(opts = {}) {
241
113
  apply: "serve",
242
114
  async applyToEnvironment(env) {
243
115
  if (env.config.consumer !== "client" || skipFastRefresh) return false;
244
- let nativePlugin;
245
- try {
246
- nativePlugin = (await import("vite/internal")).reactRefreshWrapperPlugin;
247
- } catch {}
248
- if (!nativePlugin || [
249
- "7.1.10",
250
- "7.1.11",
251
- "7.1.12"
252
- ].includes(vite.version)) return true;
253
- delete viteRefreshWrapper.transform;
254
- return nativePlugin({
116
+ return reactRefreshWrapperPlugin({
255
117
  cwd: process.cwd(),
256
118
  include: makeIdFiltersToMatchWithQuery(include),
257
119
  exclude: makeIdFiltersToMatchWithQuery(exclude),
258
120
  jsxImportSource,
259
121
  reactRefreshHost: opts.reactRefreshHost ?? ""
260
122
  });
261
- },
262
- transform: {
263
- filter: { id: {
264
- include: makeIdFiltersToMatchWithQuery(include),
265
- exclude: makeIdFiltersToMatchWithQuery(exclude)
266
- } },
267
- handler(code, id, options) {
268
- const ssr = options?.ssr === true;
269
- const [filepath] = id.split("?");
270
- const isJSX = filepath.endsWith("x");
271
- if (!(!skipFastRefresh && !ssr && (isJSX || code.includes(jsxImportDevRuntime) || code.includes(jsxImportRuntime)))) return;
272
- const newCode = addRefreshWrapper(code, "@vitejs/plugin-react", id, opts.reactRefreshHost);
273
- return newCode ? {
274
- code: newCode,
275
- map: null
276
- } : void 0;
277
- }
278
123
  }
279
124
  };
280
125
  const viteConfigPost = {
@@ -304,46 +149,38 @@ function viteReact(opts = {}) {
304
149
  jsxImportDevRuntime,
305
150
  jsxImportRuntime
306
151
  ];
307
- const reactCompilerPlugin = getReactCompilerPlugin(typeof opts.babel === "object" ? opts.babel?.plugins ?? [] : []);
308
- if (reactCompilerPlugin != null) {
309
- const reactCompilerRuntimeModule = getReactCompilerRuntimeModule(reactCompilerPlugin);
310
- dependencies.push(reactCompilerRuntimeModule);
311
- }
312
- const viteReactRefresh = {
313
- name: "vite:react-refresh",
314
- enforce: "pre",
315
- config: (userConfig) => ({
316
- build: silenceUseClientWarning(userConfig),
317
- optimizeDeps: { include: dependencies }
318
- }),
319
- resolveId: {
320
- filter: { id: exactRegex(runtimePublicPath) },
321
- handler(id) {
322
- if (id === runtimePublicPath) return id;
323
- }
324
- },
325
- load: {
326
- filter: { id: exactRegex(runtimePublicPath) },
327
- handler(id) {
328
- if (id === runtimePublicPath) return readFileSync(refreshRuntimePath, "utf-8").replace(/__README_URL__/g, "https://github.com/vitejs/vite-plugin-react/tree/main/packages/plugin-react");
329
- }
330
- },
331
- transformIndexHtml() {
332
- if (!skipFastRefresh && !isBundledDev) return [{
333
- tag: "script",
334
- attrs: { type: "module" },
335
- children: getPreambleCode(base)
336
- }];
337
- }
338
- };
339
152
  return [
340
153
  viteBabel,
341
- ...isRolldownVite ? [
342
- viteRefreshWrapper,
343
- viteConfigPost,
344
- viteReactRefreshBundledDevMode
345
- ] : [],
346
- viteReactRefresh,
154
+ viteRefreshWrapper,
155
+ viteConfigPost,
156
+ viteReactRefreshBundledDevMode,
157
+ {
158
+ name: "vite:react-refresh",
159
+ enforce: "pre",
160
+ config: (userConfig) => ({
161
+ build: silenceUseClientWarning(userConfig),
162
+ optimizeDeps: { include: dependencies }
163
+ }),
164
+ resolveId: {
165
+ filter: { id: exactRegex(runtimePublicPath) },
166
+ handler(id) {
167
+ if (id === "/@react-refresh") return id;
168
+ }
169
+ },
170
+ load: {
171
+ filter: { id: exactRegex(runtimePublicPath) },
172
+ handler(id) {
173
+ if (id === "/@react-refresh") return readFileSync(refreshRuntimePath, "utf-8").replace(/__README_URL__/g, "https://github.com/vitejs/vite-plugin-react/tree/main/packages/plugin-react");
174
+ }
175
+ },
176
+ transformIndexHtml() {
177
+ if (!skipFastRefresh && !isBundledDev) return [{
178
+ tag: "script",
179
+ attrs: { type: "module" },
180
+ children: getPreambleCode(base)
181
+ }];
182
+ }
183
+ },
347
184
  virtualPreamblePlugin({
348
185
  name: "@vitejs/plugin-react/preamble",
349
186
  isEnabled: () => !skipFastRefresh && !isBundledDev
@@ -354,48 +191,9 @@ viteReact.preambleCode = preambleCode;
354
191
  function viteReactForCjs(options) {
355
192
  return viteReact.call(this, options);
356
193
  }
357
- Object.assign(viteReactForCjs, { default: viteReactForCjs });
358
- function canSkipBabel(plugins, babelOptions) {
359
- return !(plugins.length || babelOptions.presets.length || babelOptions.overrides.length || babelOptions.configFile || babelOptions.babelrc);
360
- }
361
- const loadedPlugin = /* @__PURE__ */ new Map();
362
- function loadPlugin(path) {
363
- const cached = loadedPlugin.get(path);
364
- if (cached) return cached;
365
- const promise = import(path).then((module) => {
366
- const value = module.default || module;
367
- loadedPlugin.set(path, value);
368
- return value;
369
- });
370
- loadedPlugin.set(path, promise);
371
- return promise;
372
- }
373
- function createBabelOptions(rawOptions) {
374
- const babelOptions = {
375
- babelrc: false,
376
- configFile: false,
377
- ...rawOptions
378
- };
379
- babelOptions.plugins ||= [];
380
- babelOptions.presets ||= [];
381
- babelOptions.overrides ||= [];
382
- babelOptions.parserOpts ||= {};
383
- babelOptions.parserOpts.plugins ||= [];
384
- return babelOptions;
385
- }
386
- function defined(value) {
387
- return value !== void 0;
388
- }
389
- function getReactCompilerPlugin(plugins) {
390
- return plugins.find((p) => p === "babel-plugin-react-compiler" || Array.isArray(p) && p[0] === "babel-plugin-react-compiler");
391
- }
392
- function getReactCompilerRuntimeModule(plugin) {
393
- let moduleName = "react/compiler-runtime";
394
- if (Array.isArray(plugin)) {
395
- if (plugin[1]?.target === "17" || plugin[1]?.target === "18") moduleName = "react-compiler-runtime";
396
- }
397
- return moduleName;
398
- }
399
-
194
+ Object.assign(viteReactForCjs, {
195
+ default: viteReactForCjs,
196
+ reactCompilerPreset
197
+ });
400
198
  //#endregion
401
- export { viteReact as default, viteReactForCjs as "module.exports" };
199
+ export { viteReact as default, viteReactForCjs as "module.exports", reactCompilerPreset };
package/package.json CHANGED
@@ -1,9 +1,8 @@
1
1
  {
2
2
  "name": "@vitejs/plugin-react",
3
- "version": "5.2.0",
3
+ "version": "6.0.0",
4
4
  "description": "The default Vite plugin for React projects",
5
5
  "keywords": [
6
- "babel",
7
6
  "fast refresh",
8
7
  "react",
9
8
  "react-refresh",
@@ -30,6 +29,9 @@
30
29
  "types"
31
30
  ],
32
31
  "type": "module",
32
+ "imports": {
33
+ "#optionalTypes": "./types/optionalTypes.d.ts"
34
+ },
33
35
  "exports": {
34
36
  ".": "./dist/index.js",
35
37
  "./preamble": "./types/preamble.d.ts"
@@ -41,23 +43,31 @@
41
43
  "test-unit": "vitest run"
42
44
  },
43
45
  "dependencies": {
44
- "@babel/core": "^7.29.0",
45
- "@babel/plugin-transform-react-jsx-self": "^7.27.1",
46
- "@babel/plugin-transform-react-jsx-source": "^7.27.1",
47
- "@rolldown/pluginutils": "1.0.0-rc.3",
48
- "@types/babel__core": "^7.20.5",
49
- "react-refresh": "^0.18.0"
46
+ "@rolldown/pluginutils": "1.0.0-rc.7"
50
47
  },
51
48
  "devDependencies": {
49
+ "@babel/core": "8.0.0-rc.2",
50
+ "@rolldown/plugin-babel": "^0.2.0",
52
51
  "@vitejs/react-common": "workspace:*",
53
- "babel-plugin-react-compiler": "19.1.0-rc.3",
52
+ "babel-plugin-react-compiler": "^1.0.0",
54
53
  "react": "^19.2.4",
55
54
  "react-dom": "^19.2.4",
56
- "rolldown": "1.0.0-rc.3",
57
- "tsdown": "^0.20.3"
55
+ "rolldown": "1.0.0-rc.7",
56
+ "tsdown": "^0.21.0",
57
+ "vite": "^8.0.0-beta.16"
58
58
  },
59
59
  "peerDependencies": {
60
- "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0"
60
+ "@rolldown/plugin-babel": "^0.1.7",
61
+ "babel-plugin-react-compiler": "^1.0.0",
62
+ "vite": "^8.0.0"
63
+ },
64
+ "peerDependenciesMeta": {
65
+ "@rolldown/plugin-babel": {
66
+ "optional": true
67
+ },
68
+ "babel-plugin-react-compiler": {
69
+ "optional": true
70
+ }
61
71
  },
62
72
  "engines": {
63
73
  "node": "^20.19.0 || >=22.12.0"
@@ -0,0 +1,12 @@
1
+ /* eslint-disable @typescript-eslint/ban-ts-comment */
2
+
3
+ // @ts-ignore --- `@rolldown/plugin-babel` is an optional peer dependency, so this may cause an error
4
+ import type * as pluginBabel from '@rolldown/plugin-babel'
5
+ // @ts-ignore --- `babel-plugin-react-compiler` is an optional peer dependency, so this may cause an error
6
+ import type * as babelPluginReactCompiler from 'babel-plugin-react-compiler'
7
+
8
+ // @ts-ignore --- `@rolldown/plugin-babel` is an optional peer dependency, so this may cause an error
9
+ export type RolldownBabelPreset = pluginBabel.RolldownBabelPreset
10
+ // @ts-ignore --- `babel-plugin-react-compiler` is an optional peer dependency, so this may cause an error
11
+ export type ReactCompilerBabelPluginOptions =
12
+ babelPluginReactCompiler.PluginOptions