vercel / vercel/next.js

Turbopack: `productionBrowserSourceMaps: true` disables dead-import elimination for `compiler.define`-folded `typeof` guards

Open
#97,791 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Performance Turbopack
Dominant language
JavaScript
Stars
142k
Forks
32.4k
Avg merge
2d 14h
Merged PRs (30d)
351

Description

Link to the code that reproduces this issue

https://github.com/kevbarns/turbopack-define-sourcemaps-repro

To Reproduce
  1. npm install && npx next build
  2. grep -rl "FEATURE_MARKER_SHOULD_BE_TREESHAKEN" .next/static/chunks/

The repro has a local package (fake-sdk, sideEffects: false) that guards an import behind the universal SDK tree-shaking-flag pattern, with the flag set via compiler.define:

// fake-sdk/index.js
import { feature } from './feature.js'

function getDefaultIntegrations() {
  const integrations = [];
  if (typeof __MY_FLAG__ === 'undefined' || __MY_FLAG__) {
    integrations.push(feature());
  }
  return integrations;
}
// next.config.mjs
const nextConfig = {
  productionBrowserSourceMaps: true,
  compiler: {
    define: { __MY_FLAG__: false },
  },
}
Current vs. Expected behavior
Guard in the package productionBrowserSourceMaps Dead module in the client bundle?
typeof __MY_FLAG__ === 'undefined' || __MY_FLAG__ not set pruned ✔
typeof __MY_FLAG__ === 'undefined' || __MY_FLAG__ true bundled ✗ (this issue)
if (__MY_FLAG__) true pruned ✔

Expected: enabling browser source maps should not change which modules are considered live. The guarded branch is dead either way (the call site is correctly eliminated from the emitted code in all cases) — but with source maps enabled, the import it referenced is kept in the module graph and the whole subtree is emitted.

Reproduced on next 16.3.0, 16.3.2 and 16.4.0-canary.3.

Provide environment information
Operating System:
  Platform: darwin
  Arch: arm64
  Version: Darwin Kernel Version 25.5.0
  Available memory (MB): 65536
  Available CPU cores: 14
Binaries:
  Node: 24.11.1
  npm: 11.6.2
Relevant Packages:
  next: 16.4.0-canary.3 // also reproduced on 16.3.0 and 16.3.2
  react: 19.2.4
  react-dom: 19.2.4
Next.js Config:
  output: N/A
Which area(s) are affected? (Select all that apply)

Turbopack, Performance

Additional context

Real-world impact: typeof __FLAG__ === 'undefined' || __FLAG__ is the universal guard used by SDK tree-shaking flags — e.g. Sentry's __SENTRY_TRACING__ / __SENTRY_DEBUG__ (which the Sentry docs suggest wiring through compiler.define on Turbopack). Sentry users are hit by the combination almost by definition: they enable productionBrowserSourceMaps precisely to upload source maps to Sentry, which silently makes the flags inoperative. On our production Next.js app this keeps ~30 KB minified of unreachable tracing code in the first load. Downstream report with measurements: https://github.com/getsentry/sentry-javascript/issues/23482

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the linked reproduction, especially fake-sdk/index.js and next.config.mjs, then run npm install && npx next build and grep the generated chunks for FEATURE_MARKER_SHOULD_BE_TREESHAKEN. Trace the Turbopack build behavior with productionBrowserSourceMaps enabled; done means the guarded module subtree is absent from the client bundle while source maps remain enabled.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, nextjs
Domain
build-system, performance
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.