Skip to content

fix(plugin-rsc): use MagicString to preserve sourcemap chain in webpack-require transform#1120

Open
nianyi778 wants to merge 3 commits intovitejs:mainfrom
nianyi778:fix/rsc-plugin-sourcemap-chain-break
Open

fix(plugin-rsc): use MagicString to preserve sourcemap chain in webpack-require transform#1120
nianyi778 wants to merge 3 commits intovitejs:mainfrom
nianyi778:fix/rsc-plugin-sourcemap-chain-break

Conversation

@nianyi778
Copy link

Problem

The rsc:patch-react-server-dom-webpack transform replaces __webpack_require__ occurrences using string operations and returns { code, map: null }. Returning map: null from a transform that changes string lengths breaks the Rollup sourcemap chain, causing Rollup/Vite to emit a noisy warning for every file that passes through this transform:

src/components/foo.tsx (1:0): Error when using sourcemap for reporting an error: Can't resolve original location of error.

In practice this fires for every "use client" component in an app, since those files go through the RSC pipeline and may contain (or transitively load) modules that match the __webpack_require__ filter. The build still succeeds, but the output is very noisy.

Root cause: __webpack_require__ (18 chars) → __vite_rsc_require__ (20 chars) is not a same-length replacement, so map: null doesn't just "suppress" the map — it actively misleads Rollup about character offsets, snapping the sourcemap chain.

Fix

Replace the manual replaceAll + map: null with MagicString, which:

  • Tracks all character-level edits relative to the original source
  • Generates a correct hires sourcemap that reflects the actual offset changes
  • Handles both the .__webpack_require__.u variant and bare __webpack_require__ in a single left-to-right regex pass (avoids overlapping overwrites)
// Before
return { code, map: null }

// After
return {
  code: s.toString(),
  map: s.generateMap({ hires: true, source: id }),
}

magic-string is already a dependency of this package.

Testing

Verified with a Next.js + vinext (Cloudflare Workers) app: the 10+ sourcemap warnings on every "use client" component are eliminated with this fix applied.

@hi-ogawa
Copy link
Contributor

Can you provide reproduction?

@nianyi778
Copy link
Author

Can you provide reproduction?

@hi-ogawa
The simplest reproduction is any RSC app that has "use client" modules going through this transform.
Steps:

  1. Create a project from the official RSC starter template:
    npm create vite@latest -- --template rsc my-app
    cd my-app && npm install
    2. Run npx vite build
  2. Observe Rollup warnings in the build output:
    (!) Error when using sourcemap for reporting an error: Can't resolve original location of error

