Skip to content

fix: use sanitized filename for chunk name with preserveModulesRoot#8817

Closed
younggglcy wants to merge 10 commits into
rolldown:mainfrom
younggglcy:younggglcy/fix-sanitize-name
Closed

fix: use sanitized filename for chunk name with preserveModulesRoot#8817
younggglcy wants to merge 10 commits into
rolldown:mainfrom
younggglcy:younggglcy/fix-sanitize-name

Conversation

@younggglcy

@younggglcy younggglcy commented Mar 20, 2026

Copy link
Copy Markdown
Contributor

Summary

  • When preserveModulesRoot is set, the chunk name was derived from the unsanitized absolute filename, causing query string characters (?, &) to leak into chunk.name and subsequently into fileName when entryFileNames is a function
  • This affected Vue SFC virtual modules (e.g. Comp.vue?vue&type=script&setup=true&lang.ts) in Vite lib mode, producing invalid filenames like Comp.vue?vue&type=script&setup=true&lang.js
  • Fix: use the already-sanitized filename (sanitized_absolute_filename) instead of the raw one (absolute_chunk_file_name) when stripping the preserveModulesRoot prefix

Closes #8761

Test plan

  • Added test fixture sanitize-filename-query-string that reproduces the bug with preserveModulesRoot + function-form entryFileNames + query string module IDs
  • Verified existing sanitize-filename test still passes
  • Verified with the reproduction repo

@codspeed-hq

codspeed-hq Bot commented Mar 20, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 4 untouched benchmarks
⏩ 10 skipped benchmarks1


Comparing younggglcy:younggglcy/fix-sanitize-name (553dde9) with main (a52d258)2

Open in CodSpeed

Footnotes

  1. 10 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

  2. No successful run was found on main (a41a709) during the generation of this report, so a52d258 was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

Copilot AI left a comment

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.

Pull request overview

Fixes preserve-modules chunk naming so that when preserveModulesRoot is set, the computed chunk.name (and therefore fileName when entryFileNames is a function) is derived from a sanitized filename, preventing query-string characters from leaking into output filenames (e.g., Vue SFC virtual module ids).

Changes:

  • Use sanitized_absolute_filename (instead of the raw absolute filename) when stripping the preserveModulesRoot prefix during chunk name generation.
  • Add a new preserve-modules fixture to cover query-string virtual module ids with function-form entryFileNames.
  • Add a minimal entry module for the new fixture.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
crates/rolldown/src/stages/generate_stage/mod.rs Ensures chunk name prefix-stripping uses the sanitized path so chunk.name/fileName can’t include ?/&.
packages/rolldown/tests/fixtures/topics/preserve-modules/sanitize-filename-query-string/_config.ts Adds regression test that asserts chunk.name and chunk.fileName don’t contain query-string characters under preserveModulesRoot + function entryFileNames.
packages/rolldown/tests/fixtures/topics/preserve-modules/sanitize-filename-query-string/entry.js New fixture entry that imports the virtual module used by the regression test.

hyfdev
hyfdev previously approved these changes Mar 20, 2026

@hyfdev hyfdev left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM. Looks like related to preserveModules, so @IWANABETHATGUY cc

Comment thread crates/rolldown/src/stages/generate_stage/mod.rs Outdated
if let Some(ref preserve_modules_root) = preserve_modules_root {
if absolute_chunk_file_name.starts_with(preserve_modules_root.as_str()) {
absolute_chunk_file_name[preserve_modules_root.len()..]
if sanitized_absolute_filename.starts_with(preserve_modules_root.as_str()) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think this will incorrectly match when two directories are sanitized to the same value:

  • preserve_modules_root: './somewhere/foo+bar' -> (sanitized) ./somewhere/foo__bar
  • chunk 1 filename: ./somewhere/foo+bar/baz.js -> (sanitized) ./somewhere/foo__bar/baz.js
  • chunk 2 filename: ./somewhere/foo#bar/baz.js -> (sanitized) ./somewhere/foo__bar/baz.js

younggglcy and others added 8 commits April 15, 2026 23:48
…eserveModulesRoot

When preserveModulesRoot is set, the chunk name was derived from the
unsanitized absolute filename, causing query string characters (? &) to
leak into chunk.name and subsequently into fileName when entryFileNames
is a function. This affected Vue SFC virtual modules in Vite lib mode.

Closes rolldown#8761
…ized filenames

When a custom sanitizeFileName transforms characters in the root path
(e.g. '+' → '__'), the starts_with check against the sanitized absolute
filename would fail, producing invalid relative paths like '../__libs/helper'.
Derive preserve-modules names from the original path and reuse the computed pre-rendered name when rendering filenames. This prevents sanitized path prefixes from flattening sibling directories onto the same preserveModulesRoot output.

Made-with: Cursor
@younggglcy
younggglcy force-pushed the younggglcy/fix-sanitize-name branch from d4be8b2 to d6431c0 Compare April 15, 2026 15:55
autofix-ci Bot and others added 2 commits April 15, 2026 15:56
Align the issue 7146 Rust snapshot with the corrected preserveModules output name so JSON inputs keep their .json segment before the generated .js extension.

Made-with: Cursor
Comment on lines -247 to -248
if let Some(ref preserve_modules_root) = options.preserve_modules_root {
if chunk_name.starts_with(preserve_modules_root) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think this has the same problem with #8817 (comment)

@younggglcy

Copy link
Copy Markdown
Contributor Author

Thanks a lot for the patient reviews here. This needs a broader
design pass than I can take on, so I'll close in favor of leaving
it open for someone else to pick up.

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.

[Bug]: sanitizeFileName is ignored for JS chunks when preserveModules: true with object-form entry

5 participants