fix: keep source map source names as emitted in maps and stack frames - #1470
Merged
Merged
Conversation
Babel and swc were given `sourceRoot: this.context` alongside an absolute `sourceFileName`. Webpack, and Rspack whenever Babel produced the map, prepend `sourceRoot` to the absolute source, so project files and workspace packages were named `src/<dir>/<absolute path>` in development and release source maps. `source-map` normalises every source name through `new URL()`, so the dev server returned `[projectRoot%5E2]/...` for files outside the project root and encoded any path with a space or non-ASCII character. That name reached LogBox, `/open-stack-frame` and the no-sources fallback, none of which resolve an encoded placeholder. Source names are now escaped before the consumer reads the map and decoded on the way out, and `parseUrl` returns a decoded path. Fixes #1468
🦋 Changeset detectedLatest commit: 5c8f026 The changes in this PR will be included in the next version bump. This PR includes changesets to release 6 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #1468.
This fixes both bugs from the issue, using the corrected root cause from the follow-up comment. Checking further showed the scope is wider than the issue describes, in three ways:
sourceRootfor swc output. When Babel writes the map (@callstack/repack/babel-loader, orbabel-swc-loaderwithout swc), Rspack names filessrc/<dir>/<absolute path>too. Workspace packages in a monorepo get the same doubled name.^.source-mappasses every source name throughnew URL(). That encodes spaces and non-ASCII characters (Home Screen.tsx,Écran.tsx), so standalone apps are affected too, not just files outside the project root.%5Ecomes fromsource-map, notparseUrl, as the follow-up showed. Decoding only inparseUrlbrings back the code frame, but the responsefilestays encoded, so tapping a frame in LogBox still does nothing.Changes
sourceRoot: this.contextfrombabelLoaderand both transforms inbabelSwcLoader. Upstreambabel-loaderdoesn't set it either. It can still be set throughbabelOverrides/swcOverrides.prepareSourceMap(renamed fromnormalizeInvalidWebpackSourceUrls) escapes%in every source name beforeSourceMapConsumerreads the map.decodeURIComponentis then an exact inverse of the consumer's encoding, solookup.sourcecomes back exactly as the bundler emitted it. A file name that really contains%is not decoded twice. The embedded-content lookup re-escapes the name, sosourceContentForstill matches. That one change fixes the/symbolicateresponse,/open-stack-frameand theSymbolicated stack framelog line.parseUrl: returns the decoded pathname, falling back to the raw path if the escape sequence is malformed.symbolicator.getSourcepasses it raw file names, and the asset route passes a param Fastify has already decoded.new URL()was encoding both again.The 5.4 canary changes are all kept. #1434 (remote source URLs):
__repack_source__URLs still come out encoded, andgetRemoteSourceandgetPrintableFiledecode them as before (there's a test for this). #1446 (getSourcewith absolute paths) is untouched and now actually gets used fornosources-*maps.Tests
tests/integration/src/loaders/source-map-sources.test.ts(new). It compiles a small on-disk project with webpack and Rspack, through bothbabel-loaderandbabel-swc-loader, and checks that every file is named once by its absolute path in the source map. The project has app files, a space in a path, a localnode_modulesdependency, a hoistednode_modulesdependency and a workspace package. Onmain, 3 of 4 cases fail; only Rspack + swc passes. With the fix, all 4 pass, in about 0.4s.@swc/coreis linked into the fixture so webpack exercises the swc path too, andhermes-parseris added as a test dev dependency. The project is written to a temp directory, asNativeEntryPlugin.srcLayout.test.tsalready does.Symbolicator.test.ts: covers[projectRoot^2], a space, non-ASCII, a literal%25and an absolute path with a space. For each it checks the framefile, the code frame from embedded content, and the no-sources fallback, wheregetSourcemust receive the raw name. It also checks that remote__repack_source__URLs stay encoded, and that the log line strips a[projectRoot^N]placeholder. Onmain, 11 of these fail.parseUrl.test.ts/resolveProjectPath.test.ts: decoded paths, malformed escapes, andparseUrl→resolveProjectPathcomposed the way the dev server does it.Manual verification
apps/tester-appwithdevtool: 'nosources-source-map'on both bundlers. I symbolicated a frame fromsrc/App.tsxand one fromreact-native/.../ActionSheetIOS.jswithcurl, then posted each result to/open-stack-framewithREACT_EDITORpointing at a stub script that records its arguments:[projectRoot]/sources / doubledsrc/App.tsxframefile[projectRoot]/src/App.tsx[projectRoot]/src/App.tsxfile[projectRoot^2]/node_modules/...[projectRoot^2]/node_modules/...Known limitation
A literal
%XXsequence in a directory name is now decoded byparseUrl, sosymbolicator.getSourceor an asset request for it would look up the decoded name. Asset file names are already sanitised to[a-z0-9_], and the Symbolicator keeps literal%exact. In return, paths with spaces, non-ASCII characters or^now work, which is far more common.