Skip to content

fix: ensure route chunk names are relative instead of absolute paths - #112

Closed
alvadorn wants to merge 1 commit into
rstackjs:mainfrom
alvadorn:fix/route-chunk-entry-names
Closed

fix: ensure route chunk names are relative instead of absolute paths#112
alvadorn wants to merge 1 commit into
rstackjs:mainfrom
alvadorn:fix/route-chunk-entry-names

Conversation

@alvadorn

Copy link
Copy Markdown
Contributor

Symptom

With splitRouteModules enabled, routes using relative() without an explicit id emit absolute filesystem paths as part of their chunk names (e.g.,
/Users/<user>/...). This breaks build reproducibility, causes invalid asset URLs (double slashes), and leaks local path structures.

Root Cause

The plugin used route.id as the entry filename. While the manifest relativizes route.file, it keeps route.id absolute. When relative() is used, the id becomes
an absolute path, which the plugin then treated as a directory tree for the output.

The Fix

Introduced getRouteEntryBaseName(route, appDirectory) to derive both the main route entry and its chunks from a shared, relative base.

This shared helper also adds safety against:

  • Path traversal: Collapses segments attempting to escape static/js/.
  • Windows paths: Strips drive prefixes (e.g., C:\).

Behavior Change

  • Cache-busting: Routes with explicit ids now use file-based names instead of id-based names. This is a rename, not a logic change.
  • Deduplication: Routes pointing to the same file now share a single chunk entry.
  • Collision prevention: Prevs collision between different files that previously shared the same id.

Tests

  • Unit tests for naming rules (relative, absolute, traversal, and Windows).
  • Integration tests reproducing the absolute path/double-slash symptom in a full production build.

`relative()` from `@react-router/dev/routes` resolves route files to
absolute paths, so React Router relativizes `file` but leaves `id`
absolute. The plugin used that opaque id as an rspack entry name, so
split route module chunks were emitted into a directory tree mirroring
the developer's checkout, and the browser manifest published those
paths -- leaking $HOME into production assets and making builds
unreproducible across machines and CI.

The main route entry already derived its name from `route.file`, twenty
lines above the chunk entry that derived it from `route.id`. Both now
go through one shared `getRouteEntryBaseName`, so a chunk lands beside
its route, the `/static/js//...` double slash is gone, and an entry can
no longer escape the JS output directory or carry a Windows drive
prefix. Routes sharing a file now share one chunk instead of emitting
byte-identical duplicates.

Route ids are untouched: they remain the runtime contract behind
`useRouteLoaderData(id)` and `matches[].id`.
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