Visitar URL original
fix(new-url): keep the query and fragment when rewriting `new URL()` … · rolldown/rolldown@fa2038a · GitHub
Skip to content

Commit fa2038a

Browse files
theRizwanhyfdev
andauthored
fix(new-url): keep the query and fragment when rewriting new URL() (#11420)
Fixes case 3 of #11325. Case 1 is #11418 and case 2 is #11419; this one is independent of both. ## Problem With `experimental.resolveNewUrlToAsset`, the query and fragment were dropped when `new URL()` was rewritten: ```js new URL("./sprite.svg?v=1", import.meta.url) // -> new URL("assets/sprite-[hash].svg", import.meta.url) new URL("./sprite.svg#icon", import.meta.url) // -> new URL("assets/sprite-[hash].svg", import.meta.url) ``` so `url.search` and `url.hash` were lost, which breaks uses like SVG sprite fragments. ## Fix In the `new URL()` finalizer, after computing the asset path, append the part of the original specifier that follows the path (everything from the first `?` or `#`, using `clean_url`). This matches Vite's `vite:asset-import-meta-url`, which keeps the postfix when it rewrites the URL. Resolution and the emitted asset are unchanged: all of `?v=1`, `#icon`, `?v=1#icon` and the plain path still share one emitted file. ## Tests New fixture `topics/new_url/keep_query_and_hash` covering a query, a fragment, both, and the plain path. With snapshot updates disabled (`INSTA_UPDATE=no CI=true`) it fails on `main` and passes here. No existing snapshot changed. `cargo test -p rolldown` passes except `test262_module_code`, which fails the same way on `main` locally because the `test262` submodule is not checked out. `cargo fmt --check` and `cargo clippy -p rolldown --all-targets` are clean. AI disclosure: I used Claude Code to help trace the code path and write the change and test. I reviewed the change and ran the tests above myself. Co-authored-by: Yunfei He <i.heyunfei@gmail.com>
1 parent 3ebda9a commit fa2038a

5 files changed

Lines changed: 37 additions & 1 deletion

File tree

‎crates/rolldown/src/module_finalizers/mod.rs‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ use oxc_str::{CompactStr, Ident};
3636
use rolldown_std_utils::absolutize_path_buf;
3737
use rolldown_utils::ecmascript::is_validate_identifier_name;
3838
use rolldown_utils::indexmap::{FxIndexMap, FxIndexSet};
39+
use rolldown_utils::url::clean_url;
3940
use rustc_hash::{FxHashMap, FxHashSet};
4041
use sugar_path::SugarPath;
4142

@@ -1505,7 +1506,10 @@ impl<'me, 'ast> ScopeHoistingFinalizer<'me, 'ast> {
15051506
let ref_id = self.ctx.file_emitter.file_ref_for_module(&importee.id)?;
15061507
let filename = self.ctx.file_emitter.get_file_name(&ref_id).ok()?;
15071508
let abs_path = self.ctx.options.cwd.join(&self.ctx.options.out_dir).join(filename.as_str());
1508-
let import_path = self.ctx.chunk.relative_path_for(abs_path.as_path());
1509+
let mut import_path = self.ctx.chunk.relative_path_for(abs_path.as_path());
1510+
// Keep the query and fragment, e.g. `sprite.svg#icon`, since they are part of the URL.
1511+
let specifier = rec.module_request.as_str();
1512+
import_path.push_str(&specifier[clean_url(specifier).len()..]);
15091513

15101514
*first_arg_expr = ast::Expression::new_string_literal(
15111515
first_arg_expr.span(),
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"config": {
3+
"dir": "dist",
4+
"experimental": {
5+
"resolveNewUrlToAsset": true
6+
}
7+
}
8+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
---
2+
source: crates/rolldown_testing/src/integration_test.rs
3+
---
4+
# Assets
5+
6+
## assets/sprite-BZcw_Can.svg
7+
8+
## main.js
9+
10+
```js
11+
// main.js
12+
const query = new URL("assets/sprite-BZcw_Can.svg?v=1", import.meta.url).href;
13+
const hash = new URL("assets/sprite-BZcw_Can.svg#icon", import.meta.url).href;
14+
const both = new URL("assets/sprite-BZcw_Can.svg?v=1#icon", import.meta.url).href;
15+
const plain = new URL("assets/sprite-BZcw_Can.svg", import.meta.url).href;
16+
export { both, hash, plain, query };
17+
18+
```
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// The query and fragment are part of the URL and must survive the rewrite.
2+
export const query = new URL('./sprite.svg?v=1', import.meta.url).href;
3+
export const hash = new URL('./sprite.svg#icon', import.meta.url).href;
4+
export const both = new URL('./sprite.svg?v=1#icon', import.meta.url).href;
5+
export const plain = new URL('./sprite.svg', import.meta.url).href;
Lines changed: 1 addition & 0 deletions
Loading

0 commit comments

Comments
 (0)