Skip to content

Commit

Permalink
feat: allow to configure output.filename.html (#3137)
Browse files Browse the repository at this point in the history
  • Loading branch information
chenjiahan authored Aug 5, 2024
1 parent a3e21dc commit 3bcf63f
Show file tree
Hide file tree
Showing 9 changed files with 77 additions and 17 deletions.
19 changes: 19 additions & 0 deletions e2e/cases/html/custom-filename/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { join } from 'node:path';
import { build, globContentJSON } from '@e2e/helper';
import { expect, test } from '@playwright/test';

test('should allow to custom HTML filename', async () => {
await build({
cwd: __dirname,
});

const outputs = await globContentJSON(join(__dirname, 'dist'));
const fooFile = Object.keys(outputs).find((item) =>
item.includes('custom-foo.html'),
);
const barFile = Object.keys(outputs).find((item) =>
item.includes('custom-bar.html'),
);
expect(fooFile).toBeTruthy();
expect(barFile).toBeTruthy();
});
15 changes: 15 additions & 0 deletions e2e/cases/html/custom-filename/rsbuild.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { defineConfig } from '@rsbuild/core';

export default defineConfig({
source: {
entry: {
foo: './src/foo.js',
bar: './src/bar.js',
},
},
output: {
filename: {
html: 'custom-[name].html',
},
},
});
1 change: 1 addition & 0 deletions e2e/cases/html/custom-filename/src/bar.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
console.log('bar');
1 change: 1 addition & 0 deletions e2e/cases/html/custom-filename/src/foo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
console.log('foo');
17 changes: 11 additions & 6 deletions packages/core/src/initPlugins.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { join } from 'node:path';
import { join, posix } from 'node:path';
import type { Compiler } from '@rspack/core';
import { LOADER_PATH } from './constants';
import { createPublicContext } from './createContext';
Expand All @@ -24,12 +24,17 @@ export function getHTMLPathByEntry(
entryName: string,
config: NormalizedEnvironmentConfig,
): string {
const filename =
config.html.outputStructure === 'flat'
? `${entryName}.html`
: `${entryName}/index.html`;
let filename: string;

return removeLeadingSlash(`${config.output.distPath.html}/${filename}`);
if (config.output.filename.html) {
filename = config.output.filename.html.replace('[name]', entryName);
} else if (config.html.outputStructure === 'flat') {
filename = `${entryName}.html`;
} else {
filename = `${entryName}/index.html`;
}

return removeLeadingSlash(posix.join(config.output.distPath.html, filename));
}

const mapProcessAssetsStage = (
Expand Down
5 changes: 5 additions & 0 deletions packages/core/src/types/config/output.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,11 @@ export type FilenameConfig = {
* @default '[name].[contenthash:8].svg'
*/
svg?: string;
/**
* The name of HTML files.
* @default `[name].html`
*/
html?: string;
/**
* The name of the font files.
* @default '[name].[contenthash:8][ext]'
Expand Down
2 changes: 2 additions & 0 deletions packages/core/tests/htmlHelper.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ describe('getHTMLPathByEntry', () => {
distPath: {
html: 'my-html',
},
filename: {},
},
html: {
outputStructure: 'nested',
Expand All @@ -44,6 +45,7 @@ describe('getHTMLPathByEntry', () => {
distPath: {
html: 'html',
},
filename: {},
},
html: {
outputStructure: 'flat',
Expand Down
16 changes: 11 additions & 5 deletions website/docs/en/config/output/filename.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

```ts
type FilenameConfig = {
html?: string;
js?:
| string
| ((pathData: Rspack.PathData, assetInfo: Rspack.JsAssetInfo) => string);
Expand All @@ -18,8 +19,9 @@ type FilenameConfig = {
- **Default:**

```js
// Development
// Development build
const devDefaultFilename = {
html: '[name].html',
js: '[name].js',
css: '[name].css',
svg: '[name].[contenthash:8].svg',
Expand All @@ -28,9 +30,10 @@ const devDefaultFilename = {
media: '[name].[contenthash:8][ext]',
};

// Production
// Production build
const prodDefaultFilename = {
js: isServer ? '[name].js' : '[name].[contenthash:8].js',
html: '[name].html',
js: output.target === 'node' ? '[name].js' : '[name].[contenthash:8].js',
css: '[name].[contenthash:8].css',
svg: '[name].[contenthash:8].svg',
font: '[name].[contenthash:8][ext]',
Expand All @@ -45,13 +48,16 @@ After the production build, Rsbuild will add a hash in the middle of the filenam

The following are the details of each filename:

- `html`: The name of the HTML file, only supports the `[name]` placeholder.
- `js`: The name of the JavaScript files.
- `css`: The name of the CSS files.
- `svg`: The name of the SVG images.
- `font`: The name of the font files.
- `image`: The name of non-SVG images.
- `media`: The name of media assets, such as video.

> See [Output Files](/guide/basic/output-files) for more information.
## Example

To set the name of the JavaScript file to `[name]_script.js`, use the following configuration:
Expand All @@ -70,7 +76,7 @@ export default {
```

:::tip Filename hash
Usually, we only set the filename hash in the production mode (i.e., when `process.env.NODE_ENV === 'production'`).
Usually, Rsbuild only set the filename hash in the production mode (i.e., when `process.env.NODE_ENV === 'production'`).

If you set the filename hash in the development mode, it may cause HMR to fail (especially for CSS files). This is because every time the file content changes, the hash value changes, preventing bundler from reading the latest file content.
:::
Expand All @@ -86,7 +92,7 @@ When you import a module via dynamic import, the module will be bundled into a s
const { add } = await import('./add.ts');
```

If you want to specify a fixed name for the async module, you can use the [magic comments](https://rspack.dev/api/modules#magic-comments) provided by the bundler to achieve this, using `webpackChunkName ` to specify the module name:
If you want to specify a fixed name for the async module, you can use the [magic comments](https://rspack.dev/api/modules#magic-comments) provided by Rspack to achieve this, using `webpackChunkName ` to specify the module name:

```js title="src/index.ts"
const { add } = await import(
Expand Down
18 changes: 12 additions & 6 deletions website/docs/zh/config/output/filename.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

```ts
type FilenameConfig = {
html?: string;
js?:
| string
| ((pathData: Rspack.PathData, assetInfo: Rspack.JsAssetInfo) => string);
Expand All @@ -18,8 +19,9 @@ type FilenameConfig = {
- **默认值:**

```js
// 开发环境
// 开发环境构建
const devDefaultFilename = {
html: '[name].html',
js: '[name].js',
css: '[name].css',
svg: '[name].[contenthash:8].svg',
Expand All @@ -28,9 +30,10 @@ const devDefaultFilename = {
media: '[name].[contenthash:8][ext]',
};

// 生产环境
// 生产环境构建
const prodDefaultFilename = {
js: isServer ? '[name].js' : '[name].[contenthash:8].js',
html: '[name].html',
js: output.target === 'node' ? '[name].js' : '[name].[contenthash:8].js',
css: '[name].[contenthash:8].css',
svg: '[name].[contenthash:8].svg',
font: '[name].[contenthash:8][ext]',
Expand All @@ -45,13 +48,16 @@ const prodDefaultFilename = {

下面是各个文件类型的说明:

- `html`:表示 HTML 文件的名称,仅支持 `[name]` 占位符。
- `js`:表示 JavaScript 文件的名称。
- `css`:表示 CSS 样式文件的名称。
- `svg`:表示 SVG 图片的名称。
- `font`:表示字体文件的名称。
- `image`:表示非 SVG 图片的名称。
- `media`:表示视频等媒体资源的名称。

> 查看 [构建产物目录](/guide/basic/output-files) 了解更多。
## 示例

修改 JavaScript 文件的名称为 `[name]_script.js`
Expand All @@ -70,9 +76,9 @@ export default {
```

:::tip 文件名中的 hash 值
通常来说,我们只会在生产环境下设置文件名的 hash 值(即 `process.env.NODE_ENV === 'production'` 时)。
通常来说,Rsbuild 只会在生产模式下设置文件名的 hash 值(即 `process.env.NODE_ENV === 'production'` 时)。

如果你在开发环境下设置了文件名的 hash,那么可能会导致热更新不生效(尤其是 CSS 文件)。这是因为每次文件内容变化时,都会引起 hash 变化,导致打包工具无法读取到最新的文件内容。
如果你在开发模式下设置了文件名的 hash,那么可能会导致热更新不生效(尤其是 CSS 文件)。这是因为每次文件内容变化时,都会引起 hash 变化,导致打包工具无法读取到最新的文件内容。
:::

## 异步模块文件名
Expand All @@ -86,7 +92,7 @@ export default {
const { add } = await import('./add.ts');
```

如果你希望为异步模块指定一个固定的名称,可以通过打包工具提供的 [magic comments](https://rspack.dev/api/modules#magic-comments) 来实现,通过 `webpackChunkName` 指定模块名称:
如果你希望为异步模块指定一个固定的名称,可以通过 Rspack 提供的 [magic comments](https://rspack.dev/api/modules#magic-comments) 来实现,通过 `webpackChunkName` 指定模块名称:

```js title="src/index.ts"
const { add } = await import(
Expand Down

0 comments on commit 3bcf63f

Please sign in to comment.