Skip to content

fix: improve sourcemap resolution for Turbopack and bundled code#67

Open
mcollina wants to merge 2 commits intomainfrom
fix/turbopack-sourcemap-resolution
Open

fix: improve sourcemap resolution for Turbopack and bundled code#67
mcollina wants to merge 2 commits intomainfrom
fix/turbopack-sourcemap-resolution

Conversation

@mcollina
Copy link
Member

@mcollina mcollina commented Feb 6, 2026

Summary

  • Fixes sourcemap resolution for Next.js apps using Turbopack where mappings don't start at column 0
  • Extracts function names from embedded sourcesContent when sourcemap name mappings are missing (resolves minified React names like eYgetCustomFormFields)

Problem

When profiling Next.js applications with Turbopack:

  1. Position lookup failures: Turbopack generates minified files where actual code mappings start at column 300+, but V8 captures positions at the beginning of lines. The default exact-match lookup fails.

  2. Missing function names: Next.js bundles React with file/line mappings but without function name mappings, resulting in profiles showing minified names like eY, ak, al instead of renderElement, performWork, etc.

Solution

  1. LEAST_UPPER_BOUND bias: When exact position lookup fails, try finding the nearest mapping to the right using sourceMap.SourceMapConsumer.LEAST_UPPER_BOUND.

  2. Function name extraction: When no name is in the sourcemap, parse the embedded sourcesContent to extract function names from the source line (handles function declarations, async functions, arrow functions, methods, and object properties).

Before/After

Before:

| 1 | `eY` | 14.3% | `app-page-turbo.runtime.prod.js:5` |
| 2 | `ak` → `al` → `ai` → `aa` ... |

After:

| 1 | `renderElement` | 14.3% | `page.tsx:38` |
| 2 | `performWork` → `retryNode` → `renderElement` → `finishFunctionComponent` |

Test plan

  • Added 17 new tests for the enhancement
  • All 90 tests pass
  • Manually tested with Next.js 16 + Turbopack

🤖 Generated with Claude Code

mcollina and others added 2 commits February 6, 2026 15:54
Two enhancements to sourcemap handling:

1. Use LEAST_UPPER_BOUND bias when exact position lookup fails. Turbopack
   and other bundlers generate minified files where actual code mappings
   start at column 300+, but V8 captures positions at the beginning of
   lines. The bias finds the nearest mapping to the right.

2. Extract function names from sourcesContent when sourcemap name mappings
   are missing. Next.js bundles React with file/line mappings but without
   function name mappings. This parses the embedded source to resolve
   minified names like 'eY' back to 'getCustomFormFields'.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add comprehensive tests for the enhanced sourcemap resolution:

- extractFunctionName helper tests for various function patterns
  (declarations, async, arrow, methods, object properties)
- LEAST_UPPER_BOUND bias test with synthetic Turbopack-style sourcemap
- sourcesContent function name extraction tests
- Integration test with SourceMapper

Also fixes extractFunctionName to:
- Properly match object property functions (name: function)
- Exclude control flow keywords (if, for, while, etc.)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@mcollina mcollina requested a review from Qard February 6, 2026 16:37
@mischnic
Copy link

mischnic commented Feb 6, 2026

where mappings don't start at column 0

You mean like this? That the module.exports= doesn't have a mapping?

Bildschirmfoto 2026-02-06 um 17 44 41

@mcollina
Copy link
Member Author

mcollina commented Feb 6, 2026

Yes, exactly! The module.exports=[...] loader wrapper at the beginning of the line has no sourcemap mappings.

When V8 captures a stack frame, it reports positions like (line: 1, column: 1). The default originalPositionFor() lookup fails because there's no mapping at column 1 - the first mapping might be at column 300+ where the actual application code starts.

Using LEAST_UPPER_BOUND bias finds the nearest mapping to the right of the requested position, which correctly resolves to the original source file.

For example in the Turbopack chunks I was testing:

Line 1: module.exports=[93695,(a,b,c)=>{...actual code at col 341+...
                                        ^-- first mapping starts here
        ^-- V8 reports position here (col 1), no mapping exists

@lukesandberg
Copy link

We have added names field population as of vercel/next.js#87911 which is available in canary releases. should go out in 16.2

As for using LEAST_UPPER_BOUND, isn't that possibly wrong? If v8 is saying a lot of time is spent parsing/evaluating the module.exports=... line, then it isn't correct to attribute it to the first module.

Wouldn't using some kind of generic unmapped marker be better?

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.

3 participants