@vitejs/plugin-react 4.2.0 → 4.3.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
@@ -2,7 +2,7 @@
2
2
 
3
3
  The default Vite plugin for React projects.
4
4
 
5
- - enable [Fast Refresh](https://www.npmjs.com/package/react-refresh) in development
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
7
  - use custom Babel plugins/presets
8
8
  - small installation size
@@ -46,7 +46,7 @@ Control where the JSX factory is imported from. Default to `'react'`
46
46
  react({ jsxImportSource: '@emotion/react' })
47
47
  ```
48
48
 
49
- ## jsxRuntime
49
+ ### jsxRuntime
50
50
 
51
51
  By default, the plugin uses the [automatic JSX runtime](https://legacy.reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html). However, if you encounter any issues, you may opt out using the `jsxRuntime` option.
52
52
 
package/dist/index.cjs CHANGED
@@ -33,10 +33,12 @@ window.$RefreshReg$ = () => {}
33
33
  window.$RefreshSig$ = () => (type) => type
34
34
  window.__vite_plugin_react_preamble_installed__ = true
35
35
  `;
36
- const header = `
36
+ const sharedHeader = `
37
37
  import RefreshRuntime from "${runtimePublicPath}";
38
38
 
39
39
  const inWebWorker = typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope;
40
+ `.replace(/\n+/g, "");
41
+ const functionHeader = `
40
42
  let prevRefreshReg;
41
43
  let prevRefreshSig;
42
44
 
@@ -55,11 +57,13 @@ if (import.meta.hot && !inWebWorker) {
55
57
  };
56
58
  window.$RefreshSig$ = RefreshRuntime.createSignatureFunctionForTransform;
57
59
  }`.replace(/\n+/g, "");
58
- const footer = `
60
+ const functionFooter = `
59
61
  if (import.meta.hot && !inWebWorker) {
60
62
  window.$RefreshReg$ = prevRefreshReg;
61
63
  window.$RefreshSig$ = prevRefreshSig;
62
-
64
+ }`;
65
+ const sharedFooter = `
66
+ if (import.meta.hot && !inWebWorker) {
63
67
  RefreshRuntime.__hmr_import(import.meta.url).then((currentExports) => {
64
68
  RefreshRuntime.registerExportsForReactRefresh(__SOURCE__, currentExports);
65
69
  import.meta.hot.accept((nextExports) => {
@@ -70,7 +74,10 @@ if (import.meta.hot && !inWebWorker) {
70
74
  });
71
75
  }`;
72
76
  function addRefreshWrapper(code, id) {
73
- return header.replace("__SOURCE__", JSON.stringify(id)) + code + footer.replace("__SOURCE__", JSON.stringify(id));
77
+ return sharedHeader + functionHeader.replace("__SOURCE__", JSON.stringify(id)) + code + functionFooter + sharedFooter.replace("__SOURCE__", JSON.stringify(id));
78
+ }
79
+ function addClassComponentRefreshWrapper(code, id) {
80
+ return sharedHeader + code + sharedFooter.replace("__SOURCE__", JSON.stringify(id));
74
81
  }
75
82
 
76
83
  let babel;
@@ -80,6 +87,7 @@ async function loadBabel() {
80
87
  }
81
88
  return babel;
82
89
  }
