Adding one export re-typechecks every route
Reproduction
https://github.com/Junk-debug/react-router-routemodules-repro
git clone https://github.com/Junk-debug/react-router-routemodules-repro
cd react-router-routemodules-repro
npm install && node bench.mjs
The script typechecks the project twice with the same edits
- without any changes in tsconfig
- with .react-router/types/+routes.ts excluded from tsconfig
and prints the results.
Because execution time is different on every machine, I recommend looking at the "largest SCC" row, it shows the biggest group of files that all depend on each other, directly or through other files.
Did not use the integration test template since this isn't a runtime bug, only type check
System Info
System:
OS: macOS 15.7.7
CPU: (11) arm64 Apple M3 Pro
Memory: 97.23 MB / 18.00 GB
Shell: 5.9 - /bin/zsh
Binaries:
Node: 22.22.3 - /Users/user/.nvm/versions/node/v22.22.3/bin/node
Yarn: 1.22.22 - /Users/user/.nvm/versions/node/v22.22.3/bin/yarn
npm: 10.9.8 - /Users/user/.nvm/versions/node/v22.22.3/bin/npm
pnpm: 11.15.1 - /Users/user/.nvm/versions/node/v22.22.3/bin/pnpm
bun: 1.2.23 - /Users/user/.bun/bin/bun
Browsers:
Chrome: 151.0.7922.175
Safari: 26.5
npmPackages:
@react-router/dev: ^8 => 8.3.1
@react-router/node: ^8 => 8.3.1
@react-router/serve: ^8 => 8.3.1
react-router: ^8 => 8.3.1
vite: ^8.0.3 => 8.2.2
Used Package Manager
npm
Expected Behavior
Editing a file should only re-typecheck the files that actually depend on it
Actual Behavior
Adding a single export to a leaf module used by just 2 out of 300 routes causes TypeScript to re-check 458 of 913 files, increasing check time from 0.08s to 0.79s.
The problem seems to come from +routes.ts. It imports every route through routeModules and also augments the react-router module. As a result, anything that imports react-router ends up transitively depending on every route, so TypeScript can't check them independently
NOTE: You won’t see this with noEmit, which is what create-react-router uses by default. Without declaration emit, incremental compilation doesn’t make a difference here. The repro uses emitDeclarationOnly to make the issue visible
This is a minimal reproduction, so the numbers are quite small, but on our project it takes up to ~90s to run typechecks even if only one file has changed
Source: remix-run/react-router