From ac694a4979574f90d66bd9eb0c7f9d2fbd3abc57 Mon Sep 17 00:00:00 2001 From: sapphi-red Date: Sat, 9 Jul 2022 19:47:05 +0900 Subject: [PATCH 1/5] fix(react): sourcemap incorrect warning --- packages/plugin-react/src/index.ts | 3 ++- playground/react-sourcemap/App.jsx | 7 +++++++ .../__tests__/react-sourcemap.spec.ts | 7 +++++++ playground/react-sourcemap/index.html | 2 ++ playground/react-sourcemap/main.jsx | 9 +++++++++ playground/react-sourcemap/package.json | 18 ++++++++++++++++++ playground/react-sourcemap/vite.config.ts | 11 +++++++++++ pnpm-lock.yaml | 11 +++++++++++ 8 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 playground/react-sourcemap/App.jsx create mode 100644 playground/react-sourcemap/__tests__/react-sourcemap.spec.ts create mode 100644 playground/react-sourcemap/index.html create mode 100644 playground/react-sourcemap/main.jsx create mode 100644 playground/react-sourcemap/package.json create mode 100644 playground/react-sourcemap/vite.config.ts diff --git a/packages/plugin-react/src/index.ts b/packages/plugin-react/src/index.ts index 160e9ca1d2f883..1ef86f0823bcd9 100644 --- a/packages/plugin-react/src/index.ts +++ b/packages/plugin-react/src/index.ts @@ -278,7 +278,8 @@ export default function viteReact(opts: Options = {}): PluginOption[] { if (shouldSkip) { // Avoid parsing if no plugins exist. return { - code + code, + map: null } } diff --git a/playground/react-sourcemap/App.jsx b/playground/react-sourcemap/App.jsx new file mode 100644 index 00000000000000..1963e9e394ea7d --- /dev/null +++ b/playground/react-sourcemap/App.jsx @@ -0,0 +1,7 @@ +function App() { + return
foo
+} + +console.log('App.jsx') // for sourcemap + +export default App diff --git a/playground/react-sourcemap/__tests__/react-sourcemap.spec.ts b/playground/react-sourcemap/__tests__/react-sourcemap.spec.ts new file mode 100644 index 00000000000000..a1d35485760753 --- /dev/null +++ b/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') + }) +}) diff --git a/playground/react-sourcemap/index.html b/playground/react-sourcemap/index.html new file mode 100644 index 00000000000000..d3ca9807c608ba --- /dev/null +++ b/playground/react-sourcemap/index.html @@ -0,0 +1,2 @@ +
+ diff --git a/playground/react-sourcemap/main.jsx b/playground/react-sourcemap/main.jsx new file mode 100644 index 00000000000000..705d3340097aeb --- /dev/null +++ b/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 diff --git a/playground/react-sourcemap/package.json b/playground/react-sourcemap/package.json new file mode 100644 index 00000000000000..a76345f9d0ad7c --- /dev/null +++ b/playground/react-sourcemap/package.json @@ -0,0 +1,18 @@ +{ + "name": "test-react-sourcemap", + "private": true, + "version": "0.0.0", + "scripts": { + "dev": "vite", + "build": "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:*" + } +} diff --git a/playground/react-sourcemap/vite.config.ts b/playground/react-sourcemap/vite.config.ts new file mode 100644 index 00000000000000..cc862dea71316f --- /dev/null +++ b/playground/react-sourcemap/vite.config.ts @@ -0,0 +1,11 @@ +import react from '@vitejs/plugin-react' +import type { UserConfig } from 'vite' + +const config: UserConfig = { + plugins: [react()], + build: { + sourcemap: true + } +} + +export default config diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a9b329c87ac56d..0944b46baec85e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -821,6 +821,17 @@ importers: '@emotion/babel-plugin': 11.9.2 '@vitejs/plugin-react': link:../../packages/plugin-react + playground/react-sourcemap: + specifiers: + '@vitejs/plugin-react': workspace:* + react: ^18.2.0 + react-dom: ^18.2.0 + dependencies: + react: 18.2.0 + react-dom: 18.2.0_react@18.2.0 + devDependencies: + '@vitejs/plugin-react': link:../../packages/plugin-react + playground/react/jsx-entry: specifiers: {} From accf16d3eb129464cfba2039d9fe6e27872b1c07 Mon Sep 17 00:00:00 2001 From: sapphi-red Date: Sat, 9 Jul 2022 20:55:00 +0900 Subject: [PATCH 2/5] fix(react): fix classic runtime sourcemap --- packages/plugin-react/package.json | 1 + packages/plugin-react/src/index.ts | 25 +++++++++++++++++++---- playground/react-sourcemap/App.jsx | 3 ++- playground/react-sourcemap/package.json | 5 ++++- playground/react-sourcemap/vite.config.ts | 6 +++++- pnpm-lock.yaml | 6 +++++- 6 files changed, 38 insertions(+), 8 deletions(-) diff --git a/packages/plugin-react/package.json b/packages/plugin-react/package.json index bb0d146594d900..c21207996e4089 100644 --- a/packages/plugin-react/package.json +++ b/packages/plugin-react/package.json @@ -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": { diff --git a/packages/plugin-react/src/index.ts b/packages/plugin-react/src/index.ts index 1ef86f0823bcd9..9b41ae9598c40c 100644 --- a/packages/plugin-react/src/index.ts +++ b/packages/plugin-react/src/index.ts @@ -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, @@ -93,6 +95,7 @@ export default function viteReact(opts: Options = {}): PluginOption[] { 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 @@ -135,6 +138,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' @@ -217,6 +222,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, @@ -261,11 +267,22 @@ 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) { + console.log('prepend') + const s = new MagicString(code) + s.prepend("import React from 'react'; ") + code = s.toString() + if (needHiresSourcemap) { + inputMap = s.generateMap({ hires: true, source: id }) + } + } + // 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 @@ -275,11 +292,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, - map: null + map: inputMap ?? null } } @@ -327,7 +344,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) { diff --git a/playground/react-sourcemap/App.jsx b/playground/react-sourcemap/App.jsx index 1963e9e394ea7d..ec47ca46ad212e 100644 --- a/playground/react-sourcemap/App.jsx +++ b/playground/react-sourcemap/App.jsx @@ -1,7 +1,8 @@ +console.log('App.jsx 1') // for sourcemap function App() { return
foo
} -console.log('App.jsx') // for sourcemap +console.log('App.jsx 2') // for sourcemap export default App diff --git a/playground/react-sourcemap/package.json b/playground/react-sourcemap/package.json index a76345f9d0ad7c..91aa3331b877b4 100644 --- a/playground/react-sourcemap/package.json +++ b/playground/react-sourcemap/package.json @@ -4,7 +4,9 @@ "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" }, @@ -13,6 +15,7 @@ "react-dom": "^18.2.0" }, "devDependencies": { - "@vitejs/plugin-react": "workspace:*" + "@vitejs/plugin-react": "workspace:*", + "cross-env": "^7.0.3" } } diff --git a/playground/react-sourcemap/vite.config.ts b/playground/react-sourcemap/vite.config.ts index cc862dea71316f..d8a2cc46b419b9 100644 --- a/playground/react-sourcemap/vite.config.ts +++ b/playground/react-sourcemap/vite.config.ts @@ -2,7 +2,11 @@ import react from '@vitejs/plugin-react' import type { UserConfig } from 'vite' const config: UserConfig = { - plugins: [react()], + plugins: [ + react({ + jsxRuntime: process.env.USE_CLASSIC === '1' ? 'classic' : 'automatic' + }) + ], build: { sourcemap: true } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0944b46baec85e..c6a4178e50ab9c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -162,6 +162,7 @@ importers: '@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 vite: workspace:* dependencies: @@ -170,6 +171,7 @@ importers: '@babel/plugin-transform-react-jsx-development': 7.18.6_@babel+core@7.18.6 '@babel/plugin-transform-react-jsx-self': 7.18.6_@babel+core@7.18.6 '@babel/plugin-transform-react-jsx-source': 7.18.6_@babel+core@7.18.6 + magic-string: 0.26.2 react-refresh: 0.14.0 devDependencies: vite: link:../vite @@ -824,6 +826,7 @@ importers: playground/react-sourcemap: specifiers: '@vitejs/plugin-react': workspace:* + cross-env: ^7.0.3 react: ^18.2.0 react-dom: ^18.2.0 dependencies: @@ -831,6 +834,7 @@ importers: react-dom: 18.2.0_react@18.2.0 devDependencies: '@vitejs/plugin-react': link:../../packages/plugin-react + cross-env: 7.0.3 playground/react/jsx-entry: specifiers: {} @@ -5721,7 +5725,7 @@ packages: dev: true /isexe/2.0.0: - resolution: {integrity: sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=} + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} dev: true /jiti/1.13.0: From e16b210f8ef216394cee1bc7247bdd5d00f2db58 Mon Sep 17 00:00:00 2001 From: sapphi-red Date: Sat, 9 Jul 2022 20:57:34 +0900 Subject: [PATCH 3/5] refactor: remove debug code --- packages/plugin-react/src/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/plugin-react/src/index.ts b/packages/plugin-react/src/index.ts index 9b41ae9598c40c..0b57a6b5fe1038 100644 --- a/packages/plugin-react/src/index.ts +++ b/packages/plugin-react/src/index.ts @@ -274,7 +274,6 @@ export default function viteReact(opts: Options = {}): PluginOption[] { let inputMap: SourceMap | undefined if (prependReactImport) { - console.log('prepend') const s = new MagicString(code) s.prepend("import React from 'react'; ") code = s.toString() From 956982143f2b8970361c800dfb54530988d16b8e Mon Sep 17 00:00:00 2001 From: sapphi-red Date: Sat, 9 Jul 2022 21:01:10 +0900 Subject: [PATCH 4/5] perf: skip magic string init --- packages/plugin-react/src/index.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/plugin-react/src/index.ts b/packages/plugin-react/src/index.ts index 0b57a6b5fe1038..05cb36c4b95461 100644 --- a/packages/plugin-react/src/index.ts +++ b/packages/plugin-react/src/index.ts @@ -90,6 +90,8 @@ declare module 'vite' { } } +const prependReactImportCode = "import React from 'react'; " + export default function viteReact(opts: Options = {}): PluginOption[] { // Provide default values for Rollup compat. let devBase = '/' @@ -274,10 +276,10 @@ export default function viteReact(opts: Options = {}): PluginOption[] { let inputMap: SourceMap | undefined if (prependReactImport) { - const s = new MagicString(code) - s.prepend("import React from 'react'; ") - code = s.toString() + code = prependReactImportCode + code if (needHiresSourcemap) { + const s = new MagicString(code) + s.prepend(prependReactImportCode) inputMap = s.generateMap({ hires: true, source: id }) } } From 6ae7d3fc70646392ebc9d48683b3234eb72eee2c Mon Sep 17 00:00:00 2001 From: sapphi-red Date: Sun, 10 Jul 2022 00:11:06 +0900 Subject: [PATCH 5/5] fix: dedupe prepend --- packages/plugin-react/src/index.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/plugin-react/src/index.ts b/packages/plugin-react/src/index.ts index 05cb36c4b95461..f1adf81510bcef 100644 --- a/packages/plugin-react/src/index.ts +++ b/packages/plugin-react/src/index.ts @@ -276,11 +276,13 @@ export default function viteReact(opts: Options = {}): PluginOption[] { let inputMap: SourceMap | undefined if (prependReactImport) { - code = prependReactImportCode + code if (needHiresSourcemap) { const s = new MagicString(code) s.prepend(prependReactImportCode) + code = s.toString() inputMap = s.generateMap({ hires: true, source: id }) + } else { + code = prependReactImportCode + code } }