Root cause in one sentence: The rsc:patch-react-server-dom-webpack transform replaces webpack_require (18 chars) with vite_rsc_require (20 chars) — a non-same-length substitution — and returns map: null, which breaks the Rollup sourcemap chain for every downstream file.
I first noticed this in a vinext (https://github.com/cloudflare/vinext) + Cloudflare Workers project where 10+ "use client" components each emit this warning on every build. But it's reproducible with any @vitejs/plugin-rsc setup that has webpack_require in the transform path.
If the starter template doesn't trigger it directly, I can push a minimal repro repo — let me know.

@hi-ogawa
Copy link
Contributor

Alright, thanks. Can reproduce right here with pnpm -C packages/plugin-rsc/examples/starter build --sourcemap. Can you add test case so we can confirm this is fixed?

$ pnpm -C packages/plugin-rsc/examples/starter build --sourcemap

> @vitejs/plugin-rsc-examples-starter@0.0.0 build /home/hiroshi/code/others/vite-plugin-react/packages/plugin-rsc/examples/starter
> vite build --sourcemap

[1/5] analyze client references...
vite v7.3.1 building rsc environment for production...
 55 modules transformed.
[plugin rsc:virtual:vite-rsc/assets-manifest] Sourcemap is likely to be incorrect: a plugin (rsc:virtual:vite-rsc/assets-manifest) was used to transform files, but didn't generate a sourcemap for the transformation. Consult the plugin documentation for help
 built in 256ms
[2/5] analyze server references...
vite v7.3.1 building ssr environment for production...
 50 modules transformed.
[plugin rsc:virtual:vite-rsc/assets-manifest] Sourcemap is likely to be incorrect: a plugin (rsc:virtual:vite-rsc/assets-manifest) was used to transform files, but didn't generate a sourcemap for the transformation. Consult the plugin documentation for help
 built in 250ms
[3/5] build rsc environment...
vite v7.3.1 building rsc environment for production...
 55 modules transformed.
[plugin vite:reporter] 
(!) /home/hiroshi/code/others/vite-plugin-react/packages/plugin-rsc/examples/starter/src/action.tsx is dynamically imported by virtual:vite-rsc/server-references but also statically imported by /home/hiroshi/code/others/vite-plugin-react/packages/plugin-rsc/examples/starter/src/root.tsx, dynamic import will not move module into another chunk.

[plugin rsc:inject-async-local-storage] Sourcemap is likely to be incorrect: a plugin (rsc:inject-async-local-storage) was used to transform files, but didn't generate a sourcemap for the transformation. Consult the plugin documentation for help
[plugin rsc:inject-async-local-storage] Sourcemap is likely to be incorrect: a plugin (rsc:inject-async-local-storage) was used to transform files, but didn't generate a sourcemap for the transformation. Consult the plugin documentation for help (x2)
[plugin rsc:virtual:vite-rsc/assets-manifest] Sourcemap is likely to be incorrect: a plugin (rsc:virtual:vite-rsc/assets-manifest) was used to transform files, but didn't generate a sourcemap for the transformation. Consult the plugin documentation for help
dist/rsc/assets/react-CHdo91hT.svg    4.13 kB
dist/rsc/assets/index-NeOOZrmx.css    1.40 kB
dist/rsc/index.js                   626.79 kB  map: 14.28 kB
 built in 585ms
[4/5] build client environment...
vite v7.3.1 building client environment for production...
 42 modules transformed.
[plugin rsc:vite-client-raw-import] Sourcemap is likely to be incorrect: a plugin (rsc:vite-client-raw-import) was used to transform files, but didn't generate a sourcemap for the transformation. Consult the plugin documentation for help
dist/client/assets/react-CHdo91hT.svg       4.13 kB  gzip:  2.05 kB
dist/client/assets/index-NeOOZrmx.css       1.40 kB  gzip:  0.71 kB
dist/client/assets/entry.rsc-JZAVNEuk.js    0.27 kB  gzip:  0.24 kB  map:     0.59 kB
dist/client/assets/index-DPERZMr6.js      222.96 kB  gzip: 70.55 kB  map: 1,034.11 kB
 built in 477ms
[5/5] build ssr environment...
vite v7.3.1 building ssr environment for production...
 51 modules transformed.
[plugin rsc:virtual:vite-rsc/assets-manifest] Sourcemap is likely to be incorrect: a plugin (rsc:virtual:vite-rsc/assets-manifest) was used to transform files, but didn't generate a sourcemap for the transformation. Consult the plugin documentation for help
[plugin rsc:inject-async-local-storage] Sourcemap is likely to be incorrect: a plugin (rsc:inject-async-local-storage) was used to transform files, but didn't generate a sourcemap for the transformation. Consult the plugin documentation for help
[plugin rsc:inject-async-local-storage] Sourcemap is likely to be incorrect: a plugin (rsc:inject-async-local-storage) was used to transform files, but didn't generate a sourcemap for the transformation. Consult the plugin documentation for help (x2)
[plugin rsc:virtual:vite-rsc/assets-manifest] Sourcemap is likely to be incorrect: a plugin (rsc:virtual:vite-rsc/assets-manifest) was used to transform files, but didn't generate a sourcemap for the transformation. Consult the plugin documentation for help
dist/ssr/assets/entry.rsc-DMKK0oJ_.js      0.54 kB  map:  0.12 kB
dist/ssr/index.js                      1,560.08 kB  map: 32.68 kB
 built in 716ms

@nianyi778
Copy link
Author

nianyi778 commented Feb 25, 2026

@hi-ogawa

Added unit tests in 9909dbd.

Extracted the transform logic into an exported patchWebpackRequire() function (the plugin now delegates to it — no behavior change) so it can be tested directly.

Added 6 test cases covering:

  • bare __webpack_require____vite_rsc_require__
  • __webpack_require__.u({}).u
  • both patterns in the same source
  • no-op when __webpack_require__ is absent
  • returned sourcemap has non-empty mappings
  • sourcemap sources field is correctly set for offset-changing replacements

All tests pass (63 total).

Side note: the build output also shows “Sourcemap is likely to be incorrect” from:

  • rsc:inject-async-local-storage
  • rsc:virtual:vite-rsc-assets-manifest
  • rsc:vite-client-raw-import

These appear to be the same class of issue (transforms not returning proper sourcemaps). Happy to address those in a follow-up PR if that makes sense.

Copy link
Contributor

@hi-ogawa hi-ogawa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unit test is not needed. Please add e2e.

…ck-require transform

The rsc:patch-react-server-dom-webpack transform replaces
__webpack_require__ (18 chars) with __vite_rsc_require__ (20 chars)
— a non-same-length substitution — and previously returned map: null,
which broke the Rollup sourcemap chain.

Replace the manual replaceAll + map: null with MagicString, which
generates a correct hires sourcemap reflecting the actual offset changes.

Added e2e test that builds the starter example with --sourcemap and
verifies no sourcemap warnings are emitted for this transform.
@nianyi778 nianyi778 force-pushed the fix/rsc-plugin-sourcemap-chain-break branch from 9909dbd to b620e6c Compare February 25, 2026 07:46
@nianyi778
Copy link
Author

Replaced unit tests with e2e test in b620e6c.
The e2e test (e2e/sourcemap.test.ts) builds examples/starter with --sourcemap and asserts:

  1. rsc:patch-react-server-dom-webpack does NOT appear in any "Sourcemap is likely to be incorrect" warning
  2. Generated .js.map files in dist/rsc/ have non-empty mappings
    Existing starter e2e tests (38 passed, 5 skipped) are unaffected.

@hi-ogawa hi-ogawa self-assigned this Feb 25, 2026
@hi-ogawa hi-ogawa removed their assignment Feb 26, 2026
Copy link
Contributor

@hi-ogawa hi-ogawa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test added in this PR doesn't seem to fail on main. This doesn't serve as a test to verify the fix. Can you find proper reproduction?

The previous e2e test didn't fail on main because `map: null` doesn't
trigger Vite's 'Sourcemap is likely to be incorrect' warning — it
silently breaks the sourcemap chain.  The new vitest directly verifies
the transform returns a valid sourcemap (not null) with non-empty
mappings, which fails on main (3 failures) and passes with the fix.
@nianyi778
Copy link
Author

@hi-ogawa

You're right — the e2e test couldn't fail on main because map: null doesn't trigger Vite's "Sourcemap is likely to be incorrect" warning. It silently breaks the sourcemap chain instead. The downstream effect ("Can't resolve original location of error") only surfaces when other warnings/errors try to resolve locations through the broken chain, which doesn't happen in the minimal starter.

Replaced the e2e test with a vitest in src/core/plugin.test.ts that directly calls the transform handler and asserts the returned map is not null with valid mappings.

On main — 3 failures (expected null not to be null):

FAIL  src/core/plugin.test.ts > rsc:patch-react-server-dom-webpack > preserves sourcemap chain when replacing __webpack_require__
AssertionError: expected null not to be null
 ❯ src/core/plugin.test.ts:27:28

FAIL  src/core/plugin.test.ts > rsc:patch-react-server-dom-webpack > preserves sourcemap chain when replacing __webpack_require__.u
AssertionError: expected null not to be null
 ❯ src/core/plugin.test.ts:39:28

FAIL  src/core/plugin.test.ts > rsc:patch-react-server-dom-webpack > handles both patterns in the same source
AssertionError: expected null not to be null
 ❯ src/core/plugin.test.ts:57:28

With fix — all 61 tests pass (including the 4 new ones).

@nianyi778 nianyi778 requested a review from hi-ogawa February 27, 2026 00:57
@hi-ogawa hi-ogawa removed their request for review March 2, 2026 09:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants