Skip to content

Commit fa0b6b6

Browse files
authored
fix: get resolve in externals should return query (#11276)
1 parent d851122 commit fa0b6b6

File tree

3 files changed

+43
-3
lines changed

3 files changed

+43
-3
lines changed

packages/rspack-test-tools/tests/configCases/externals/resolve-with-query/index.js

Whitespace-only changes.
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
const path = require("path");
2+
3+
/** @type {import("@rspack/core").Configuration} */
4+
module.exports = {
5+
externals: [
6+
async ({ context, getResolve }) => {
7+
const resolve = getResolve();
8+
expect(await resolve(context, "./index.js?foo=1#bar=1")).toBe(path.join(__dirname, "./index.js") + "?foo=1#bar=1");
9+
expect(
10+
await new Promise((promiseResolve, promiseReject) => {
11+
resolve(context, "./index.js?foo=1#bar=1", (err, result) => {
12+
if (err) {
13+
promiseReject(err);
14+
return;
15+
}
16+
promiseResolve(result);
17+
})
18+
})
19+
).toBe(path.join(__dirname, "./index.js") + "?foo=1#bar=1");
20+
return false;
21+
}
22+
]
23+
};

packages/rspack/src/builtin-plugin/ExternalsPlugin.ts

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,17 @@ export class ExternalsPlugin extends RspackBuiltinPlugin {
4848
return Object.assign({}, resolveRequest);
4949
};
5050

51+
// Reference: webpack/enhanced-resolve#255
52+
// Handle fragment escaping in resolve results:
53+
// - `#` can be escaped as `\0#` to prevent fragment parsing
54+
// - enhanced-resolve resolves `#` ambiguously as both path and fragment
55+
// - Example: `./some#thing` could resolve to `.../some.js#thing` or `.../some#thing.js`
56+
// - When `#` is part of the path, it gets escaped as `\0#` in the result
57+
// - We replace `\0#` with zero-width space + `#` (\u200b#) for compatibility
58+
#processRequest(req: ResolveRequest): string {
59+
return `${req.path.replace(/#/g, "\u200b#")}${req.query.replace(/#/g, "\u200b#")}${req.fragment}`;
60+
}
61+
5162
#getRawExternalItem = (item: ExternalItem | undefined): RawExternalItem => {
5263
if (typeof item === "string" || item instanceof RegExp) {
5364
return item;
@@ -68,7 +79,7 @@ export class ExternalsPlugin extends RspackBuiltinPlugin {
6879
issuer: data.contextInfo.issuer,
6980
issuerLayer: data.contextInfo.issuerLayer ?? null
7081
},
71-
getResolve(options) {
82+
getResolve: options => {
7283
const rawResolve = options ? getRawResolve(options) : undefined;
7384
const resolve = ctx.getResolve(rawResolve);
7485

@@ -83,7 +94,11 @@ export class ExternalsPlugin extends RspackBuiltinPlugin {
8394
callback(error);
8495
} else {
8596
const req = processResolveResult(text);
86-
callback(null, req?.path ?? false, req);
97+
callback(
98+
null,
99+
req ? this.#processRequest(req) : false,
100+
req
101+
);
87102
}
88103
});
89104
} else {
@@ -93,7 +108,9 @@ export class ExternalsPlugin extends RspackBuiltinPlugin {
93108
promiseReject(error);
94109
} else {
95110
const req = processResolveResult(text);
96-
promiseResolve(req?.path);
111+
promiseResolve(
112+
req ? this.#processRequest(req) : undefined
113+
);
97114
}
98115
});
99116
});

0 commit comments

Comments
 (0)