@vitejs/plugin-react 4.0.0-beta.0 → 4.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
@@ -40,12 +40,20 @@ export default defineConfig({
40
40
 
41
41
  ### jsxImportSource
42
42
 
43
- Control where the JSX factory is imported from. For TS projects this is inferred from the tsconfig. If you have some React code outside JSX/TSX files, this will be used to detect the presence of React code and apply Fast Refresh.
43
+ Control where the JSX factory is imported from. Default to `'react'`
44
44
 
45
45
  ```js
46
46
  react({ jsxImportSource: '@emotion/react' })
47
47
  ```
48
48
 
49
+ ## jsxRuntime
50
+
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
+
53
+ ```js
54
+ react({ jsxRuntime: 'classic' })
55
+ ```
56
+
49
57
  ### babel
50
58
 
51
59
  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.
package/dist/index.cjs CHANGED
@@ -2,7 +2,6 @@
2
2
 
3
3
  const babel = require('@babel/core');
4
4
  const vite = require('vite');
5
- const MagicString = require('magic-string');
6
5
  const fs = require('node:fs');
7
6
  const path = require('node:path');
8
7
  const node_module = require('node:module');
@@ -22,7 +21,6 @@ function _interopNamespaceCompat(e) {
22
21
  }
23
22
 
24
23
  const babel__namespace = /*#__PURE__*/_interopNamespaceCompat(babel);
25
- const MagicString__default = /*#__PURE__*/_interopDefaultCompat(MagicString);
26
24
  const fs__default = /*#__PURE__*/_interopDefaultCompat(fs);
27
25
  const path__default = /*#__PURE__*/_interopDefaultCompat(path);
28
26
 
@@ -87,20 +85,19 @@ function addRefreshWrapper(code, id) {
87
85
  return header.replace("__SOURCE__", JSON.stringify(id)) + code + footer.replace("__SOURCE__", JSON.stringify(id));
88
86
  }
89
87
 
90
- const prependReactImportCode = "import React from 'react'; ";
91
88
  const refreshContentRE = /\$Refresh(?:Reg|Sig)\$\(/;
92
89
  const defaultIncludeRE = /\.[tj]sx?$/;
93
90
  const tsRE = /\.tsx?$/;
94
91
  function viteReact(opts = {}) {
95
92
  let devBase = "/";
96
93
  const filter = vite.createFilter(opts.include ?? defaultIncludeRE, opts.exclude);
97
- let needHiresSourcemap = false;
94
+ const devRuntime = `${opts.jsxImportSource ?? "react"}/jsx-dev-runtime`;
98
95
  let isProduction = true;
99
96
  let projectRoot = process.cwd();
100
97
  let skipFastRefresh = false;
101
98
  let runPluginOverrides;
102
99
  let staticBabelOptions;
103
- const importReactRE = /(?:^|\n)import\s+(?:\*\s+as\s+)?React(?:,|\s+)/;
100
+ const importReactRE = /(?:^|\s)import\s+(?:\*\s+as\s+)?React(?:,|\s+)/;
104
101
  const viteBabel = {
105
102
  name: "vite:react-babel",
106
103
  enforce: "pre",
@@ -123,14 +120,8 @@ function viteReact(opts = {}) {
123
120
  configResolved(config) {
124
121
  devBase = config.base;
125
122
  projectRoot = config.root;
126
- needHiresSourcemap = config.command === "build" && !!config.build.sourcemap;
127
123
  isProduction = config.isProduction;
128
124
  skipFastRefresh = isProduction || config.command === "build";
129
- if (opts.jsxRuntime === "classic") {
130
- config.logger.warnOnce(
131
- "[@vitejs/plugin-react] Support for classic runtime is deprecated."
132
- );
133
- }
134
125
  if ("jsxPure" in opts) {
135
126
  config.logger.warnOnce(
136
127
  "[@vitejs/plugin-react] jsxPure was removed. You can configure esbuild.jsxSideEffects directly."
@@ -163,16 +154,13 @@ function viteReact(opts = {}) {
163
154
  })();
164
155
  const plugins = [...babelOptions.plugins];
165
156
  const isJSX = filepath.endsWith("x");
166
- const useFastRefresh = !skipFastRefresh && !ssr && (isJSX || (opts.jsxRuntime === "classic" ? code.includes(
167
- `${opts.jsxImportSource ?? "react"}/jsx-dev-runtime`
168
- ) : importReactRE.test(code)));
157
+ const useFastRefresh = !skipFastRefresh && !ssr && (isJSX || (opts.jsxRuntime === "classic" ? code.includes(devRuntime) : importReactRE.test(code)));
169
158
  if (useFastRefresh) {
170
159
  plugins.push([
171
160
  await loadPlugin("react-refresh/babel"),
172
161
  { skipEnvCheck: true }
173
162
  ]);
174
163
  }
175
- let prependReactImport = false;
176
164
  if (opts.jsxRuntime === "classic" && isJSX) {
177
165
  if (!isProduction) {
178
166
  plugins.push(
@@ -180,23 +168,9 @@ function viteReact(opts = {}) {
180
168
  await loadPlugin("@babel/plugin-transform-react-jsx-source")
181
169
  );
182
170
  }
183
- if (!importReactRE.test(code)) {
184
- prependReactImport = true;
185
- }
186
- }
187
- let inputMap;
188
- if (prependReactImport) {
189
- if (needHiresSourcemap) {
190
- const s = new MagicString__default(code);
191
- s.prepend(prependReactImportCode);
192
- code = s.toString();
193
- inputMap = s.generateMap({ hires: true, source: id });
194
- } else {
195
- code = prependReactImportCode + code;
196
- }
197
171
  }
198
172
  if (!plugins.length && !babelOptions.configFile && !babelOptions.babelrc) {
199
- return { code, map: inputMap ?? null };
173
+ return;
200
174
  }
201
175
  const parserPlugins = [...babelOptions.parserOpts.plugins];
202
176
  if (!filepath.endsWith(".ts")) {
@@ -221,9 +195,7 @@ function viteReact(opts = {}) {
221
195
  decoratorsBeforeExport: true
222
196
  },
223
197
  plugins,
224
- sourceMaps: true,
225
- // Vite handles sourcemap flattening
226
- inputSourceMap: inputMap ?? false
198
+ sourceMaps: true
227
199
  });
228
200
  if (result) {
229
201
  let code2 = result.code;
@@ -243,7 +215,7 @@ function viteReact(opts = {}) {
243
215
  // We can't add `react-dom` because the dependency is `react-dom/client`
244
216
  // for React 18 while it's `react-dom` for React 17. We'd need to detect
245
217
  // what React version the user has installed.
246
- include: ["react"]
218
+ include: ["react", devRuntime]
247
219
  },
248
220
  resolve: {
249
221
  dedupe: ["react", "react-dom"]
package/dist/index.d.ts CHANGED
@@ -4,18 +4,17 @@ import { ResolvedConfig, PluginOption } from 'vite';
4
4
  interface Options {
5
5
  include?: string | RegExp | Array<string | RegExp>;
6
6
  exclude?: string | RegExp | Array<string | RegExp>;
7
- /**
8
- * @deprecated All tools now support the automatic runtime, and it has been backported
9
- * up to React 16. This allows to skip the React import and can produce smaller bundlers.
10
- * @default "automatic"
11
- */
12
- jsxRuntime?: 'classic' | 'automatic';
13
7
  /**
14
8
  * Control where the JSX factory is imported from.
15
9
  * https://esbuild.github.io/api/#jsx-import-source
16
- * For TS projects this is read from tsconfig
10
+ * @default 'react'
17
11
  */
18
12
  jsxImportSource?: string;
13
+ /**
14
+ * Note: Skipping React import with classic runtime is not supported from v4
15
+ * @default "automatic"
16
+ */
17
+ jsxRuntime?: 'classic' | 'automatic';
19
18
  /**
20
19
  * Babel configuration applied in both dev and prod.
21
20
  */
package/dist/index.mjs CHANGED
@@ -1,6 +1,5 @@
1
1
  import * as babel from '@babel/core';
2
2
  import { createFilter } from 'vite';
3
- import MagicString from 'magic-string';
4
3
  import fs from 'node:fs';
5
4
  import path from 'node:path';
6
5
  import { createRequire } from 'node:module';
@@ -66,20 +65,19 @@ function addRefreshWrapper(code, id) {
66
65
  return header.replace("__SOURCE__", JSON.stringify(id)) + code + footer.replace("__SOURCE__", JSON.stringify(id));
67
66
  }
68
67
 
69
- const prependReactImportCode = "import React from 'react'; ";
70
68
  const refreshContentRE = /\$Refresh(?:Reg|Sig)\$\(/;
71
69
  const defaultIncludeRE = /\.[tj]sx?$/;
72
70
  const tsRE = /\.tsx?$/;
73
71
  function viteReact(opts = {}) {
74
72
  let devBase = "/";
75
73
  const filter = createFilter(opts.include ?? defaultIncludeRE, opts.exclude);
76
- let needHiresSourcemap = false;
74
+ const devRuntime = `${opts.jsxImportSource ?? "react"}/jsx-dev-runtime`;
77
75
  let isProduction = true;
78
76
  let projectRoot = process.cwd();
79
77
  let skipFastRefresh = false;
80
78
  let runPluginOverrides;
81
79
  let staticBabelOptions;
82
- const importReactRE = /(?:^|\n)import\s+(?:\*\s+as\s+)?React(?:,|\s+)/;
80
+ const importReactRE = /(?:^|\s)import\s+(?:\*\s+as\s+)?React(?:,|\s+)/;
83
81
  const viteBabel = {
84
82
  name: "vite:react-babel",
85
83
  enforce: "pre",
@@ -102,14 +100,8 @@ function viteReact(opts = {}) {
102
100
  configResolved(config) {
103
101
  devBase = config.base;
104
102
  projectRoot = config.root;
105
- needHiresSourcemap = config.command === "build" && !!config.build.sourcemap;
106
103
  isProduction = config.isProduction;
107
104
  skipFastRefresh = isProduction || config.command === "build";
108
- if (opts.jsxRuntime === "classic") {
109
- config.logger.warnOnce(
110
- "[@vitejs/plugin-react] Support for classic runtime is deprecated."
111
- );
112
- }
113
105
  if ("jsxPure" in opts) {
114
106
  config.logger.warnOnce(
115
107
  "[@vitejs/plugin-react] jsxPure was removed. You can configure esbuild.jsxSideEffects directly."
@@ -142,16 +134,13 @@ function viteReact(opts = {}) {
142
134
  })();
143
135
  const plugins = [...babelOptions.plugins];
144
136
  const isJSX = filepath.endsWith("x");
145
- const useFastRefresh = !skipFastRefresh && !ssr && (isJSX || (opts.jsxRuntime === "classic" ? code.includes(
146
- `${opts.jsxImportSource ?? "react"}/jsx-dev-runtime`
147
- ) : importReactRE.test(code)));
137
+ const useFastRefresh = !skipFastRefresh && !ssr && (isJSX || (opts.jsxRuntime === "classic" ? code.includes(devRuntime) : importReactRE.test(code)));
148
138
  if (useFastRefresh) {
149
139
  plugins.push([
150
140
  await loadPlugin("react-refresh/babel"),
151
141
  { skipEnvCheck: true }
152
142
  ]);
153
143
  }
154
- let prependReactImport = false;
155
144
  if (opts.jsxRuntime === "classic" && isJSX) {
156
145
  if (!isProduction) {
157
146
  plugins.push(
@@ -159,23 +148,9 @@ function viteReact(opts = {}) {
159
148
  await loadPlugin("@babel/plugin-transform-react-jsx-source")
160
149
  );
161
150
  }
162
- if (!importReactRE.test(code)) {
163
- prependReactImport = true;
164
- }
165
- }
166
- let inputMap;
167
- if (prependReactImport) {
168
- if (needHiresSourcemap) {
169
- const s = new MagicString(code);
170
- s.prepend(prependReactImportCode);
171
- code = s.toString();
172
- inputMap = s.generateMap({ hires: true, source: id });
173
- } else {
174
- code = prependReactImportCode + code;
175
- }
176
151
  }
177
152
  if (!plugins.length && !babelOptions.configFile && !babelOptions.babelrc) {
178
- return { code, map: inputMap ?? null };
153
+ return;
179
154
  }
180
155
  const parserPlugins = [...babelOptions.parserOpts.plugins];
181
156
  if (!filepath.endsWith(".ts")) {
@@ -200,9 +175,7 @@ function viteReact(opts = {}) {
200
175
  decoratorsBeforeExport: true
201
176
  },
202
177
  plugins,
203
- sourceMaps: true,
204
- // Vite handles sourcemap flattening
205
- inputSourceMap: inputMap ?? false
178
+ sourceMaps: true
206
179
  });
207
180
  if (result) {
208
181
  let code2 = result.code;
@@ -222,7 +195,7 @@ function viteReact(opts = {}) {
222
195
  // We can't add `react-dom` because the dependency is `react-dom/client`
223
196
  // for React 18 while it's `react-dom` for React 17. We'd need to detect
224
197
  // what React version the user has installed.
225
- include: ["react"]
198
+ include: ["react", devRuntime]
226
199
  },
227
200
  resolve: {
228
201
  dedupe: ["react", "react-dom"]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vitejs/plugin-react",
3
- "version": "4.0.0-beta.0",
3
+ "version": "4.0.0",
4
4
  "license": "MIT",
5
5
  "author": "Evan You",
6
6
  "contributors": [
@@ -42,7 +42,6 @@
42
42
  "@babel/core": "^7.21.4",
43
43
  "@babel/plugin-transform-react-jsx-self": "^7.21.0",
44
44
  "@babel/plugin-transform-react-jsx-source": "^7.19.6",
45
- "magic-string": "^0.30.0",
46
45
  "react-refresh": "^0.14.0"
47
46
  },
48
47
  "peerDependencies": {