90
+ const reactCompRE = /extends\s+(?:React\.)?(?:Pure)?Component/;
83
91
  const refreshContentRE = /\$Refresh(?:Reg|Sig)\$\(/;
84
92
  const defaultIncludeRE = /\.[tj]sx?$/;
85
93
  const tsRE = /\.tsx?$/;
@@ -184,7 +192,9 @@ function viteReact(opts = {}) {
184
192
  filename: id,
185
193
  sourceFileName: filepath,
186
194
  // Required for esbuild.jsxDev to provide correct line numbers
187
- retainLines: !isProduction && isJSX && opts.jsxRuntime !== "classic",
195
+ // This crates issues the react compiler because the re-order is too important
196
+ // People should use @babel/plugin-transform-react-jsx-development to get back good line numbers
197
+ retainLines: hasCompiler(plugins) ? false : !isProduction && isJSX && opts.jsxRuntime !== "classic",
188
198
  parserOpts: {
189
199
  ...babelOptions.parserOpts,
190
200
  sourceType: "module",
@@ -200,23 +210,29 @@ function viteReact(opts = {}) {
200
210
  });
201
211
  if (result) {
202
212
  let code2 = result.code;
203
- if (useFastRefresh && refreshContentRE.test(code2)) {
204
- code2 = addRefreshWrapper(code2, id);
213
+ if (useFastRefresh) {
214
+ if (refreshContentRE.test(code2)) {
215
+ code2 = addRefreshWrapper(code2, id);
216
+ } else if (reactCompRE.test(code2)) {
217
+ code2 = addClassComponentRefreshWrapper(code2, id);
218
+ }
205
219
  }
206
220
  return { code: code2, map: result.map };
207
221
  }
208
222
  }
209
223
  };
224
+ const dependencies = ["react", jsxImportDevRuntime, jsxImportRuntime];
225
+ const staticBabelPlugins = typeof opts.babel === "object" ? opts.babel?.plugins ?? [] : [];
226
+ if (hasCompiler(staticBabelPlugins)) {
227
+ dependencies.push("react/compiler-runtime");
228
+ }
210
229
  const viteReactRefresh = {
211
230
  name: "vite:react-refresh",
212
231
  enforce: "pre",
213
232
  config: (userConfig) => ({
214
233
  build: silenceUseClientWarning(userConfig),
215
234
  optimizeDeps: {
216
- // We can't add `react-dom` because the dependency is `react-dom/client`
217
- // for React 18 while it's `react-dom` for React 17. We'd need to detect
218
- // what React version the user has installed.
219
- include: ["react", jsxImportDevRuntime, jsxImportRuntime]
235
+ include: dependencies
220
236
  },
221
237
  resolve: {
222
238
  dedupe: ["react", "react-dom"]
@@ -290,6 +306,11 @@ function createBabelOptions(rawOptions) {
290
306
  function defined(value) {
291
307
  return value !== void 0;
292
308
  }
309
+ function hasCompiler(plugins) {
310
+ return plugins.some(
311
+ (p) => p === "babel-plugin-react-compiler" || Array.isArray(p) && p[0] === "babel-plugin-react-compiler"
312
+ );
313
+ }
293
314
 
294
315
  module.exports = viteReact;
295
316
  module.exports.default = viteReact;
package/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { TransformOptions, ParserOptions } from '@babel/core';
2
- import { ResolvedConfig, PluginOption } from 'vite';
2
+ import { PluginOption, ResolvedConfig } from 'vite';
3
3
 
4
4
  interface Options {
5
5
  include?: string | RegExp | Array<string | RegExp>;
@@ -40,19 +40,15 @@ type ReactBabelHookContext = {
40
40
  ssr: boolean;
41
41
  id: string;
42
42
  };
43
- declare module 'vite' {
44
- interface Plugin {
45
- api?: {
46
- /**
47
- * Manipulate the Babel options of `@vitejs/plugin-react`
48
- */
49
- reactBabel?: ReactBabelHook;
50
- };
51
- }
52
- }
43
+ type ViteReactPluginApi = {
44
+ /**
45
+ * Manipulate the Babel options of `@vitejs/plugin-react`
46
+ */
47
+ reactBabel?: ReactBabelHook;
48
+ };
53
49
  declare function viteReact(opts?: Options): PluginOption[];
54
50
  declare namespace viteReact {
55
51
  var preambleCode: string;
56
52
  }
57
53
 
58
- export { type BabelOptions, type Options, type ReactBabelOptions, viteReact as default };
54
+ export { type BabelOptions, type Options, type ReactBabelOptions, type ViteReactPluginApi, viteReact as default };
package/dist/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { TransformOptions, ParserOptions } from '@babel/core';
2
- import { ResolvedConfig, PluginOption } from 'vite';
2
+ import { PluginOption, ResolvedConfig } from 'vite';
3
3
 
4
4
  interface Options {
5
5
  include?: string | RegExp | Array<string | RegExp>;
@@ -40,19 +40,15 @@ type ReactBabelHookContext = {
40
40
  ssr: boolean;
41
41
  id: string;
42
42
  };
43
- declare module 'vite' {
44
- interface Plugin {
45
- api?: {
46
- /**
47
- * Manipulate the Babel options of `@vitejs/plugin-react`
48
- */
49
- reactBabel?: ReactBabelHook;
50
- };
51
- }
52
- }
43
+ type ViteReactPluginApi = {
44
+ /**
45
+ * Manipulate the Babel options of `@vitejs/plugin-react`
46
+ */
47
+ reactBabel?: ReactBabelHook;
48
+ };
53
49
  declare function viteReact(opts?: Options): PluginOption[];
54
50
  declare namespace viteReact {
55
51
  var preambleCode: string;
56
52
  }
57
53
 
58
- export { type BabelOptions, type Options, type ReactBabelOptions, viteReact as default };
54
+ export { type BabelOptions, type Options, type ReactBabelOptions, type ViteReactPluginApi, viteReact as default };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { TransformOptions, ParserOptions } from '@babel/core';
2
- import { ResolvedConfig, PluginOption } from 'vite';
2
+ import { PluginOption, ResolvedConfig } from 'vite';
3
3
 
4
4
  interface Options {
5
5
  include?: string | RegExp | Array<string | RegExp>;
@@ -40,19 +40,15 @@ type ReactBabelHookContext = {
40
40
  ssr: boolean;
41
41
  id: string;
42
42
  };
43
- declare module 'vite' {
44
- interface Plugin {
45
- api?: {
46
- /**
47
- * Manipulate the Babel options of `@vitejs/plugin-react`
48
- */
49
- reactBabel?: ReactBabelHook;
50
- };
51
- }
52
- }
43
+ type ViteReactPluginApi = {
44
+ /**
45
+ * Manipulate the Babel options of `@vitejs/plugin-react`
46
+ */
47
+ reactBabel?: ReactBabelHook;
48
+ };
53
49
  declare function viteReact(opts?: Options): PluginOption[];
54
50
  declare namespace viteReact {
55
51
  var preambleCode: string;
56
52
  }
57
53
 
58
- export { type BabelOptions, type Options, type ReactBabelOptions, viteReact as default };
54
+ export { type BabelOptions, type Options, type ReactBabelOptions, type ViteReactPluginApi, viteReact as default };
package/dist/index.mjs CHANGED
@@ -25,10 +25,12 @@ window.$RefreshReg$ = () => {}
25
25
  window.$RefreshSig$ = () => (type) => type
26
26
  window.__vite_plugin_react_preamble_installed__ = true
27
27
  `;
28
- const header = `
28
+ const sharedHeader = `
29
29
  import RefreshRuntime from "${runtimePublicPath}";
30
30
 
31
31
  const inWebWorker = typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope;
32
+ `.replace(/\n+/g, "");
33
+ const functionHeader = `
32
34
  let prevRefreshReg;
33
35
  let prevRefreshSig;
34
36
 
@@ -47,11 +49,13 @@ if (import.meta.hot && !inWebWorker) {
47
49
  };
48
50
  window.$RefreshSig$ = RefreshRuntime.createSignatureFunctionForTransform;
49
51
  }`.replace(/\n+/g, "");
50
- const footer = `
52
+ const functionFooter = `
51
53
  if (import.meta.hot && !inWebWorker) {
52
54
  window.$RefreshReg$ = prevRefreshReg;
53
55
  window.$RefreshSig$ = prevRefreshSig;
54
-
56
+ }`;
57
+ const sharedFooter = `
58
+ if (import.meta.hot && !inWebWorker) {
55
59
  RefreshRuntime.__hmr_import(import.meta.url).then((currentExports) => {
56
60
  RefreshRuntime.registerExportsForReactRefresh(__SOURCE__, currentExports);
57
61
  import.meta.hot.accept((nextExports) => {
@@ -62,7 +66,10 @@ if (import.meta.hot && !inWebWorker) {
62
66
  });
63
67
  }`;
64
68
  function addRefreshWrapper(code, id) {
65
- return header.replace("__SOURCE__", JSON.stringify(id)) + code + footer.replace("__SOURCE__", JSON.stringify(id));
69
+ return sharedHeader + functionHeader.replace("__SOURCE__", JSON.stringify(id)) + code + functionFooter + sharedFooter.replace("__SOURCE__", JSON.stringify(id));
70
+ }
71
+ function addClassComponentRefreshWrapper(code, id) {
72
+ return sharedHeader + code + sharedFooter.replace("__SOURCE__", JSON.stringify(id));
66
73
  }
67
74
 
68
75
  let babel;
@@ -72,6 +79,7 @@ async function loadBabel() {
72
79
  }
73
80
  return babel;
74
81
  }
82
+ const reactCompRE = /extends\s+(?:React\.)?(?:Pure)?Component/;
75
83
  const refreshContentRE = /\$Refresh(?:Reg|Sig)\$\(/;
76
84
  const defaultIncludeRE = /\.[tj]sx?$/;
77
85
  const tsRE = /\.tsx?$/;
@@ -176,7 +184,9 @@ function viteReact(opts = {}) {
176
184
  filename: id,
177
185
  sourceFileName: filepath,
178
186
  // Required for esbuild.jsxDev to provide correct line numbers
179
- retainLines: !isProduction && isJSX && opts.jsxRuntime !== "classic",
187
+ // This crates issues the react compiler because the re-order is too important
188
+ // People should use @babel/plugin-transform-react-jsx-development to get back good line numbers
189
+ retainLines: hasCompiler(plugins) ? false : !isProduction && isJSX && opts.jsxRuntime !== "classic",
180
190
  parserOpts: {
181
191
  ...babelOptions.parserOpts,
182
192
  sourceType: "module",
@@ -192,23 +202,29 @@ function viteReact(opts = {}) {
192
202
  });
193
203
  if (result) {
194
204
  let code2 = result.code;
195
- if (useFastRefresh && refreshContentRE.test(code2)) {
196
- code2 = addRefreshWrapper(code2, id);
205
+ if (useFastRefresh) {
206
+ if (refreshContentRE.test(code2)) {
207
+ code2 = addRefreshWrapper(code2, id);
208
+ } else if (reactCompRE.test(code2)) {
209
+ code2 = addClassComponentRefreshWrapper(code2, id);
210
+ }
197
211
  }
198
212
  return { code: code2, map: result.map };
199
213
  }
200
214
  }
201
215
  };
216
+ const dependencies = ["react", jsxImportDevRuntime, jsxImportRuntime];
217
+ const staticBabelPlugins = typeof opts.babel === "object" ? opts.babel?.plugins ?? [] : [];
218
+ if (hasCompiler(staticBabelPlugins)) {
219
+ dependencies.push("react/compiler-runtime");
220
+ }
202
221
  const viteReactRefresh = {
203
222
  name: "vite:react-refresh",
204
223
  enforce: "pre",
205
224
  config: (userConfig) => ({
206
225
  build: silenceUseClientWarning(userConfig),
207
226
  optimizeDeps: {
208
- // We can't add `react-dom` because the dependency is `react-dom/client`
209
- // for React 18 while it's `react-dom` for React 17. We'd need to detect
210
- // what React version the user has installed.
211
- include: ["react", jsxImportDevRuntime, jsxImportRuntime]
227
+ include: dependencies
212
228
  },
213
229
  resolve: {
214
230
  dedupe: ["react", "react-dom"]
@@ -282,5 +298,10 @@ function createBabelOptions(rawOptions) {
282
298
  function defined(value) {
283
299
  return value !== void 0;
284
300
  }
301
+ function hasCompiler(plugins) {
302
+ return plugins.some(
303
+ (p) => p === "babel-plugin-react-compiler" || Array.isArray(p) && p[0] === "babel-plugin-react-compiler"
304
+ );
305
+ }
285
306
 
286
307
  export { viteReact as default };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vitejs/plugin-react",
3
- "version": "4.2.0",
3
+ "version": "4.3.0",
4
4
  "license": "MIT",
5
5
  "author": "Evan You",
6
6
  "contributors": [
@@ -38,13 +38,16 @@
38
38
  },
39
39
  "homepage": "https://github.com/vitejs/vite-plugin-react/tree/main/packages/plugin-react#readme",
40
40
  "dependencies": {
41
- "@babel/core": "^7.23.3",
42
- "@babel/plugin-transform-react-jsx-self": "^7.23.3",
43
- "@babel/plugin-transform-react-jsx-source": "^7.23.3",
44
- "@types/babel__core": "^7.20.4",
45
- "react-refresh": "^0.14.0"
41
+ "@babel/core": "^7.24.5",
42
+ "@babel/plugin-transform-react-jsx-self": "^7.24.5",
43
+ "@babel/plugin-transform-react-jsx-source": "^7.24.1",
44
+ "@types/babel__core": "^7.20.5",
45
+ "react-refresh": "^0.14.2"
46
46
  },
47
47
  "peerDependencies": {
48
48
  "vite": "^4.2.0 || ^5.0.0"
49
+ },
50
+ "devDependencies": {
51
+ "unbuild": "^2.0.0"
49
52
  }
50
53
  }