@vitejs/plugin-react 5.0.3 → 5.1.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
@@ -102,9 +102,16 @@ react({ reactRefreshHost: 'http://localhost:3000' })
102
102
 
103
103
  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}`.
104
104
 
105
- ## Middleware mode
105
+ ## `@vitejs/plugin-react/preamble`
106
106
 
107
- In [middleware mode](https://vite.dev/config/server-options.html#server-middlewaremode), you should make sure your entry `index.html` file is transformed by Vite. Here's an example for an Express server:
107
+ The package provides `@vitejs/plugin-react/preamble` to initialize HMR runtime from client entrypoint for SSR applications which don't use [`transformIndexHtml` API](https://vite.dev/guide/api-javascript.html#vitedevserver). For example:
108
+
109
+ ```js
110
+ // [entry.client.js]
111
+ import '@vitejs/plugin-react/preamble'
112
+ ```
113
+
114
+ Alternatively, you can manually call `transformIndexHtml` during SSR, which sets up equivalent initialization code. Here's an example for an Express server:
108
115
 
109
116
  ```js
110
117
  app.get('/', async (req, res, next) => {
@@ -121,16 +128,12 @@ app.get('/', async (req, res, next) => {
121
128
  })
122
129
  ```
123
130
 
124
- Otherwise, you'll probably get this error:
131
+ Otherwise, you'll get the following error:
125
132
 
126
133
  ```
127
134
  Uncaught Error: @vitejs/plugin-react can't detect preamble. Something is wrong.
128
135
  ```
129
136
 
130
- ### disableOxcRecommendation
131
-
132
- If set, disables the recommendation to use `@vitejs/plugin-react-oxc` (which is shown when `rolldown-vite` is detected and `babel` is not configured).
133
-
134
137
  ## Consistent components exports
135
138
 
136
139
  For React refresh to work correctly, your file should only export React components. You can find a good explanation in the [Gatsby docs](https://www.gatsbyjs.com/docs/reference/local-development/fast-refresh/#how-it-works).
package/dist/index.js CHANGED
@@ -45,6 +45,27 @@ function $RefreshSig$() { return RefreshRuntime.createSignatureFunctionForTransf
45
45
  `;
46
46
  return newCode;
47
47
  }
48
+ function virtualPreamblePlugin({ name, isEnabled }) {
49
+ return {
50
+ name: "vite:react-virtual-preamble",
51
+ resolveId: {
52
+ order: "pre",
53
+ filter: { id: exactRegex(name) },
54
+ handler(source) {
55
+ if (source === name) return "\0" + source;
56
+ }
57
+ },
58
+ load: {
59
+ filter: { id: exactRegex("\0" + name) },
60
+ handler(id) {
61
+ if (id === "\0" + name) {
62
+ if (isEnabled()) return preambleCode.replace("__BASE__", "/");
63
+ return "";
64
+ }
65
+ }
66
+ }
67
+ };
68
+ }
48
69
 
49
70
  //#endregion
50
71
  //#region ../common/warning.ts
@@ -57,8 +78,7 @@ const silenceUseClientWarning = (userConfig) => ({ rollupOptions: { onwarn(warni
57
78
 
58
79
  //#endregion
59
80
  //#region src/index.ts
60
- const _dirname = dirname(fileURLToPath(import.meta.url));
61
- const refreshRuntimePath = join(_dirname, "refresh-runtime.js");
81
+ const refreshRuntimePath = join(dirname(fileURLToPath(import.meta.url)), "refresh-runtime.js");
62
82
  let babel;
63
83
  async function loadBabel() {
64
84
  if (!babel) babel = await import("@babel/core");
@@ -80,6 +100,8 @@ function viteReact(opts = {}) {
80
100
  let isProduction = true;
81
101
  let projectRoot = process.cwd();
82
102
  let skipFastRefresh = true;
103
+ let base;
104
+ let isFullBundle = false;
83
105
  let runPluginOverrides;
84
106
  let staticBabelOptions;
85
107
  const importReactRE = /\bimport\s+(?:\*\s+as\s+)?React\b/;
@@ -119,6 +141,8 @@ function viteReact(opts = {}) {
119
141
  },
120
142
  configResolved(config) {
121
143
  runningInVite = true;
144
+ base = config.base;
145
+ if (config.experimental.fullBundleMode) isFullBundle = true;
122
146
  projectRoot = config.root;
123
147
  isProduction = config.isProduction;
124
148
  skipFastRefresh = isProduction || config.command === "build" || config.server.hmr === false;
@@ -133,8 +157,9 @@ function viteReact(opts = {}) {
133
157
  },
134
158
  options(options) {
135
159
  if (!runningInVite) {
136
- options.jsx = {
137
- mode: opts.jsxRuntime,
160
+ options.transform ??= {};
161
+ options.transform.jsx = {
162
+ runtime: opts.jsxRuntime,
138
163
  importSource: opts.jsxImportSource
139
164
  };
140
165
  return options;
@@ -214,6 +239,26 @@ function viteReact(opts = {}) {
214
239
  const viteRefreshWrapper = {
215
240
  name: "vite:react:refresh-wrapper",
216
241
  apply: "serve",
242
+ async applyToEnvironment(env) {
243
+ 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({
255
+ cwd: process.cwd(),
256
+ include: makeIdFiltersToMatchWithQuery(include),
257
+ exclude: makeIdFiltersToMatchWithQuery(exclude),
258
+ jsxImportSource,
259
+ reactRefreshHost: opts.reactRefreshHost ?? ""
260
+ });
261
+ },
217
262
  transform: {
218
263
  filter: { id: {
219
264
  include: makeIdFiltersToMatchWithQuery(include),
@@ -239,14 +284,27 @@ function viteReact(opts = {}) {
239
284
  if (userConfig.server?.hmr === false) return { oxc: { jsx: { refresh: false } } };
240
285
  }
241
286
  };
287
+ const viteReactRefreshFullBundleMode = {
288
+ name: "vite:react-refresh-fbm",
289
+ enforce: "pre",
290
+ transformIndexHtml: {
291
+ handler() {
292
+ if (!skipFastRefresh && isFullBundle) return [{
293
+ tag: "script",
294
+ attrs: { type: "module" },
295
+ children: getPreambleCode(base)
296
+ }];
297
+ },
298
+ order: "pre"
299
+ }
300
+ };
242
301
  const dependencies = [
243
302
  "react",
244
303
  "react-dom",
245
304
  jsxImportDevRuntime,
246
305
  jsxImportRuntime
247
306
  ];
248
- const staticBabelPlugins = typeof opts.babel === "object" ? opts.babel?.plugins ?? [] : [];
249
- const reactCompilerPlugin = getReactCompilerPlugin(staticBabelPlugins);
307
+ const reactCompilerPlugin = getReactCompilerPlugin(typeof opts.babel === "object" ? opts.babel?.plugins ?? [] : []);
250
308
  if (reactCompilerPlugin != null) {
251
309
  const reactCompilerRuntimeModule = getReactCompilerRuntimeModule(reactCompilerPlugin);
252
310
  dependencies.push(reactCompilerRuntimeModule);
@@ -270,18 +328,26 @@ function viteReact(opts = {}) {
270
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");
271
329
  }
272
330
  },
273
- transformIndexHtml(_, config) {
274
- if (!skipFastRefresh) return [{
331
+ transformIndexHtml() {
332
+ if (!skipFastRefresh && !isFullBundle) return [{
275
333
  tag: "script",
276
334
  attrs: { type: "module" },
277
- children: getPreambleCode(config.server.config.base)
335
+ children: getPreambleCode(base)
278
336
  }];
279
337
  }
280
338
  };
281
339
  return [
282
340
  viteBabel,
283
- ...isRolldownVite ? [viteRefreshWrapper, viteConfigPost] : [],
284
- viteReactRefresh
341
+ ...isRolldownVite ? [
342
+ viteRefreshWrapper,
343
+ viteConfigPost,
344
+ viteReactRefreshFullBundleMode
345
+ ] : [],
346
+ viteReactRefresh,
347
+ virtualPreamblePlugin({
348
+ name: "@vitejs/plugin-react/preamble",
349
+ isEnabled: () => !skipFastRefresh && !isFullBundle
350
+ })
285
351
  ];
286
352
  }
287
353
  viteReact.preambleCode = preambleCode;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vitejs/plugin-react",
3
- "version": "5.0.3",
3
+ "version": "5.1.0",
4
4
  "license": "MIT",
5
5
  "author": "Evan You",
6
6
  "description": "The default Vite plugin for React projects",
@@ -17,10 +17,14 @@
17
17
  "Arnaud Barré"
18
18
  ],
19
19
  "files": [
20
+ "types",
20
21
  "dist"
21
22
  ],
22
23
  "type": "module",
23
- "exports": "./dist/index.js",
24
+ "exports": {
25
+ ".": "./dist/index.js",
26
+ "./preamble": "./types/preamble.d.ts"
27
+ },
24
28
  "scripts": {
25
29
  "dev": "tsdown --watch ./src --watch ../common",
26
30
  "build": "tsdown",
@@ -43,9 +47,9 @@
43
47
  "@babel/core": "^7.28.4",
44
48
  "@babel/plugin-transform-react-jsx-self": "^7.27.1",
45
49
  "@babel/plugin-transform-react-jsx-source": "^7.27.1",
46
- "@rolldown/pluginutils": "1.0.0-beta.35",
50
+ "@rolldown/pluginutils": "1.0.0-beta.43",
47
51
  "@types/babel__core": "^7.20.5",
48
- "react-refresh": "^0.17.0"
52
+ "react-refresh": "^0.18.0"
49
53
  },
50
54
  "peerDependencies": {
51
55
  "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0"
@@ -53,10 +57,9 @@
53
57
  "devDependencies": {
54
58
  "@vitejs/react-common": "workspace:*",
55
59
  "babel-plugin-react-compiler": "19.1.0-rc.3",
56
- "react": "^19.1.1",
57
- "react-dom": "^19.1.1",
58
- "rolldown": "1.0.0-beta.35",
59
- "tsdown": "^0.14.2",
60
- "vitest": "^3.2.4"
60
+ "react": "^19.2.0",
61
+ "react-dom": "^19.2.0",
62
+ "rolldown": "1.0.0-beta.44",
63
+ "tsdown": "^0.15.8"
61
64
  }
62
65
  }
@@ -0,0 +1 @@
1
+ export {}