Skip to content

fix(react-router): prevent webpack static analysis of React.use with let binding#7182

Open
mixelburg wants to merge 1 commit intoTanStack:mainfrom
mixelburg:fix/react-use-webpack-regression
Open

fix(react-router): prevent webpack static analysis of React.use with let binding#7182
mixelburg wants to merge 1 commit intoTanStack:mainfrom
mixelburg:fix/react-use-webpack-regression

Conversation

@mixelburg
Copy link
Copy Markdown

@mixelburg mixelburg commented Apr 13, 2026

Fixes #7176

In #6926, the const REACT_USE = 'use' statement started getting optimized away by the bundler (constant folding), replacing React[REACT_USE] with React['use'] in the published ESM output. This caused Webpack to fail on React 18 apps again since it statically analyzes the 'use' property access.

Changing const to let prevents the bundler from inlining the string literal, restoring the dynamic lookup behaviour in the compiled output:

let REACT_USE = 'use';
var reactUse = React[REACT_USE];

Summary by CodeRabbit

Release Notes

No user-visible changes. This release contains internal code optimizations that do not affect application functionality or behavior.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 13, 2026

📝 Walkthrough

Walkthrough

Changed REACT_USE from a const to a let variable in utils.ts to prevent webpack bundler optimization. This preserves the dynamic property access pattern React[REACT_USE] during build, avoiding failures when bundling with React 18.

Changes

Cohort / File(s) Summary
Webpack Optimization Fix
packages/react-router/src/utils.ts
Changed REACT_USE declaration from const to let to prevent bundler optimization that interferes with dynamic property access to React[REACT_USE].

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~2 minutes

Poem

A rabbit hops through webpack's code,
Where constants once did firmly load,
But now with let, the way stays free,
Dynamic access flows with glee,
React.use stays out of sight! 🐰✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately describes the main change: converting const to let binding to prevent webpack's static analysis of React.use.
Linked Issues check ✅ Passed The code change directly addresses issue #7176 by converting const REACT_USE to let REACT_USE to prevent constant folding and restore dynamic lookup.
Out of Scope Changes check ✅ Passed The single-line change (const to let) is narrowly scoped and directly targets the regression without introducing unrelated modifications.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Copy Markdown
Contributor

Bundle Size Benchmarks

  • Commit: f1a4973d41dc
  • Measured at: 2026-04-13T22:10:35.420Z
  • Baseline source: history:7324b98d114b
  • Dashboard: bundle-size history
Scenario Current (gzip) Delta vs baseline Raw Brotli Trend
react-router.minimal 87.33 KiB 0 B (0.00%) 274.58 KiB 75.97 KiB █▇▇▇▇▇▁▁▁▁▁
react-router.full 90.59 KiB 0 B (0.00%) 285.66 KiB 78.72 KiB ██████▁▁▁▁▁
solid-router.minimal 35.50 KiB 0 B (0.00%) 106.58 KiB 31.88 KiB █▇▇▇▇▇▁▁▁▁▁
solid-router.full 39.98 KiB 0 B (0.00%) 120.08 KiB 35.93 KiB ██████▁▁▁▁▁
vue-router.minimal 53.30 KiB 0 B (0.00%) 151.99 KiB 47.86 KiB ██████▁▁▁▁▁
vue-router.full 58.19 KiB 0 B (0.00%) 167.41 KiB 52.09 KiB ██████▁▁▁▁▁
react-start.minimal 101.73 KiB 0 B (0.00%) 322.31 KiB 87.94 KiB ██████▁▁▁▁▁
react-start.full 105.17 KiB 0 B (0.00%) 332.64 KiB 90.84 KiB █▇▇▇▇▇▁▁▁▁▁
solid-start.minimal 49.50 KiB 0 B (0.00%) 152.39 KiB 43.63 KiB ██████▁▁▁▁▁
solid-start.full 55.03 KiB 0 B (0.00%) 168.60 KiB 48.41 KiB ██████▁▁▁▁▁

Trend sparkline is historical gzip bytes ending with this PR measurement; lower is better.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/react-router/src/utils.ts`:
- Line 7: Replace the silent use of let REACT_USE = 'use' with an inline ESLint
disable comment that documents why mutable binding is intentional; specifically
add a comment like /* eslint-disable-next-line prefer-const -- mutable binding
prevents bundlers from constant-folding the string so React[REACT_USE] remains
dynamic */ directly above or on the REACT_USE declaration to suppress
prefer-const and explain the rationale (symbol: REACT_USE in
packages/react-router/src/utils.ts).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: efaa0812-1371-418a-9f88-75a286f37e12

📥 Commits

Reviewing files that changed from the base of the PR and between f1a4973 and 22a3484.

📒 Files selected for processing (1)
  • packages/react-router/src/utils.ts

// sees React.use referenced (since 'use' is not exported from React 18).
// This uses a dynamic string lookup to avoid the static analysis.
const REACT_USE = 'use'
let REACT_USE = 'use'
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Verify the build output preserves dynamic lookup pattern and doesn't inline 'use'

# Build the package (adjust command as needed for your build setup)
# Then search the compiled output for the pattern

fd --type f --extension js --extension mjs . packages/react-router/dist packages/react-router/build 2>/dev/null | head -20 | xargs rg -l "REACT_USE|React\[|\.use" 2>/dev/null || echo "Note: Build output directory not found. Please build the package first and inspect the ESM output manually."

Repository: TanStack/router

Length of output: 50371


🏁 Script executed:

cat -n packages/react-router/src/utils.ts | head -50

Repository: TanStack/router

Length of output: 1988


🏁 Script executed:

rg "eslint-disable" packages/react-router/src/utils.ts

Repository: TanStack/router

Length of output: 41


Add ESLint suppression comment to explain the intentional use of let.

Line 7 uses let instead of const to prevent bundlers from constant-folding the string literal, ensuring the dynamic lookup pattern React[REACT_USE] is preserved in compiled output rather than being inlined as React["use"]. ESLint's prefer-const rule will flag this as an issue since the variable is never reassigned, but the mutable binding is necessary for this optimization strategy.

Add an ESLint disable comment with a clear explanation:

🔧 Proposed fix
 // This uses a dynamic string lookup to avoid the static analysis.
+// eslint-disable-next-line prefer-const -- Must be `let` to prevent bundler constant-folding
 let REACT_USE = 'use'
🧰 Tools
🪛 ESLint

[error] 7-7: 'REACT_USE' is never reassigned. Use 'const' instead.

(prefer-const)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/react-router/src/utils.ts` at line 7, Replace the silent use of let
REACT_USE = 'use' with an inline ESLint disable comment that documents why
mutable binding is intentional; specifically add a comment like /*
eslint-disable-next-line prefer-const -- mutable binding prevents bundlers from
constant-folding the string so React[REACT_USE] remains dynamic */ directly
above or on the REACT_USE declaration to suppress prefer-const and explain the
rationale (symbol: REACT_USE in packages/react-router/src/utils.ts).

@schiller-manuel
Copy link
Copy Markdown
Contributor

this feels like a "hacky" workaround... let's see if we can make this work reliably

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Regression: React.use build error with React 18 and Webpack

2 participants