Skip to content

Commit 91ab67b

Browse files
committed
fix(externals): use resolver to resolve request
1 parent f145f6a commit 91ab67b

File tree

28 files changed

+315
-115
lines changed

28 files changed

+315
-115
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464
},
6565
"pnpm": {
6666
"overrides": {
67+
"@rspack/core": "npm:@rspack/[email protected]",
6768
"zx>@types/node": "-"
6869
}
6970
}

packages/core/src/config.ts

Lines changed: 40 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
type EnvironmentConfig,
55
type RsbuildConfig,
66
type RsbuildPlugin,
7+
type Rspack,
78
defineConfig as defineRsbuildConfig,
89
loadConfig as loadRsbuildConfig,
910
mergeRsbuildConfig,
@@ -36,6 +37,7 @@ import type {
3637
DeepRequired,
3738
ExcludesFalse,
3839
Format,
40+
GetAsyncFunctionFromUnion,
3941
LibConfig,
4042
LibOnlyConfig,
4143
PkgJson,
@@ -60,6 +62,7 @@ import {
6062
isEmptyObject,
6163
isObject,
6264
nodeBuiltInModules,
65+
normalizeSlash,
6366
omit,
6467
pick,
6568
readPackageJson,
@@ -949,23 +952,37 @@ const composeBundleConfig = (
949952

950953
const isStyleRedirect = redirect.style ?? true;
951954

955+
type Resolver = GetAsyncFunctionFromUnion<
956+
ReturnType<NonNullable<Rspack.ExternalItemFunctionData['getResolve']>>
957+
>;
958+
let resolver: Resolver | undefined;
959+
952960
return {
953961
output: {
954962
externals: [
955-
(data: any, callback: any) => {
963+
async (data, callback) => {
964+
const { request, getResolve, context, contextInfo } = data;
965+
if (!request || !getResolve || !context || !contextInfo) {
966+
return callback();
967+
}
968+
969+
if (!resolver) {
970+
resolver = (await getResolve()) as Resolver;
971+
}
972+
956973
// Issuer is not empty string when the module is imported by another module.
957974
// Prevent from externalizing entry modules here.
958-
if (data.contextInfo.issuer) {
975+
if (contextInfo.issuer) {
959976
// Node.js ECMAScript module loader does no extension searching.
960977
// Add a file extension according to autoExtension config
961978
// when data.request is a relative path and do not have an extension.
962979
// If data.request already have an extension, we replace it with new extension
963980
// This may result in a change in semantics,
964981
// user should use copy to keep origin file or use another separate entry to deal this
965-
let request: string = data.request;
982+
let resolvedRequest: string = request;
966983

967984
const cssExternal = cssExternalHandler(
968-
request,
985+
resolvedRequest,
969986
callback,
970987
jsExtension,
971988
cssModulesAuto,
@@ -976,27 +993,39 @@ const composeBundleConfig = (
976993
return cssExternal;
977994
}
978995

979-
if (request[0] === '.') {
980-
const ext = extname(request);
996+
if (resolvedRequest[0] === '.') {
997+
const resolved = await resolver(context, resolvedRequest);
998+
resolvedRequest = normalizeSlash(
999+
path.relative(path.dirname(contextInfo.issuer), resolved),
1000+
);
1001+
1002+
if (resolvedRequest[0] !== '.') {
1003+
resolvedRequest = `./${resolvedRequest}`;
1004+
}
1005+
1006+
const ext = extname(resolvedRequest);
9811007

9821008
if (ext) {
983-
if (JS_EXTENSIONS_PATTERN.test(request)) {
984-
request = request.replace(/\.[^.]+$/, jsExtension);
1009+
if (JS_EXTENSIONS_PATTERN.test(resolvedRequest)) {
1010+
resolvedRequest = resolvedRequest.replace(
1011+
/\.[^.]+$/,
1012+
jsExtension,
1013+
);
9851014
} else {
9861015
// If it does not match jsExtensionsPattern, we should do nothing, eg: ./foo.png
9871016
return callback();
9881017
}
9891018
} else {
9901019
// TODO: add redirect.extension option
991-
request = `${request}${jsExtension}`;
1020+
resolvedRequest = `${resolvedRequest}${jsExtension}`;
9921021
}
9931022
}
9941023

995-
return callback(null, request);
1024+
return callback(undefined, resolvedRequest);
9961025
}
9971026
callback();
9981027
},
999-
],
1028+
] as Rspack.ExternalItem[],
10001029
},
10011030
};
10021031
};

packages/core/src/css/cssConfig.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ export function isCssGlobalFile(
7777
return !isCssModules;
7878
}
7979

80-
type ExternalCallback = (arg0?: null, arg1?: string) => void;
80+
type ExternalCallback = (arg0?: undefined, arg1?: string) => void;
8181

8282
export function cssExternalHandler(
8383
request: string,
@@ -99,12 +99,12 @@ export function cssExternalHandler(
9999
if (request[0] === '.' && isCssFile(request)) {
100100
// preserve import './CounterButton.module.scss'
101101
if (!isStyleRedirect) {
102-
return callback(null, request);
102+
return callback(undefined, request);
103103
}
104104
if (isCssModulesRequest) {
105-
return callback(null, request.replace(/\.[^.]+$/, jsExtension));
105+
return callback(undefined, request.replace(/\.[^.]+$/, jsExtension));
106106
}
107-
return callback(null, request.replace(/\.[^.]+$/, '.css'));
107+
return callback(undefined, request.replace(/\.[^.]+$/, '.css'));
108108
}
109109

110110
return false;

packages/core/src/types/utils.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,9 @@ export type DeepRequired<T> = Required<{
1212
}>;
1313

1414
export type ExcludesFalse = <T>(x: T | false | undefined | null) => x is T;
15+
16+
export type GetAsyncFunctionFromUnion<T> = T extends (
17+
...args: any[]
18+
) => Promise<any>
19+
? T
20+
: never;

packages/core/src/utils/helper.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,3 +233,8 @@ export const isTTY = (type: 'stdin' | 'stdout' = 'stdout'): boolean => {
233233
};
234234

235235
export { color };
236+
237+
const windowsSlashRegex = /\\/g;
238+
export function normalizeSlash(p: string): string {
239+
return p.replace(windowsSlashRegex, '/');
240+
}

0 commit comments

Comments
 (0)