Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 13 additions & 7 deletions packages/core/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1230,7 +1230,8 @@ const composeBundlelessExternalConfig = (
const styleRedirectExtension = redirect.style?.extension ?? true;
const jsRedirectPath = redirect.js?.path ?? true;
const jsRedirectExtension = redirect.js?.extension ?? true;
const assetRedirect = redirect.asset ?? true;
const assetRedirectPath = redirect.asset?.path ?? true;
const assetRedirectExtension = redirect.asset?.extension ?? true;

let resolver: RspackResolver | undefined;

Expand Down Expand Up @@ -1302,26 +1303,27 @@ const composeBundlelessExternalConfig = (
if (issuer) {
let resolvedRequest: string = request;

const redirectedPath = await redirectPath(resolvedRequest);
const cssExternal = await cssExternalHandler(
resolvedRequest,
callback,
jsExtension,
cssModulesAuto,
styleRedirectPath,
styleRedirectExtension,
redirectPath,
redirectedPath,
issuer,
);

if (cssExternal !== false) {
return cssExternal;
}

if (redirectedPath === undefined) {
return callback(undefined, request);
}

if (jsRedirectPath) {
const redirectedPath = await redirectPath(resolvedRequest);
if (redirectedPath === undefined) {
return callback(undefined, request);
}
resolvedRequest = redirectedPath;
}

Expand All @@ -1346,7 +1348,11 @@ const composeBundlelessExternalConfig = (
} else {
// 2. asset files, does not match jsExtensionsPattern, eg: ./foo.png -> ./foo.mjs
// non-js && non-css files
if (assetRedirect) {
resolvedRequest = assetRedirectPath
? redirectedPath
: request;

if (assetRedirectExtension) {
resolvedRequest = resolvedRequest.replace(
/\.[^.]+$/,
jsExtension,
Expand Down
5 changes: 2 additions & 3 deletions packages/core/src/css/cssConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export async function cssExternalHandler(
auto: CssLoaderOptionsAuto,
styleRedirectPath: boolean,
styleRedirectExtension: boolean,
redirectPath: (request: string) => Promise<string | undefined>,
redirectedPath: string | undefined,
issuer: string,
): Promise<false | void> {
// cssExtract: do not external @rsbuild/core/compiled/css-loader/noSourceMaps.js, sourceMaps.js, api.mjs etc.
Expand All @@ -32,9 +32,8 @@ export async function cssExternalHandler(
let resolvedRequest = request;

if (styleRedirectPath) {
const redirectedPath = await redirectPath(resolvedRequest);
if (redirectedPath === undefined) {
return callback(undefined, request);
return false;
}
resolvedRequest = redirectedPath;
}
Expand Down
15 changes: 14 additions & 1 deletion packages/core/src/types/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,19 @@ export type StyleRedirect = {
extension?: boolean;
};

export type AssetRedirect = {
/**
* Whether to automatically redirect the import paths of asset output files.
* @defaultValue `true`
*/
path?: boolean;
/**
* Whether to automatically redirect the file extension to import paths based on the asset output files.
* @defaultValue `true`
*/
extension?: boolean;
};

export type DtsRedirect = {
/**
* Whether to automatically redirect the import paths of TypeScript declaration output files.
Expand All @@ -210,7 +223,7 @@ export type Redirect = {
/** Controls the redirect of the import paths of output style files. */
style?: StyleRedirect;
/** Controls the redirect of the import paths of output asset files. */
asset?: boolean;
asset?: AssetRedirect;
/** Controls the redirect of the import paths of output TypeScript declaration files. */
dts?: DtsRedirect;
};
Expand Down
16 changes: 15 additions & 1 deletion tests/integration/redirect/asset.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,23 @@ test('0. default', async () => {
expect(indexCjs).toContain('require("./assets/logo.cjs")');
});

test('1. redirect.asset = false', async () => {
test('1. redirect.asset.extension = false', async () => {
const { content: indexJs } = queryContent(contents.esm1!, /index\.js/);
const { content: indexCjs } = queryContent(contents.cjs1!, /index\.cjs/);
expect(indexJs).toContain('import logo from "./assets/logo.svg";');
expect(indexCjs).toContain('require("./assets/logo.svg")');
});

test('2. redirect.asset.path = false', async () => {
const { content: indexJs } = queryContent(contents.esm2!, /index\.js/);
const { content: indexCjs } = queryContent(contents.cjs2!, /index\.cjs/);
expect(indexJs).toContain('import logo from "@/assets/logo.js";');
expect(indexCjs).toContain('require("@/assets/logo.cjs")');
});

test('3. redirect.asset.path = false, redirect.js.path = false', async () => {
const { content: indexJs } = queryContent(contents.esm3!, /index\.js/);
const { content: indexCjs } = queryContent(contents.cjs3!, /index\.cjs/);
expect(indexJs).toContain('import logo from "@/assets/logo.svg";');
expect(indexCjs).toContain('require("@/assets/logo.svg")');
});
75 changes: 72 additions & 3 deletions tests/integration/redirect/asset/rslib.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,69 @@ export default defineConfig({
},
},
}),
// 1. redirect.asset: false
// 1. redirect.asset.extension: false
generateBundleEsmConfig({
bundle: false,
redirect: { asset: false },
redirect: {
asset: {
extension: false,
},
},
output: {
distPath: {
root: 'dist/asset-extension-false/esm',
},
},
}),
generateBundleCjsConfig({
bundle: false,
redirect: {
asset: {
extension: false,
},
},
output: {
distPath: {
root: 'dist/asset-extension-false/cjs',
},
},
}),
// 2. redirect.asset.path: false
generateBundleEsmConfig({
bundle: false,
redirect: {
asset: {
path: false,
},
},
output: {
distPath: {
root: 'dist/asset-path-false/esm',
},
},
}),
generateBundleCjsConfig({
bundle: false,
redirect: {
asset: {
path: false,
},
},
output: {
distPath: {
root: 'dist/asset-path-false/cjs',
},
},
}),
// 3. redirect.asset.extension: false + redirect.asset.path: false
generateBundleEsmConfig({
bundle: false,
redirect: {
asset: {
path: false,
extension: false,
},
},
output: {
distPath: {
root: 'dist/asset-false/esm',
Expand All @@ -32,7 +91,12 @@ export default defineConfig({
}),
generateBundleCjsConfig({
bundle: false,
redirect: { asset: false },
redirect: {
asset: {
path: false,
extension: false,
},
},
output: {
distPath: {
root: 'dist/asset-false/cjs',
Expand All @@ -43,4 +107,9 @@ export default defineConfig({
output: {
target: 'web',
},
resolve: {
alias: {
'@': './src',
},
},
});
2 changes: 1 addition & 1 deletion tests/integration/redirect/asset/src/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
import svg from './assets/logo.svg';
import svg from '@/assets/logo.svg';

console.log('svg: ', svg);
44 changes: 40 additions & 4 deletions website/docs/en/config/lib/redirect.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ type StyleRedirect = {
extension?: boolean;
};

type AssetRedirect = {
path?: boolean;
extension?: boolean;
};

type DtsRedirect = {
path?: boolean;
extension?: boolean;
Expand All @@ -31,7 +36,7 @@ type DtsRedirect = {
type Redirect = {
js?: JsRedirect;
style?: StyleRedirect;
asset?: boolean;
asset?: AssetRedirect;
dts?: DtsRedirect;
};
```
Expand All @@ -48,7 +53,10 @@ const defaultRedirect = {
path: true,
extension: true,
},
asset: true,
asset: {
path: true,
extension: true,
},
dts: {
path: true,
extension: false,
Expand Down Expand Up @@ -187,6 +195,28 @@ import styles from './index.module.mjs'; // expected output

Controls the redirect of the import paths of output asset files.

### redirect.asset.path

Whether to automatically redirect the import paths of asset output files.

- **Type:** `boolean`
- **Default:** `true`

When set to `true`, the relevant redirect rules are the same as [redirect.js.path](/config/lib/redirect#redirectjspath).

When set to `false`, the original import path will remain unchanged.

- **Example:**

```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'
```

### redirect.asset.extension

Whether to automatically redirect the file extension to import paths based on the asset output files.

- **Type:** `boolean`
- **Default:** `true`

Expand All @@ -197,10 +227,16 @@ When set to `false`, the file extension will remain unchanged from the original
- **Example:**

```ts
import url from './assets/logo.svg'; // source code ↓
import url from './assets/logo.mjs'; // expected output
import url from './assets/logo.svg'; // source code of './src/foo.ts'
import url from './assets/logo.mjs'; // expected output of './dist/foo.mjs'
```

::: note

The way to import static assets in a JavaScript file and the corresponding output structure, please see [Import static assets](/guide/advanced/static-assets#import-assets-in-javascript-file).

:::

## redirect.dts

Controls the redirect of the import paths of output TypeScript declaration files.
Expand Down
35 changes: 35 additions & 0 deletions website/docs/en/guide/faq/features.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,41 @@ export default defineConfig({
});
```

## Static assets processing

### How to skip the processing of static asset files in bundleless mode?

In bundleless mode, Rslib transforms the source static asset file into a JavaScript file and a static asset file that is emitted according to [output.distPath](/config/rsbuild/output#outputdistpath) by default with preserving the `import` or `require` statements for static assets. To skip the above processing of static asset files, you need to:

1. Set `source.entry` to remove static asset files from the entry.
2. Set `output.copy` to copy static asset files to the output directory.
3. Set `redirect.asset.extension` to `false` to disable the redirect behavior for the import path of static asset files.

Below is an example of skipping the `.png` file processing. All `.png` files in `src` will be copied to the output directory and retained with consistent relative paths.

```ts title="rslib.config.ts"
export default defineConfig({
lib: [
{
// ...
source: {
entry: {
index: ['./src/**', '!src/**/*.png'],
},
},
output: {
copy: [{ from: '**/*.png', context: path.join(__dirname, 'src') }],
},
redirect: {
asset: {
extension: false,
},
},
},
],
});
```

## Code minification

### How to preserve all comments in the output files?
Expand Down
Loading
Loading