Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(react): sourcemap incorrect warning and classic runtime sourcemap #9006

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/plugin-react/package.json
Expand Up @@ -44,6 +44,7 @@
"@babel/plugin-transform-react-jsx-development": "^7.18.6",
"@babel/plugin-transform-react-jsx-self": "^7.18.6",
"@babel/plugin-transform-react-jsx-source": "^7.18.6",
"magic-string": "^0.26.2",
"react-refresh": "^0.14.0"
},
"peerDependencies": {
Expand Down
29 changes: 25 additions & 4 deletions packages/plugin-react/src/index.ts
Expand Up @@ -3,6 +3,8 @@ import type { ParserOptions, TransformOptions, types as t } from '@babel/core'
import * as babel from '@babel/core'
import { createFilter, normalizePath } from 'vite'
import type { Plugin, PluginOption, ResolvedConfig } from 'vite'
import MagicString from 'magic-string'
import type { SourceMap } from 'magic-string'
import {
addRefreshWrapper,
isRefreshBoundary,
Expand Down Expand Up @@ -88,11 +90,14 @@ declare module 'vite' {
}
}

const prependReactImportCode = "import React from 'react'; "

export default function viteReact(opts: Options = {}): PluginOption[] {
// Provide default values for Rollup compat.
let devBase = '/'
let resolvedCacheDir: string
let filter = createFilter(opts.include, opts.exclude)
let needHiresSourcemap = false
let isProduction = true
let projectRoot = process.cwd()
let skipFastRefresh = opts.fastRefresh === false
Expand Down Expand Up @@ -135,6 +140,8 @@ export default function viteReact(opts: Options = {}): PluginOption[] {
filter = createFilter(opts.include, opts.exclude, {
resolve: projectRoot
})
needHiresSourcemap =
config.command === 'build' && !!config.build.sourcemap
isProduction = config.isProduction
skipFastRefresh ||= isProduction || config.command === 'build'

Expand Down Expand Up @@ -217,6 +224,7 @@ export default function viteReact(opts: Options = {}): PluginOption[] {
}

let ast: t.File | null | undefined
let prependReactImport = false
if (!isProjectFile || isJSX) {
if (useAutomaticRuntime) {
// By reverse-compiling "React.createElement" calls into JSX,
Expand Down Expand Up @@ -261,11 +269,23 @@ export default function viteReact(opts: Options = {}): PluginOption[] {
// Even if the automatic JSX runtime is not used, we can still
// inject the React import for .jsx and .tsx modules.
if (!skipReactImport && !importReactRE.test(code)) {
code = `import React from 'react'; ` + code
prependReactImport = true
}
}
}

let inputMap: SourceMap | undefined
if (prependReactImport) {
if (needHiresSourcemap) {
const s = new MagicString(code)
s.prepend(prependReactImportCode)
code = s.toString()
inputMap = s.generateMap({ hires: true, source: id })
} else {
code = prependReactImportCode + code
}
}

// Plugins defined through this Vite plugin are only applied
// to modules within the project root, but "babel.config.js"
// files can define plugins that need to be applied to every
Expand All @@ -275,10 +295,11 @@ export default function viteReact(opts: Options = {}): PluginOption[] {
!babelOptions.configFile &&
!(isProjectFile && babelOptions.babelrc)

// Avoid parsing if no plugins exist.
if (shouldSkip) {
// Avoid parsing if no plugins exist.
return {
code
code,
map: inputMap ?? null
}
}

Expand Down Expand Up @@ -326,7 +347,7 @@ export default function viteReact(opts: Options = {}): PluginOption[] {
plugins,
sourceMaps: true,
// Vite handles sourcemap flattening
inputSourceMap: false as any
inputSourceMap: inputMap ?? (false as any)
})

if (result) {
Expand Down
8 changes: 8 additions & 0 deletions playground/react-sourcemap/App.jsx
@@ -0,0 +1,8 @@
console.log('App.jsx 1') // for sourcemap
function App() {
return <div>foo</div>
}

console.log('App.jsx 2') // for sourcemap

export default App
7 changes: 7 additions & 0 deletions playground/react-sourcemap/__tests__/react-sourcemap.spec.ts
@@ -0,0 +1,7 @@
import { isBuild, serverLogs } from '~utils'

test.runIf(isBuild)('should not output sourcemap warning', () => {
serverLogs.forEach((log) => {
expect(log).not.toMatch('Sourcemap is likely to be incorrect')
})
})
2 changes: 2 additions & 0 deletions playground/react-sourcemap/index.html
@@ -0,0 +1,2 @@
<div id="app"></div>
<script type="module" src="main.jsx"></script>
9 changes: 9 additions & 0 deletions playground/react-sourcemap/main.jsx
@@ -0,0 +1,9 @@
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.jsx'

ReactDOM.createRoot(document.getElementById('app')).render(
React.createElement(App)
)

console.log('main.jsx') // for sourcemap
21 changes: 21 additions & 0 deletions playground/react-sourcemap/package.json
@@ -0,0 +1,21 @@
{
"name": "test-react-sourcemap",
"private": true,
"version": "0.0.0",
"scripts": {
"dev": "vite",
"dev:classic": "cross-env USE_CLASSIC=1 vite",
"build": "vite build",
"build:classic": "cross-env USE_CLASSIC=1 vite build",
"debug": "node --inspect-brk ../../packages/vite/bin/vite",
"preview": "vite preview"
},
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@vitejs/plugin-react": "workspace:*",
"cross-env": "^7.0.3"
}
}
15 changes: 15 additions & 0 deletions playground/react-sourcemap/vite.config.ts
@@ -0,0 +1,15 @@
import react from '@vitejs/plugin-react'
import type { UserConfig } from 'vite'

const config: UserConfig = {
plugins: [
react({
jsxRuntime: process.env.USE_CLASSIC === '1' ? 'classic' : 'automatic'
})
],
build: {
sourcemap: true
}
}

export default config
17 changes: 16 additions & 1 deletion pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.