Skip to content

Commit bf8e967

Browse files
authored
fix!: don't auto import React with classic runtime (#150)
1 parent 14a0e83 commit bf8e967

File tree

5 files changed

+17
-44
lines changed

5 files changed

+17
-44
lines changed

packages/plugin-react/README.md

+8
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,14 @@ Control where the JSX factory is imported from. Default to `'react'`
4646
react({ jsxImportSource: '@emotion/react' })
4747
```
4848

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+
4957
### babel
5058

5159
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.

packages/plugin-react/package.json

-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@
4242
"@babel/core": "^7.21.4",
4343
"@babel/plugin-transform-react-jsx-self": "^7.21.0",
4444
"@babel/plugin-transform-react-jsx-source": "^7.19.6",
45-
"magic-string": "^0.30.0",
4645
"react-refresh": "^0.14.0"
4746
},
4847
"peerDependencies": {

packages/plugin-react/src/index.ts

+7-40
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@ import type {
88
ResolvedConfig,
99
UserConfig,
1010
} from 'vite'
11-
import MagicString from 'magic-string'
12-
import type { SourceMap } from 'magic-string'
1311
import {
1412
addRefreshWrapper,
1513
preambleCode,
@@ -20,18 +18,17 @@ import {
2018
export interface Options {
2119
include?: string | RegExp | Array<string | RegExp>
2220
exclude?: string | RegExp | Array<string | RegExp>
23-
/**
24-
* @deprecated All tools now support the automatic runtime, and it has been backported
25-
* up to React 16. This allows to skip the React import and can produce smaller bundlers.
26-
* @default "automatic"
27-
*/
28-
jsxRuntime?: 'classic' | 'automatic'
2921
/**
3022
* Control where the JSX factory is imported from.
3123
* https://esbuild.github.io/api/#jsx-import-source
3224
* @default 'react'
3325
*/
3426
jsxImportSource?: string
27+
/**
28+
* Note: Skipping React import with classic runtime is not supported from v4
29+
* @default "automatic"
30+
*/
31+
jsxRuntime?: 'classic' | 'automatic'
3532
/**
3633
* Babel configuration applied in both dev and prod.
3734
*/
@@ -82,7 +79,6 @@ declare module 'vite' {
8279
}
8380
}
8481

85-
const prependReactImportCode = "import React from 'react'; "
8682
const refreshContentRE = /\$Refresh(?:Reg|Sig)\$\(/
8783
const defaultIncludeRE = /\.[tj]sx?$/
8884
const tsRE = /\.tsx?$/
@@ -92,7 +88,6 @@ export default function viteReact(opts: Options = {}): PluginOption[] {
9288
let devBase = '/'
9389
const filter = createFilter(opts.include ?? defaultIncludeRE, opts.exclude)
9490
const devRuntime = `${opts.jsxImportSource ?? 'react'}/jsx-dev-runtime`
95-
let needHiresSourcemap = false
9691
let isProduction = true
9792
let projectRoot = process.cwd()
9893
let skipFastRefresh = false
@@ -105,7 +100,7 @@ export default function viteReact(opts: Options = {}): PluginOption[] {
105100
// - import * as React from 'react';
106101
// - import React from 'react';
107102
// - import React, {useEffect} from 'react';
108-
const importReactRE = /(?:^|\n)import\s+(?:\*\s+as\s+)?React(?:,|\s+)/
103+
const importReactRE = /(?:^|\s)import\s+(?:\*\s+as\s+)?React(?:,|\s+)/
109104

110105
const viteBabel: Plugin = {
111106
name: 'vite:react-babel',
@@ -129,16 +124,9 @@ export default function viteReact(opts: Options = {}): PluginOption[] {
129124
configResolved(config) {
130125
devBase = config.base
131126
projectRoot = config.root
132-
needHiresSourcemap =
133-
config.command === 'build' && !!config.build.sourcemap
134127
isProduction = config.isProduction
135128
skipFastRefresh = isProduction || config.command === 'build'
136129

137-
if (opts.jsxRuntime === 'classic') {
138-
config.logger.warnOnce(
139-
'[@vitejs/plugin-react] Support for classic runtime is deprecated.',
140-
)
141-
}
142130
if ('jsxPure' in opts) {
143131
config.logger.warnOnce(
144132
'[@vitejs/plugin-react] jsxPure was removed. You can configure esbuild.jsxSideEffects directly.',
@@ -191,7 +179,6 @@ export default function viteReact(opts: Options = {}): PluginOption[] {
191179
])
192180
}
193181

194-
let prependReactImport = false
195182
if (opts.jsxRuntime === 'classic' && isJSX) {
196183
if (!isProduction) {
197184
// These development plugins are only needed for the classic runtime.
@@ -200,24 +187,6 @@ export default function viteReact(opts: Options = {}): PluginOption[] {
200187
await loadPlugin('@babel/plugin-transform-react-jsx-source'),
201188
)
202189
}
203-
204-
// Even if the automatic JSX runtime is not used, we can still
205-
// inject the React import for .jsx and .tsx modules.
206-
if (!importReactRE.test(code)) {
207-
prependReactImport = true
208-
}
209-
}
210-
211-
let inputMap: SourceMap | undefined
212-
if (prependReactImport) {
213-
if (needHiresSourcemap) {
214-
const s = new MagicString(code)
215-
s.prepend(prependReactImportCode)
216-
code = s.toString()
217-
inputMap = s.generateMap({ hires: true, source: id })
218-
} else {
219-
code = prependReactImportCode + code
220-
}
221190
}
222191

223192
// Avoid parsing if no special transformation is needed
@@ -226,7 +195,7 @@ export default function viteReact(opts: Options = {}): PluginOption[] {
226195
!babelOptions.configFile &&
227196
!babelOptions.babelrc
228197
) {
229-
return { code, map: inputMap ?? null }
198+
return
230199
}
231200

232201
const parserPlugins = [...babelOptions.parserOpts.plugins]
@@ -256,8 +225,6 @@ export default function viteReact(opts: Options = {}): PluginOption[] {
256225
},
257226
plugins,
258227
sourceMaps: true,
259-
// Vite handles sourcemap flattening
260-
inputSourceMap: inputMap ?? (false as any),
261228
})
262229

263230
if (result) {

playground/react-classic/App.jsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useState } from 'react'
1+
import React, { useState } from 'react'
22

33
function App() {
44
const [count, setCount] = useState(0)

pnpm-lock.yaml

+1-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)