Skip to content

Commit 36510a0

Browse files
committed
fix: respect extension of origin import path when redirect.js.extension disabled
1 parent 1933c3e commit 36510a0

File tree

9 files changed

+143
-39
lines changed

9 files changed

+143
-39
lines changed

packages/core/src/config.ts

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1448,6 +1448,7 @@ const composeBundlelessExternalConfig = (
14481448
return;
14491449
}
14501450
const { issuer } = contextInfo;
1451+
const originExtension = extname(request);
14511452

14521453
if (!resolver) {
14531454
resolver = getResolve() as RspackResolver;
@@ -1497,7 +1498,7 @@ const composeBundlelessExternalConfig = (
14971498
logger.debug(
14981499
`Failed to resolve module ${color.green(`"${request}"`)} from ${color.green(issuer)}. If it's an npm package, consider adding it to dependencies or peerDependencies in package.json to make it externalized.`,
14991500
);
1500-
return request;
1501+
return undefined;
15011502
}
15021503
}
15031504

@@ -1543,12 +1544,14 @@ const composeBundlelessExternalConfig = (
15431544
if (ext) {
15441545
// 1. js files hit JS_EXTENSIONS_PATTERN, ./foo.ts -> ./foo.mjs
15451546
if (JS_EXTENSIONS_PATTERN.test(resolvedRequest)) {
1546-
if (jsRedirectExtension) {
1547-
resolvedRequest = resolvedRequest.replace(
1548-
/\.[^.]+$/,
1549-
jsExtension,
1550-
);
1551-
}
1547+
resolvedRequest = resolvedRequest.replace(
1548+
/\.[^.]+$/,
1549+
jsRedirectExtension
1550+
? jsExtension
1551+
: JS_EXTENSIONS_PATTERN.test(originExtension)
1552+
? originExtension
1553+
: '',
1554+
);
15521555
} else {
15531556
// 2. asset files, does not match jsExtensionsPattern, eg: ./foo.png -> ./foo.mjs
15541557
// non-js && non-css files
@@ -1569,7 +1572,7 @@ const composeBundlelessExternalConfig = (
15691572
// If the import path refers to a directory,
15701573
// it most likely actually refers to a `index.*` file due to Node's module resolution.
15711574
// When redirect.js.path is set to false, index should still be added before adding extension.
1572-
// When redirect.js.path is true, the resolver directly generate correct resolvedRequest with index appended.
1575+
// When redirect.js.path is set to true, the resolver directly generate correct resolvedRequest with index appended.
15731576
if (
15741577
!jsRedirectPath &&
15751578
(await isDirectory(

packages/plugin-dts/README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ const defaultRedirect = {
233233
};
234234
```
235235

236-
Controls the redirect of the import paths of output TypeScript declaration files.
236+
Controls the redirect of the import paths of TypeScript declaration output files.
237237

238238
```js
239239
pluginDts({
@@ -269,9 +269,9 @@ import { foo } from '../foo'; // expected output './dist/utils/index.d.ts'
269269
- **Type:** `boolean`
270270
- **Default:** `false`
271271

272-
Whether to automatically redirect the file extension to import paths based on the TypeScript declaration output files.
272+
Whether to automatically redirect the file extension of import paths based on the TypeScript declaration output files.
273273

274-
- When set to `true`, the import paths in declaration files will be redirected to the corresponding JavaScript extension which can be resolved to corresponding declaration file. The extension of the declaration output file is related to the `dtsExtension` configuration.
274+
- When set to `true`, the file extension of the import path in the declaration file will be automatically completed or replaced with the corresponding JavaScript file extension that can be resolved to the corresponding declaration file. The extension of the declaration output file is related to the `dtsExtension` configuration.
275275

276276
```ts
277277
// `dtsExtension` is set to `.d.mts`
@@ -282,7 +282,7 @@ import { foo } from './foo.ts'; // source code of './src/bar.ts' ↓
282282
import { foo } from './foo.mjs'; // expected output of './dist/bar.d.mts'
283283
```
284284

285-
- When set to `false`, the file extension will remain unchanged from the original import path in the rewritten import path of the output file (regardless of whether it is specified or specified as any value).
285+
- When set to `false`, import paths will retain their original file extensions.
286286

287287
### tsgo
288288

tests/integration/redirect/js.test.ts

Lines changed: 94 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,18 @@ test('redirect.js default', async () => {
1818
contents.cjs0!,
1919
/cjs\/index\.cjs/,
2020
);
21+
const { content: notResolvedContent } = queryContent(
22+
contents.esm0!,
23+
/esm\/not-resolved\.js/,
24+
);
25+
26+
expect(notResolvedContent).toMatchInlineSnapshot(`
27+
"export * from "not_resolved";
28+
export * from "./foo.node";
29+
export * from "./foo.node.js";
30+
export * from "./not_resolved_file";
31+
"
32+
`);
2133

2234
expect(indexContent).toMatchInlineSnapshot(`
2335
"import lodash from "lodash";
@@ -28,6 +40,11 @@ test('redirect.js default', async () => {
2840
import { baz } from "./baz.js";
2941
export * from "./.hidden.js";
3042
export * from "./.hidden-folder/index.js";
43+
export * from "./bar.node.js";
44+
export * from "./bar.node.js";
45+
export * from "./bar.node.js";
46+
export * from "./foo.js";
47+
export * from "./foo.js";
3148
const src = lodash.toUpper(lodash_merge(foo) + bar + foo + bar + baz + typeof prettier.version);
3249
export { src as default };
3350
"
@@ -46,6 +63,19 @@ test('redirect.js.path false', async () => {
4663
/esm\/index\.js/,
4764
);
4865

66+
const { content: notResolvedContent } = queryContent(
67+
contents.esm1!,
68+
/esm\/not-resolved\.js/,
69+
);
70+
71+
expect(notResolvedContent).toMatchInlineSnapshot(`
72+
"export * from "not_resolved";
73+
export * from "./foo.node";
74+
export * from "./foo.node.js";
75+
export * from "./not_resolved_file";
76+
"
77+
`);
78+
4979
expect(indexContent).toMatchInlineSnapshot(`
5080
"import lodash from "lodash";
5181
import lodash_merge from "lodash.merge";
@@ -57,6 +87,11 @@ test('redirect.js.path false', async () => {
5787
import { foo as external_foo_js_foo } from "./foo.js";
5888
export * from "./.hidden.js";
5989
export * from "./.hidden-folder/index.js";
90+
export * from "./bar.node.js";
91+
export * from "./bar.node.js";
92+
export * from "./bar.node.js";
93+
export * from "./foo.js";
94+
export * from "./foo.js";
6095
const src = lodash.toUpper(lodash_merge(external_foo_js_foo) + index_js_bar + foo + bar + baz + typeof prettier.version);
6196
export { src as default };
6297
"
@@ -73,6 +108,19 @@ test('redirect.js.path with user override externals', async () => {
73108
/cjs\/index\.cjs/,
74109
);
75110

111+
const { content: notResolvedContent } = queryContent(
112+
contents.esm2!,
113+
/esm\/not-resolved\.js/,
114+
);
115+
116+
expect(notResolvedContent).toMatchInlineSnapshot(`
117+
"export * from "not_resolved";
118+
export * from "./foo.node";
119+
export * from "./foo.node.js";
120+
export * from "./not_resolved_file";
121+
"
122+
`);
123+
76124
expect(indexContent).toMatchInlineSnapshot(`
77125
"import lodash from "lodash";
78126
import lodash_merge from "lodash.merge";
@@ -84,6 +132,11 @@ test('redirect.js.path with user override externals', async () => {
84132
import { foo as external_foo_js_foo } from "./foo.js";
85133
export * from "./.hidden.js";
86134
export * from "./.hidden-folder/index.js";
135+
export * from "./bar.node.js";
136+
export * from "./bar.node.js";
137+
export * from "./bar.node.js";
138+
export * from "./foo.js";
139+
export * from "./foo.js";
87140
const src = lodash.toUpper(lodash_merge(external_foo_js_foo) + index_js_bar + foo + bar + baz + typeof prettier.version);
88141
export { src as default };
89142
"
@@ -108,6 +161,19 @@ test('redirect.js.path with user override alias', async () => {
108161
/cjs\/index\.cjs/,
109162
);
110163

164+
const { content: notResolvedContent } = queryContent(
165+
contents.esm3!,
166+
/esm\/not-resolved\.js/,
167+
);
168+
169+
expect(notResolvedContent).toMatchInlineSnapshot(`
170+
"export * from "not_resolved";
171+
export * from "./foo.node";
172+
export * from "./foo.node.js";
173+
export * from "./not_resolved_file";
174+
"
175+
`);
176+
111177
expect(indexContent).toMatchInlineSnapshot(`
112178
"import lodash from "lodash";
113179
import lodash_merge from "lodash.merge";
@@ -119,6 +185,11 @@ test('redirect.js.path with user override alias', async () => {
119185
import { foo as external_foo_js_foo } from "./foo.js";
120186
export * from "./.hidden.js";
121187
export * from "./.hidden-folder/index.js";
188+
export * from "./bar.node.js";
189+
export * from "./bar.node.js";
190+
export * from "./bar.node.js";
191+
export * from "./foo.js";
192+
export * from "./foo.js";
122193
const src = lodash.toUpper(lodash_merge(external_foo_js_foo) + index_js_bar + foo + bar + baz + typeof prettier.version);
123194
export { src as default };
124195
"
@@ -138,15 +209,33 @@ test('redirect.js.extension: false', async () => {
138209
contents.esm4!,
139210
/esm\/index\.js/,
140211
);
212+
const { content: notResolvedContent } = queryContent(
213+
contents.esm4!,
214+
/esm\/not-resolved\.js/,
215+
);
216+
217+
expect(notResolvedContent).toMatchInlineSnapshot(`
218+
"export * from "not_resolved";
219+
export * from "./foo.node";
220+
export * from "./foo.node.js";
221+
export * from "./not_resolved_file";
222+
"
223+
`);
224+
141225
expect(indexContent).toMatchInlineSnapshot(`
142226
"import lodash from "lodash";
143227
import lodash_merge from "lodash.merge";
144228
import prettier from "prettier";
145-
import { bar } from "./bar/index.ts";
146-
import { foo } from "./foo.ts";
147-
import { baz } from "./baz.ts";
148-
export * from "./.hidden.ts";
149-
export * from "./.hidden-folder/index.ts";
229+
import { bar } from "./bar/index";
230+
import { foo } from "./foo";
231+
import { baz } from "./baz";
232+
export * from "./.hidden";
233+
export * from "./.hidden-folder/index";
234+
export * from "./bar.node";
235+
export * from "./bar.node.js";
236+
export * from "./bar.node.ts";
237+
export * from "./foo.js";
238+
export * from "./foo.ts";
150239
const src = lodash.toUpper(lodash_merge(foo) + bar + foo + bar + baz + typeof prettier.version);
151240
export { src as default };
152241
"
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const bar_node = 'bar node';

tests/integration/redirect/js/src/index.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
// can not be resolved
2-
import lodash from 'lodash';
31
// can be resolved, 3rd party packages
2+
import lodash from 'lodash';
43
import merge from 'lodash.merge';
54
// can be resolved but not specified -- phantom dependency
65
import prettier from 'prettier';
@@ -14,6 +13,11 @@ import { foo } from './foo';
1413

1514
export * from './.hidden';
1615
export * from './.hidden-folder';
16+
export * from './bar.node';
17+
export * from './bar.node.js';
18+
export * from './bar.node.ts';
19+
export * from './foo.js';
20+
export * from './foo.ts';
1721

1822
export default lodash.toUpper(
1923
merge(foo) + bar + foo2 + bar2 + baz + typeof prettier.version,
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// @ts-nocheck
2+
export * from 'not_resolved';
3+
export * from './foo.node';
4+
export * from './foo.node.js';
5+
export * from './not_resolved_file';

tests/integration/redirect/js/tsconfig.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
"extends": "@rslib/tsconfig/base",
33
"compilerOptions": {
44
"baseUrl": "./",
5+
"noEmit": true,
6+
"allowImportingTsExtensions": true,
57
"paths": {
68
"@/*": ["./src/*"]
79
}

website/docs/en/config/lib/redirect.mdx

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ Whether to automatically redirect the import paths of JavaScript output files.
8585
- **Type:** `boolean`
8686
- **Default:** `true`
8787

88-
When set to `true`, [resolve.alias](/config/rsbuild/resolve#resolvealias) and [resolve.aliasStrategy](/config/rsbuild/resolve#aliasstrategy) will take effect and applied in the rewritten import path of the output file. For TypeScript projects, just configure [compilerOptions.paths](https://typescriptlang.org/tsconfig#paths) in the `tsconfig.json` file.
88+
When set to `true`, [resolve.alias](/config/rsbuild/resolve#resolvealias) and [resolve.aliasStrategy](/config/rsbuild/resolve#aliasstrategy) will take effect in the output file, and the import path of the output file will be rewritten. For TypeScript projects, just configure [compilerOptions.paths](https://typescriptlang.org/tsconfig#paths) in the `tsconfig.json` file.
8989

9090
When set to `false`, the import path will not be effected by [resolve.alias](/config/rsbuild/resolve#resolvealias), [resolve.aliasStrategy](/config/rsbuild/resolve#aliasstrategy) and `tsconfig.json`.
9191

@@ -103,14 +103,14 @@ import { foo } from '../foo.js'; // expected output './dist/utils/index.js'
103103

104104
### redirect.js.extension
105105

106-
Whether to automatically redirect the file extension to import paths based on the JavaScript output files.
106+
Whether to automatically redirect the file extension of import paths based on the JavaScript output files.
107107

108108
- **Type:** `boolean`
109109
- **Default:** `true`
110110

111-
When set to `true`, the file extension will automatically be added to the rewritten import path of the output file, regardless of the original extension or whether it is specified in the import path.
111+
When set to `true`, the file extension of import paths in JavaScript output files that can be resolved correctly will be automatically completed or replaced.
112112

113-
When set to `false`, the file extension will remain unchanged from the original import path in the rewritten import path of the output file (regardless of whether it is specified or specified as any value).
113+
When set to `false`, import paths will retain their original file extensions.
114114

115115
:::note
116116
The extension of the JavaScript output file is related to the [autoExtension](/config/lib/auto-extension#libautoextension) configuration.
@@ -167,7 +167,7 @@ import styles from '../foo.css'; // expected output of './dist/utils/index.js'
167167

168168
### redirect.style.extension
169169

170-
Whether to automatically redirect the file extension to import paths based on the style output files.
170+
Whether to automatically redirect the file extension of import paths based on the style output files.
171171

172172
- **Type:** `boolean`
173173
- **Default:** `true`
@@ -215,7 +215,7 @@ import url from './assets/logo.svg'; // expected output of './dist/foo.js'
215215

216216
### redirect.asset.extension
217217

218-
Whether to automatically redirect the file extension to import paths based on the asset output files.
218+
Whether to automatically redirect the file extension of import paths based on the asset output files.
219219

220220
- **Type:** `boolean`
221221
- **Default:** `true`
@@ -266,22 +266,22 @@ import { foo } from '../foo'; // expected output './dist/utils/index.d.ts'
266266

267267
### redirect.dts.extension
268268

269-
Whether to automatically redirect the file extension to import paths based on the TypeScript declaration output files.
269+
Whether to automatically redirect the file extension of import paths based on the TypeScript declaration output files.
270270

271271
- **Type:** `boolean`
272272
- **Default:** `false`
273273

274-
When set to `true`, the import paths in declaration files will be redirected to the corresponding JavaScript extension which can be resolved to corresponding declaration file.
274+
When set to `true`, the file extension of the import path in the declaration file will be automatically completed or replaced with the corresponding JavaScript file extension that can be resolved to the corresponding declaration file.
275275

276-
When set to `false`, the file extension will remain unchanged from the original import path in the rewritten import path of the output file (regardless of whether it is specified or specified as any value).
276+
When set to `false`, import paths will retain their original file extensions.
277277

278278
:::note
279279
The extension of the TypeScript declaration file is related to the [dts.autoExtension](/config/lib/dts#dtsautoextension) configuration.
280280
:::
281281

282282
- **Example:**
283283

284-
For the `.d.mts` declaration file, in some scenarios, the full extension of the module import path is needed to load correctly.
284+
When loading a module with `moduleResolution: 'nodenext'`, the import path needs to include the full file extension. Rslib will automatically add the corresponding file extension based on the actual JavaScript output file.
285285

286286
```ts
287287
import { foo } from './foo'; // source code of './src/bar.ts' ↓

0 commit comments

Comments
 (0)