From e08f60851a3df0a8798afa28e6c68961c528c233 Mon Sep 17 00:00:00 2001 From: Timeless0911 <1604889533@qq.com> Date: Mon, 1 Dec 2025 19:06:23 +0800 Subject: [PATCH 1/2] fix: preserve original extension when extension redirection is disabled --- packages/core/src/config.ts | 40 ++++++--- packages/plugin-dts/README.md | 8 +- .../__snapshots__/index.test.ts.snap | 60 ++++++------- .../redirect/js-not-resolve/src/index.js | 7 +- tests/integration/redirect/js.test.ts | 36 ++++++-- tests/integration/redirect/js/src/bar.node.ts | 1 + tests/integration/redirect/js/src/index.ts | 8 +- tests/integration/redirect/js/tsconfig.json | 2 + .../redirect/jsNotResolved.test.ts | 19 +++-- website/docs/en/config/lib/redirect.mdx | 82 ++++++++++++++---- website/docs/zh/config/lib/redirect.mdx | 84 ++++++++++++++----- 11 files changed, 250 insertions(+), 97 deletions(-) create mode 100644 tests/integration/redirect/js/src/bar.node.ts diff --git a/packages/core/src/config.ts b/packages/core/src/config.ts index 294a68da1..8edfb2a07 100644 --- a/packages/core/src/config.ts +++ b/packages/core/src/config.ts @@ -1448,6 +1448,7 @@ const composeBundlelessExternalConfig = ( return; } const { issuer } = contextInfo; + const originExtension = extname(request); if (!resolver) { resolver = getResolve() as RspackResolver; @@ -1455,7 +1456,7 @@ const composeBundlelessExternalConfig = ( async function redirectPath( request: string, - ): Promise { + ): Promise<{ path?: string; isResolved: boolean }> { try { let resolvedRequest = request; // use resolver to resolve the request @@ -1485,11 +1486,17 @@ const composeBundlelessExternalConfig = ( ) { resolvedRequest = `./${resolvedRequest}`; } - return resolvedRequest; + return { + path: resolvedRequest, + isResolved: true, + }; } // NOTE: If request is a phantom dependency, which means it can be resolved but not specified in dependencies or peerDependencies in package.json, the output will be incorrect to use when the package is published // return the original request instead of the resolved request - return undefined; + return { + path: undefined, + isResolved: true, + }; } catch (_e) { // catch error when request can not be resolved by resolver // e.g. A react component library importing and using 'react' but while not defining @@ -1497,7 +1504,11 @@ const composeBundlelessExternalConfig = ( logger.debug( `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.`, ); - return request; + // return origin request instead of undefined for cssExternalHandler + return { + path: request, + isResolved: false, + }; } } @@ -1506,7 +1517,8 @@ const composeBundlelessExternalConfig = ( if (issuer) { let resolvedRequest: string = request; - const redirectedPath = await redirectPath(resolvedRequest); + const { path: redirectedPath, isResolved } = + await redirectPath(resolvedRequest); const cssExternal = await cssExternalHandler( resolvedRequest, callback, @@ -1537,18 +1549,20 @@ const composeBundlelessExternalConfig = ( // If data.request already have an extension, we replace it with new extension // This may result in a change in semantics, // user should use copy to keep origin file or use another separate entry to deal this - if (resolvedRequest.startsWith('.')) { + if (resolvedRequest.startsWith('.') && isResolved) { const ext = extname(resolvedRequest); if (ext) { // 1. js files hit JS_EXTENSIONS_PATTERN, ./foo.ts -> ./foo.mjs if (JS_EXTENSIONS_PATTERN.test(resolvedRequest)) { - if (jsRedirectExtension) { - resolvedRequest = resolvedRequest.replace( - /\.[^.]+$/, - jsExtension, - ); - } + resolvedRequest = resolvedRequest.replace( + /\.[^.]+$/, + jsRedirectExtension + ? jsExtension + : JS_EXTENSIONS_PATTERN.test(originExtension) + ? originExtension + : '', + ); } else { // 2. asset files, does not match jsExtensionsPattern, eg: ./foo.png -> ./foo.mjs // non-js && non-css files @@ -1569,7 +1583,7 @@ const composeBundlelessExternalConfig = ( // If the import path refers to a directory, // it most likely actually refers to a `index.*` file due to Node's module resolution. // When redirect.js.path is set to false, index should still be added before adding extension. - // When redirect.js.path is true, the resolver directly generate correct resolvedRequest with index appended. + // When redirect.js.path is set to true, the resolver directly generates correct resolvedRequest with index appended. if ( !jsRedirectPath && (await isDirectory( diff --git a/packages/plugin-dts/README.md b/packages/plugin-dts/README.md index e1fe228c0..ddc503348 100644 --- a/packages/plugin-dts/README.md +++ b/packages/plugin-dts/README.md @@ -233,7 +233,7 @@ const defaultRedirect = { }; ``` -Controls the redirect of the import paths of output TypeScript declaration files. +Controls the redirect of the import paths of TypeScript declaration output files. ```js pluginDts({ @@ -269,9 +269,9 @@ import { foo } from '../foo'; // expected output './dist/utils/index.d.ts' - **Type:** `boolean` - **Default:** `false` -Whether to automatically redirect the file extension to import paths based on the TypeScript declaration output files. +Whether to automatically redirect the file extension of import paths based on the TypeScript declaration output files. -- 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. +- 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. ```ts // `dtsExtension` is set to `.d.mts` @@ -282,7 +282,7 @@ import { foo } from './foo.ts'; // source code of './src/bar.ts' ↓ import { foo } from './foo.mjs'; // expected output of './dist/bar.d.mts' ``` -- 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). +- When set to `false`, import paths will retain their original file extensions. ### tsgo diff --git a/tests/integration/preserve-jsx/__snapshots__/index.test.ts.snap b/tests/integration/preserve-jsx/__snapshots__/index.test.ts.snap index 8ca7bc2bf..6cbe66288 100644 --- a/tests/integration/preserve-jsx/__snapshots__/index.test.ts.snap +++ b/tests/integration/preserve-jsx/__snapshots__/index.test.ts.snap @@ -29,12 +29,12 @@ __webpack_require__.r(__webpack_exports__); __webpack_require__.d(__webpack_exports__, { default: ()=>Root }); -const external_App1_cjs_namespaceObject = require("./App1.cjs"); -const external_App2_cjs_namespaceObject = require("./App2.cjs"); +const external_App1_namespaceObject = require("./App1"); +const external_App2_namespaceObject = require("./App2"); const DynamicComponent = ()=>{ - const Component = Math.random() > 0.5 ? external_App1_cjs_namespaceObject.App1A : external_App1_cjs_namespaceObject.App1C; - return import("./App1.cjs").then((mod)=>{ - const Dynamic = mod[Component === external_App1_cjs_namespaceObject.App1A ? 'App1A' : 'App1C']; + const Component = Math.random() > 0.5 ? external_App1_namespaceObject.App1A : external_App1_namespaceObject.App1C; + return import("./App1").then((mod)=>{ + const Dynamic = mod[Component === external_App1_namespaceObject.App1A ? 'App1A' : 'App1C']; return ; }); }; @@ -47,51 +47,51 @@ function Root() { return <> <> - + Loading...}> - - {x ? - - - - - - : } - - - - + + {x ? + + + + + + : } + + + + } fragmentContent={<> + }} data-count={3} icon={} fragmentContent={<> Nested Fragment }/>
{[
- + {'item-one'.toUpperCase()} {}
,
- + app2 - + - + {}
,
- + {(()=>)()} @@ -120,11 +120,11 @@ Object.defineProperty(exports, '__esModule', { `; exports[`JSX syntax should be preserved 2`] = ` -"import { App, App1A, App1B, App1C, app1cProps } from "./App1.js"; -import { App2, app2Props } from "./App2.js"; +"import { App, App1A, App1B, App1C, app1cProps } from "./App1"; +import { App2, app2Props } from "./App2"; const DynamicComponent = ()=>{ const Component = Math.random() > 0.5 ? App1A : App1C; - return import("./App1.js").then((mod)=>{ + return import("./App1").then((mod)=>{ const Dynamic = mod[Component === App1A ? 'App1A' : 'App1C']; return ; }); @@ -205,11 +205,11 @@ export { Root as default }; `; exports[`JSX syntax should be preserved 3`] = ` -"import { App, App1A, App1B, App1C, app1cProps } from "./App1.jsx"; -import { App2, app2Props } from "./App2.jsx"; +"import { App, App1A, App1B, App1C, app1cProps } from "./App1"; +import { App2, app2Props } from "./App2"; const DynamicComponent = ()=>{ const Component = Math.random() > 0.5 ? App1A : App1C; - return import("./App1.jsx").then((mod)=>{ + return import("./App1").then((mod)=>{ const Dynamic = mod[Component === App1A ? 'App1A' : 'App1C']; return ; }); diff --git a/tests/integration/redirect/js-not-resolve/src/index.js b/tests/integration/redirect/js-not-resolve/src/index.js index e933c4a47..31248d171 100644 --- a/tests/integration/redirect/js-not-resolve/src/index.js +++ b/tests/integration/redirect/js-not-resolve/src/index.js @@ -3,6 +3,11 @@ import lodash from 'lodash'; // can be resolved but not specified -- phantom dependency import prettier from 'prettier'; import bar from './bar.js'; +import baz from './baz.cjs'; import foo from './foo'; +import foo_node from './foo.node'; +import foo_node_js from './foo.node.js'; -export default lodash.toUpper(foo + bar + typeof prettier.version); +export default lodash.toUpper( + foo + foo_node + foo_node_js + bar + baz + typeof prettier.version, +); diff --git a/tests/integration/redirect/js.test.ts b/tests/integration/redirect/js.test.ts index e14780749..d1f7b7a6b 100644 --- a/tests/integration/redirect/js.test.ts +++ b/tests/integration/redirect/js.test.ts @@ -28,6 +28,11 @@ test('redirect.js default', async () => { import { baz } from "./baz.js"; export * from "./.hidden.js"; export * from "./.hidden-folder/index.js"; + export * from "./bar.node.js"; + export * from "./bar.node.js"; + export * from "./bar.node.js"; + export * from "./foo.js"; + export * from "./foo.js"; const src = lodash.toUpper(lodash_merge(foo) + bar + foo + bar + baz + typeof prettier.version); export { src as default }; " @@ -57,6 +62,11 @@ test('redirect.js.path false', async () => { import { foo as external_foo_js_foo } from "./foo.js"; export * from "./.hidden.js"; export * from "./.hidden-folder/index.js"; + export * from "./bar.node.js"; + export * from "./bar.node.js"; + export * from "./bar.node.js"; + export * from "./foo.js"; + export * from "./foo.js"; const src = lodash.toUpper(lodash_merge(external_foo_js_foo) + index_js_bar + foo + bar + baz + typeof prettier.version); export { src as default }; " @@ -84,6 +94,11 @@ test('redirect.js.path with user override externals', async () => { import { foo as external_foo_js_foo } from "./foo.js"; export * from "./.hidden.js"; export * from "./.hidden-folder/index.js"; + export * from "./bar.node.js"; + export * from "./bar.node.js"; + export * from "./bar.node.js"; + export * from "./foo.js"; + export * from "./foo.js"; const src = lodash.toUpper(lodash_merge(external_foo_js_foo) + index_js_bar + foo + bar + baz + typeof prettier.version); export { src as default }; " @@ -119,6 +134,11 @@ test('redirect.js.path with user override alias', async () => { import { foo as external_foo_js_foo } from "./foo.js"; export * from "./.hidden.js"; export * from "./.hidden-folder/index.js"; + export * from "./bar.node.js"; + export * from "./bar.node.js"; + export * from "./bar.node.js"; + export * from "./foo.js"; + export * from "./foo.js"; const src = lodash.toUpper(lodash_merge(external_foo_js_foo) + index_js_bar + foo + bar + baz + typeof prettier.version); export { src as default }; " @@ -138,15 +158,21 @@ test('redirect.js.extension: false', async () => { contents.esm4!, /esm\/index\.js/, ); + expect(indexContent).toMatchInlineSnapshot(` "import lodash from "lodash"; import lodash_merge from "lodash.merge"; import prettier from "prettier"; - import { bar } from "./bar/index.ts"; - import { foo } from "./foo.ts"; - import { baz } from "./baz.ts"; - export * from "./.hidden.ts"; - export * from "./.hidden-folder/index.ts"; + import { bar } from "./bar/index"; + import { foo } from "./foo"; + import { baz } from "./baz"; + export * from "./.hidden"; + export * from "./.hidden-folder/index"; + export * from "./bar.node"; + export * from "./bar.node.js"; + export * from "./bar.node.ts"; + export * from "./foo.js"; + export * from "./foo.ts"; const src = lodash.toUpper(lodash_merge(foo) + bar + foo + bar + baz + typeof prettier.version); export { src as default }; " diff --git a/tests/integration/redirect/js/src/bar.node.ts b/tests/integration/redirect/js/src/bar.node.ts new file mode 100644 index 000000000..90faa37dd --- /dev/null +++ b/tests/integration/redirect/js/src/bar.node.ts @@ -0,0 +1 @@ +export const bar_node = 'bar node'; diff --git a/tests/integration/redirect/js/src/index.ts b/tests/integration/redirect/js/src/index.ts index be16d7884..ab5430b16 100644 --- a/tests/integration/redirect/js/src/index.ts +++ b/tests/integration/redirect/js/src/index.ts @@ -1,6 +1,5 @@ -// can not be resolved -import lodash from 'lodash'; // can be resolved, 3rd party packages +import lodash from 'lodash'; import merge from 'lodash.merge'; // can be resolved but not specified -- phantom dependency import prettier from 'prettier'; @@ -14,6 +13,11 @@ import { foo } from './foo'; export * from './.hidden'; export * from './.hidden-folder'; +export * from './bar.node'; +export * from './bar.node.js'; +export * from './bar.node.ts'; +export * from './foo.js'; +export * from './foo.ts'; export default lodash.toUpper( merge(foo) + bar + foo2 + bar2 + baz + typeof prettier.version, diff --git a/tests/integration/redirect/js/tsconfig.json b/tests/integration/redirect/js/tsconfig.json index 2291f72e1..8549dcdd9 100644 --- a/tests/integration/redirect/js/tsconfig.json +++ b/tests/integration/redirect/js/tsconfig.json @@ -2,6 +2,8 @@ "extends": "@rslib/tsconfig/base", "compilerOptions": { "baseUrl": "./", + "noEmit": true, + "allowImportingTsExtensions": true, "paths": { "@/*": ["./src/*"] } diff --git a/tests/integration/redirect/jsNotResolved.test.ts b/tests/integration/redirect/jsNotResolved.test.ts index 9df841757..22819a514 100644 --- a/tests/integration/redirect/jsNotResolved.test.ts +++ b/tests/integration/redirect/jsNotResolved.test.ts @@ -16,8 +16,11 @@ test('redirect.js default', async () => { "import lodash from "lodash"; import prettier from "prettier"; import bar from "./bar.js"; - import foo from "./foo.js"; - const src = lodash.toUpper(foo + bar + typeof prettier.version); + import baz from "./baz.cjs"; + import foo from "./foo"; + import foo_0 from "./foo.node"; + import foo_node from "./foo.node.js"; + const src = lodash.toUpper(foo + foo_0 + foo_node + bar + baz + typeof prettier.version); export { src as default }; " `); @@ -37,8 +40,11 @@ test('redirect.js.path false', async () => { "import lodash from "lodash"; import prettier from "prettier"; import bar from "./bar.js"; - import foo from "./foo.js"; - const src = lodash.toUpper(foo + bar + typeof prettier.version); + import baz from "./baz.cjs"; + import foo from "./foo"; + import foo_0 from "./foo.node"; + import foo_node from "./foo.node.js"; + const src = lodash.toUpper(foo + foo_0 + foo_node + bar + baz + typeof prettier.version); export { src as default }; " `); @@ -58,8 +64,11 @@ test('redirect.js.extension: false', async () => { "import lodash from "lodash"; import prettier from "prettier"; import bar from "./bar.js"; + import baz from "./baz.cjs"; import foo from "./foo"; - const src = lodash.toUpper(foo + bar + typeof prettier.version); + import foo_0 from "./foo.node"; + import foo_node from "./foo.node.js"; + const src = lodash.toUpper(foo + foo_0 + foo_node + bar + baz + typeof prettier.version); export { src as default }; " `); diff --git a/website/docs/en/config/lib/redirect.mdx b/website/docs/en/config/lib/redirect.mdx index bbd5e17c7..3e6e6a5f7 100644 --- a/website/docs/en/config/lib/redirect.mdx +++ b/website/docs/en/config/lib/redirect.mdx @@ -72,9 +72,21 @@ In bundleless mode, there are often needs such as using aliases or automatically Controls the redirect of the import paths of output JavaScript files. +- **Example:** + +By default, when set `compilerOptions.paths` to `{ "@/*": ["src/*"] }` in `tsconfig.json`, the import path for the JavaScript output file will be redirected to the correct relative path and the corresponding file extension will be added: + +```ts +import { foo } from '@/foo'; // source code of './src/bar.ts' ↓ +import { foo } from './foo.mjs'; // expected output of './dist/bar.mjs' + +import { foo } from '@/foo'; // source code of './src/utils/index.ts' ↓ +import { foo } from '../foo.mjs'; // expected output of './dist/utils/index.mjs' +``` + :::warning -When [output.externals](/config/rsbuild/output#outputexternals) is configured and a request is matched, neither `redirect.js.path` nor `redirect.js.extension` will take effect, and the final rewritten request path will be entirely controlled by [output.externals](/config/rsbuild/output#outputexternals). +When [output.externals](/config/rsbuild/output#outputexternals) is configured and a request is matched, neither `redirect.js.path` nor `redirect.js.extension` will take effect, and the final redirected request path will be entirely controlled by [output.externals](/config/rsbuild/output#outputexternals). ::: @@ -85,32 +97,32 @@ Whether to automatically redirect the import paths of JavaScript output files. - **Type:** `boolean` - **Default:** `true` -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. +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 redirected. For TypeScript projects, just configure [compilerOptions.paths](https://typescriptlang.org/tsconfig#paths) in the `tsconfig.json` file. 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`. - **Example:** -When set `compilerOptions.paths` to `{ "@/*": ["src/*"] }` in `tsconfig.json`, the output file will be redirected to the correct relative path: +When set `compilerOptions.paths` to `{ "@/*": ["src/*"] }` in `tsconfig.json`, the import path for the JavaScript output file will be redirected to the correct relative path: ```ts import { foo } from '@/foo'; // source code of './src/bar.ts' ↓ -import { foo } from './foo.js'; // expected output of './dist/bar.js' +import { foo } from './foo'; // expected output of './dist/bar.js' import { foo } from '@/foo'; // source code of './src/utils/index.ts' ↓ -import { foo } from '../foo.js'; // expected output './dist/utils/index.js' +import { foo } from '../foo'; // expected output './dist/utils/index.js' ``` ### redirect.js.extension -Whether to automatically redirect the file extension to import paths based on the JavaScript output files. +Whether to automatically redirect the file extension of import paths based on the JavaScript output files. - **Type:** `boolean` - **Default:** `true` -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. +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. -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). +When set to `false`, import paths will retain their original file extensions. :::note The extension of the JavaScript output file is related to the [autoExtension](/config/lib/auto-extension#libautoextension) configuration. @@ -132,6 +144,18 @@ import { foo } from './foo.mjs'; // expected output './dist/utils/index.mjs' Controls the redirect of the import paths of output style files. +- **Example:** + +By default, when `compilerOptions.paths` is set to `{ "@/*": ["src/*"] }` in `tsconfig.json`, the import paths of style output files will be redirected to the correct relative paths. Additionally, when importing [CSS Modules](/config/rsbuild/output#outputcssmodules), the file extension will be rewritten to the corresponding JavaScript output file extension. + +```ts +import '@/foo.css'; // source code of './src/bar.ts' ↓ +import './foo.css'; // expected output of './dist/bar.js' + +import styles from '@/foo.module.less'; // source code of './src/baz.ts' ↓ +import styles from './foo.module.mjs'; // expected output of './dist/baz.mjs' +``` + ### redirect.style.path Whether to automatically redirect the import paths of style output files. @@ -145,6 +169,8 @@ When set to `false`, the original import path will remain unchanged. - **Example:** +When set `compilerOptions.paths` to `{ "@/*": ["src/*"] }` in `tsconfig.json`, the import path for the style output file will be redirected to the correct relative path. + When importing normal style files: ```ts @@ -167,15 +193,15 @@ import styles from '../foo.css'; // expected output of './dist/utils/index.js' ### redirect.style.extension -Whether to automatically redirect the file extension to import paths based on the style output files. +Whether to automatically redirect the file extension of import paths based on the style output files. - **Type:** `boolean` - **Default:** `true` When set to `true`: -- When importing a normal style file, the path will be rewritten to `.css`. -- When importing [CSS Modules](/config/rsbuild/output#outputcssmodules), the path will be rewritten to the corresponding JavaScript output file. +- When importing a normal style file, the path will be redirected to `.css`. +- When importing [CSS Modules](/config/rsbuild/output#outputcssmodules), the file extension will be redirected to the corresponding JavaScript output file extension. When set to `false`, the file extension will remain unchanged from the original import path. @@ -195,6 +221,15 @@ import styles from './index.module.mjs'; // expected output Controls the redirect of the import paths of output asset files. +- **Example:** + +By default, when `compilerOptions.paths` is set to `{ "@/*": ["src/*"] }` in `tsconfig.json`, the import paths of asset files will be redirected to the correct relative paths, and the file extensions will be rewritten to the corresponding JavaScript output file extensions. + +```ts +import url from '@/assets/logo.svg'; // source code of './src/foo.ts' ↓ +import url from './assets/logo.mjs'; // expected output of './dist/foo.mjs' +``` + ### redirect.asset.path Whether to automatically redirect the import paths of asset output files. @@ -208,6 +243,8 @@ When set to `false`, the original import path will remain unchanged. - **Example:** +When set `compilerOptions.paths` to `{ "@/*": ["src/*"] }` in `tsconfig.json`, the import path for the asset file will be redirected to the correct relative path: + ```ts import url from '@/assets/logo.svg'; // source code of './src/foo.ts' ↓ import url from './assets/logo.svg'; // expected output of './dist/foo.js' @@ -215,12 +252,12 @@ import url from './assets/logo.svg'; // expected output of './dist/foo.js' ### redirect.asset.extension -Whether to automatically redirect the file extension to import paths based on the asset output files. +Whether to automatically redirect the file extension of import paths based on the asset output files. - **Type:** `boolean` - **Default:** `true` -When set to `true`, the paths of imported asset files will be redirected to the corresponding JavaScript output file. +When set to `true`, the file extension of imported asset files will be redirected to the corresponding JavaScript output file extension. When set to `false`, the file extension will remain unchanged from the original import path. @@ -241,6 +278,15 @@ The way to import static assets in a JavaScript file and the corresponding outpu Controls the redirect of the import paths of output TypeScript declaration files. +- **Example:** + +By default, when `compilerOptions.paths` is set to `{ "@/*": ["src/*"] }` in `tsconfig.json`, the import path in the declaration output file will be redirected to the correct relative path: + +```ts +import { foo } from '@/foo'; // source code of './src/bar.ts' ↓ +import { foo } from './foo'; // expected output of './dist/bar.d.ts' +``` + ### redirect.dts.path Whether to automatically redirect the import paths of TypeScript declaration output files. @@ -254,7 +300,7 @@ When set to `false`, the original import path will remain unchanged. - **Example:** -When `compilerOptions.paths` is set to `{ "@/*": ["src/*"] }` in `tsconfig.json`, the declaration output file will be redirected to the correct relative path: +When `compilerOptions.paths` is set to `{ "@/*": ["src/*"] }` in `tsconfig.json`, the import path in the declaration output file will be redirected to the correct relative path: ```ts import { foo } from '@/foo'; // source code of './src/bar.ts' ↓ @@ -266,14 +312,14 @@ import { foo } from '../foo'; // expected output './dist/utils/index.d.ts' ### redirect.dts.extension -Whether to automatically redirect the file extension to import paths based on the TypeScript declaration output files. +Whether to automatically redirect the file extension of import paths based on the TypeScript declaration output files. - **Type:** `boolean` - **Default:** `false` -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. +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. -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). +When set to `false`, import paths will retain their original file extensions. :::note The extension of the TypeScript declaration file is related to the [dts.autoExtension](/config/lib/dts#dtsautoextension) configuration. @@ -281,7 +327,7 @@ The extension of the TypeScript declaration file is related to the [dts.autoExte - **Example:** -For the `.d.mts` declaration file, in some scenarios, the full extension of the module import path is needed to load correctly. +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. ```ts import { foo } from './foo'; // source code of './src/bar.ts' ↓ diff --git a/website/docs/zh/config/lib/redirect.mdx b/website/docs/zh/config/lib/redirect.mdx index 8a0f73534..c0f0b0bf3 100644 --- a/website/docs/zh/config/lib/redirect.mdx +++ b/website/docs/zh/config/lib/redirect.mdx @@ -72,9 +72,21 @@ const defaultRedirect = { 控制 JavaScript 产物文件导入路径的重定向。 +- **示例:** + +默认情况下,在 `tsconfig.json` 中将 `compilerOptions.paths` 设置为 `{ "@/*": ["src/*"] }` 时,JavaScript 产物文件的导入路径将被重定向到正确的相对路径并添加对应的文件扩展名。 + +```ts +import { foo } from '@/foo'; // './src/bar.ts' 的源码 ↓ +import { foo } from './foo.mjs'; // './dist/bar.mjs' 预期生成的代码 + +import { foo } from '@/foo'; // './src/utils/index.ts' 的源码 ↓ +import { foo } from '../foo.mjs'; // './dist/utils/index.mjs' 预期生成的代码 +``` + :::warning -当 [output.externals](/config/rsbuild/output#outputexternals) 被配置且请求被匹配时,`redirect.js.path` 和 `redirect.js.extension` 都不会生效,最终重写的请求路径将完全由 [output.externals](/config/rsbuild/output#outputexternals) 控制。 +当 [output.externals](/config/rsbuild/output#outputexternals) 被配置且请求被匹配时,`redirect.js.path` 和 `redirect.js.extension` 都不会生效,最终重定向的请求路径将完全由 [output.externals](/config/rsbuild/output#outputexternals) 控制。 ::: @@ -85,32 +97,32 @@ const defaultRedirect = { - **类型:** `boolean` - **默认值:** `true` -当设置为 `true` 时,[resolve.alias](/config/rsbuild/resolve#resolvealias) 和 [resolve.aliasStrategy](/config/rsbuild/resolve#aliasstrategy) 将生效并应用于产物文件的重写导入路径。对于 TypeScript 项目,在 `tsconfig.json` 文件中配置 [compilerOptions.paths](https://typescriptlang.org/tsconfig#paths) 即可。 +当设置为 `true` 时,[resolve.alias](/config/rsbuild/resolve#resolvealias) 和 [resolve.aliasStrategy](/config/rsbuild/resolve#aliasstrategy) 会在产物文件中生效,产物文件的导入路径会被重写。对于 TypeScript 项目,在 `tsconfig.json` 文件中配置 [compilerOptions.paths](https://typescriptlang.org/tsconfig#paths) 即可。 当设置为 `false` 时,导入路径将不受 [resolve.alias](/config/rsbuild/resolve#resolvealias)、[resolve.aliasStrategy](/config/rsbuild/resolve#aliasstrategy) 和 `tsconfig.json` 的影响。 -- 示例: +- **示例:** -在 `tsconfig.json` 中将 `compilerOptions.paths` 设置为 `{ "@/*": ["src/*"] }` 时,产物文件将被重定向到正确的相对路径: +在 `tsconfig.json` 中将 `compilerOptions.paths` 设置为 `{ "@/*": ["src/*"] }` 时,JavaScript 产物文件的导入路径将被重定向到正确的相对路径: ```ts import { foo } from '@/foo'; // './src/bar.ts' 的源码 ↓ -import { foo } from './foo.js'; // './dist/bar.js' 预期生成的代码 +import { foo } from './foo'; // './dist/bar.js' 预期生成的代码 import { foo } from '@/foo'; // './src/utils/index.ts' 的源码 ↓ -import { foo } from '../foo.js'; // './dist/utils/index.js' 预期生成的代码 +import { foo } from '../foo'; // './dist/utils/index.js' 预期生成的代码 ``` ### redirect.js.extension -是否根据 JavaScript 产物文件自动重定向文件扩展名到导入路径。 +是否根据 JavaScript 产物文件自动重定向导入路径的文件扩展名。 - **类型:** `boolean` - **默认值:** `true` -当设置为 `true` 时,无论原始扩展名或导入路径中是否指定,文件扩展名都将自动添加到产物文件的重写导入路径中。 +当设置为 `true` 时,JavaScript 产物文件中那些可被正确解析的导入路径,其文件扩展名将被自动补全或替换。 -当设置为 `false` 时,文件扩展名将保持原始导入路径不变(无论是否指定或指定为任意值)。 +当设置为 `false` 时,导入路径将保留其原始的文件扩展名。 :::note JavaScript 产物文件的扩展名与 [autoExtension](/config/lib/auto-extension#libautoextension) 配置有关。 @@ -132,6 +144,18 @@ import { foo } from './foo.mjs'; // './dist/utils/index.mjs' 预期生成的代 控制样式产物文件导入路径的重定向。 +- **示例:** + +默认情况下,在 `tsconfig.json` 中将 `compilerOptions.paths` 设置为 `{ "@/*": ["src/*"] }` 时,样式产物文件的导入路径将被重定向到正确的相对路径。此外,在导入 [CSS Modules](/config/rsbuild/output#outputcssmodules) 时,文件扩展名将被重写为对应的 JavaScript 产物文件扩展名。 + +```ts +import '@/foo.css'; // './src/bar.ts' 的源码 ↓ +import './foo.css'; // './dist/bar.js' 预期生成的代码 + +import styles from '@/foo.module.less'; // './src/baz.ts' 的源码 ↓ +import styles from './foo.module.mjs'; // './dist/baz.mjs' 预期生成的代码 +``` + ### redirect.style.path 是否自动重定向样式产物文件的导入路径。 @@ -145,6 +169,8 @@ import { foo } from './foo.mjs'; // './dist/utils/index.mjs' 预期生成的代 - **示例:** +在 `tsconfig.json` 中将 `compilerOptions.paths` 设置为 `{ "@/*": ["src/*"] }` 时,样式产物文件的导入路径将被重定向到正确的相对路径。 + 导入普通样式文件时: ```ts @@ -155,7 +181,7 @@ import '@/foo.css'; // './src/utils/index.ts' 的源码 ↓ import '../foo.css'; // './dist/utils/index.js' 预期生成的代码 ``` -导入 [CSS Modules](/zh/config/rsbuild/output#outputcssmodules) 时: +导入 [CSS Modules](/config/rsbuild/output#outputcssmodules) 时: ```ts import styles from '@/foo.css'; // './src/bar.ts' 的源码 ↓ @@ -167,7 +193,7 @@ import styles from '../foo.css'; // './dist/utils/index.js' 预期生成的代 ### redirect.style.extension -是否根据样式产物文件自动重定向文件扩展名到导入路径。 +是否根据样式产物文件自动重定向导入路径的文件扩展名。 - **类型:** `boolean` - **默认值:** `true` @@ -175,7 +201,7 @@ import styles from '../foo.css'; // './dist/utils/index.js' 预期生成的代 当设置为 `true` 时: - 导入普通样式文件的文件扩展名将被重写为 `.css`。 -- 导入 [CSS Modules](/config/rsbuild/output#outputcssmodules) 时,路径将被重写为到对应的 JavaScript 产物文件。 +- 导入 [CSS Modules](/config/rsbuild/output#outputcssmodules) 时,文件扩展名将被重写为对应的 JavaScript 产物文件扩展名。 当设置为 `false` 时,文件扩展名将保持原始导入路径。 @@ -195,6 +221,15 @@ import styles from './index.module.mjs'; // 预期生成的代码 控制资源文件导入路径的重定向。 +- **示例:** + +默认情况下,在 `tsconfig.json` 中将 `compilerOptions.paths` 设置为 `{ "@/*": ["src/*"] }` 时,资源文件的导入路径将被重定向到正确的相对路径,扩展名将被重写为对应的 JavaScript 产物文件扩展名。 + +```ts +import url from '@/assets/logo.svg'; // './src/foo.ts' 的源码 ↓ +import url from './assets/logo.mjs'; // './dist/foo.mjs' 预期生成的代码 +``` + ### redirect.asset.path 是否自动重定向资源文件的导入路径。 @@ -208,6 +243,8 @@ import styles from './index.module.mjs'; // 预期生成的代码 - **示例:** +在 `tsconfig.json` 中将 `compilerOptions.paths` 设置为 `{ "@/*": ["src/*"] }` 时,资源文件的导入路径将被重定向到正确的相对路径并 + ```ts import url from '@/assets/logo.svg'; // './src/foo.ts' 的源码 ↓ import url from './assets/logo.svg'; // './dist/foo.js' 预期生成的代码 @@ -215,12 +252,12 @@ import url from './assets/logo.svg'; // './dist/foo.js' 预期生成的代码 ### redirect.asset.extension -是否根据资源产物文件自动重定向文件扩展名到导入路径。 +是否根据资源产物文件自动重定向导入路径的文件扩展名。 - **类型:** `boolean` - **默认值:** `true` -当设置为 `true` 时,导入资源文件的路径将被重写到对应的 JavaScript 产物文件。 +当设置为 `true` 时,导入资源文件的扩展名将被重写为对应的 JavaScript 产物文件扩展名。 当设置为 `false` 时,文件扩展名将保持原始导入路径。 @@ -241,6 +278,15 @@ import url from './assets/logo.mjs'; // './dist/foo.mjs' 预期生成的代码 控制 TypeScript 类型文件中导入路径的重定向。 +- **示例:** + +默认情况下,在 `tsconfig.json` 中将 `compilerOptions.paths` 设置为 `{ "@/*": ["src/*"] }` 时,类型声明产物文件的导入路径将被重定向到正确的相对路径。 + +```ts +import { foo } from '@/foo'; // './src/bar.ts' 的源码 ↓ +import { foo } from './foo'; // './dist/bar.d.ts' 预期生成的代码 +``` + ### redirect.dts.path 是否自动重定向 TypeScript 类型文件中的导入路径。 @@ -254,7 +300,7 @@ import url from './assets/logo.mjs'; // './dist/foo.mjs' 预期生成的代码 - **示例:** -在 `tsconfig.json` 中将 `compilerOptions.paths` 设置为 `{ "@/*": ["src/*"] }` 时,类型声明产物文件将被重定向到正确的相对路径: +在 `tsconfig.json` 中将 `compilerOptions.paths` 设置为 `{ "@/*": ["src/*"] }` 时,类型声明产物文件中的导入路径将被重定向到正确的相对路径: ```ts import { foo } from '@/foo'; // './src/bar.ts' 的源码 ↓ @@ -266,14 +312,14 @@ import { foo } from '../foo'; // './dist/utils/index.d.ts' 预期生成的代码 ### redirect.dts.extension -是否根据 TypeScript 类型文件自动重定向文件扩展名到导入路径。 +是否根据 TypeScript 类型文件自动重定向导入路径的文件扩展名。 - **类型:** `boolean` - **默认值:** `false` -当设置为 `true` 时,类型声明文件中的引入路径会被重定向到对应的可以解析到相应类型声明文件的 JavaScript 文件扩展名。 +当设置为 `true` 时,类型声明文件中的导入路径,其文件扩展名会被自动补全或替换为对应的可以解析到相应类型声明文件的 JavaScript 文件扩展名。 -当设置为 `false` 时,文件扩展名将保持原始导入路径不变(无论是否指定或指定为任意值)。 +当设置为 `false` 时,导入路径将保留其原始的文件扩展名。 :::note TypeScript 类型文件的扩展名与 [dts.autoExtension](/config/lib/dts#dtsautoextension) 配置有关。 @@ -281,7 +327,7 @@ TypeScript 类型文件的扩展名与 [dts.autoExtension](/config/lib/dts#dtsau - **示例:** -对于 `.d.mts` 类型文件,在一些场景下需要指定模块导入路径的完整扩展名才能正确加载。 +当使用 `moduleResolution: 'nodenext'` 加载模块时,导入路径需要包含完整的文件扩展名。Rslib 将根据实际的 JavaScript 产物文件自动添加对应的文件扩展名。 ```ts import { foo } from './foo'; // './src/bar.ts' 的源码 ↓ From 40151d3a458a51797a60e0375fa923e42bc44e6a Mon Sep 17 00:00:00 2001 From: Timeless0911 <1604889533@qq.com> Date: Mon, 1 Dec 2025 19:15:35 +0800 Subject: [PATCH 2/2] chore: update --- website/docs/zh/config/lib/redirect.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/website/docs/zh/config/lib/redirect.mdx b/website/docs/zh/config/lib/redirect.mdx index c0f0b0bf3..0697aaa25 100644 --- a/website/docs/zh/config/lib/redirect.mdx +++ b/website/docs/zh/config/lib/redirect.mdx @@ -223,7 +223,7 @@ import styles from './index.module.mjs'; // 预期生成的代码 - **示例:** -默认情况下,在 `tsconfig.json` 中将 `compilerOptions.paths` 设置为 `{ "@/*": ["src/*"] }` 时,资源文件的导入路径将被重定向到正确的相对路径,扩展名将被重写为对应的 JavaScript 产物文件扩展名。 +默认情况下,在 `tsconfig.json` 中将 `compilerOptions.paths` 设置为 `{ "@/*": ["src/*"] }` 时,资源文件的导入路径将被重定向到正确的相对路径,其扩展名将被重写为对应的 JavaScript 产物文件扩展名。 ```ts import url from '@/assets/logo.svg'; // './src/foo.ts' 的源码 ↓ @@ -243,7 +243,7 @@ import url from './assets/logo.mjs'; // './dist/foo.mjs' 预期生成的代码 - **示例:** -在 `tsconfig.json` 中将 `compilerOptions.paths` 设置为 `{ "@/*": ["src/*"] }` 时,资源文件的导入路径将被重定向到正确的相对路径并 +在 `tsconfig.json` 中将 `compilerOptions.paths` 设置为 `{ "@/*": ["src/*"] }` 时,资源文件的导入路径将被重定向到正确的相对路径。 ```ts import url from '@/assets/logo.svg'; // './src/foo.ts' 的源码 ↓