Skip to content

feat(react)!: extract React Router relaxations into an optional group - #42

Merged
stevensacks merged 1 commit into
mainfrom
feat/optional-react-router-group
Jul 22, 2026
Merged

feat(react)!: extract React Router relaxations into an optional group#42
stevensacks merged 1 commit into
mainfrom
feat/optional-react-router-group

Conversation

@stevensacks

Copy link
Copy Markdown
Contributor

What

react shipped a block scoped to **/routes/**/*.tsx that turned no-empty-pattern off. That glob is not unique to React Router, since TanStack Router uses a routes/ directory too, so a project on any other file-based router had the rule silently disabled across its whole route tree with nothing in the composed config explaining why.

The relaxation moves into a new opt-in reactRouter block:

...lint.react,
...lint.reactRouter,   // React Router framework mode only

Why this is a major

Unlike storybook and playwright, which only ever add rules, this block is subtractive. Making a subtractive block opt-in is inherently breaking: React Router consumers must add the spread to keep current behavior. Migration is that one line, and a project that never writes ({}: Route.ComponentProps) sees no new errors either way.

Verification

Measured against GAIA's real tree rather than assumed:

  • ({}: Route.ComponentProps) errors outside routes/ and is suppressed inside it, so the exemption is load-bearing rather than vestigial.
  • no-empty-pattern forced on across app/routes reports zero violations today, so GAIA's own upgrade is a no-op.
  • New suite asks ESLint what the composed config resolves to on both sides of the opt-in, so folding the block back into react, or widening its glob, fails a test instead of quietly relaxing a rule.

Dead config removed

Two entries in the blocks being touched, both verified to change no effective rule anywhere:

  • react/display-name was set to off in the route block, but airbnb/config/react already sets it off for every file.
  • The typescript/only-throw-error block disabled that rule for hooks/, routes/, and sessions.server/, but typescript/config already disables it globally for **/*.ts?(x).

Notes

The /.react-router/** glob stays in the ignores defaults. It names a directory that only exists in a React Router project, so it costs other projects nothing, while moving it would break React Router consumers who miss the new spread.

A TanStack Router group (wrapping @tanstack/eslint-plugin-router) is deliberately not in this PR. It is purely additive, so it can land as a minor without a migration.

An audit of the whole composed config turned up ~28 further dead rule entries beyond the two removed here. Out of scope for this PR; will be raised separately.

🤖 Generated with Claude Code

https://claude.ai/code/session_01MN1TCLUXUHLv9PBPBaL3fg

`react` shipped a block scoped to `**/routes/**/*.tsx` that turned
`no-empty-pattern` off. That glob is not unique to React Router, since
TanStack Router uses a `routes/` directory too, so a project on any other
file-based router had the rule silently disabled across its whole route
tree with nothing in the composed config explaining why.

The relaxation moves to a new opt-in `reactRouter` block, spread after
`react`. Unlike `storybook` and `playwright`, which only add rules, this
block is subtractive, which is why making it opt-in is a breaking change:
React Router consumers must add the spread to keep current behavior.

Verified against GAIA's real tree: `({}: Route.ComponentProps)` errors
outside `routes/` and is suppressed inside it, so the exemption is
load-bearing rather than vestigial.

Also removes two dead config entries found while auditing the composition.
Neither changes any effective rule:

- `react/display-name` was set to `off` in the route block, but
  `airbnb/config/react` already sets it to `off` for every file.
- The `typescript/only-throw-error` block disabled that rule for `hooks/`,
  `routes/`, and `sessions.server/`, but `typescript/config` already
  disables it globally for `**/*.ts?(x)`.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MN1TCLUXUHLv9PBPBaL3fg
@stevensacks
stevensacks merged commit b364e99 into main Jul 22, 2026
1 check passed
@stevensacks
stevensacks deleted the feat/optional-react-router-group branch July 22, 2026 07:17
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.

1 participant