diff --git a/crates/node_binding/binding.d.ts b/crates/node_binding/binding.d.ts index 36af31a5e85b..d6f19a73b22c 100644 --- a/crates/node_binding/binding.d.ts +++ b/crates/node_binding/binding.d.ts @@ -1176,7 +1176,7 @@ export interface RawCacheGroupOptions { key: string priority?: number test?: RegExp | string | Function - filename?: string + filename?: JsFilename idHint?: string /** What kind of chunks should be selected. */ chunks?: RegExp | 'async' | 'initial' | 'all' diff --git a/crates/rspack_binding_values/src/raw_options/raw_split_chunks/mod.rs b/crates/rspack_binding_values/src/raw_options/raw_split_chunks/mod.rs index 4140516f0755..6740b3fa4d5b 100644 --- a/crates/rspack_binding_values/src/raw_options/raw_split_chunks/mod.rs +++ b/crates/rspack_binding_values/src/raw_options/raw_split_chunks/mod.rs @@ -23,6 +23,7 @@ use self::raw_split_chunk_cache_group_test::RawCacheGroupTest; use self::raw_split_chunk_chunks::{create_chunks_filter, Chunks}; use self::raw_split_chunk_name::default_chunk_option_name; use self::raw_split_chunk_size::RawSplitChunkSizes; +use crate::JsFilename; #[napi(object, object_to_js = false)] #[derive(Debug)] @@ -63,7 +64,7 @@ pub struct RawCacheGroupOptions { #[napi(ts_type = "RegExp | string | Function")] #[debug(skip)] pub test: Option, - pub filename: Option, + pub filename: Option, // pub enforce: bool, pub id_hint: Option, /// What kind of chunks should be selected. diff --git a/packages/rspack-test-tools/tests/configCases/split-chunks/custom-filename-function/a.js b/packages/rspack-test-tools/tests/configCases/split-chunks/custom-filename-function/a.js new file mode 100644 index 000000000000..e79a06170101 --- /dev/null +++ b/packages/rspack-test-tools/tests/configCases/split-chunks/custom-filename-function/a.js @@ -0,0 +1,24 @@ +import "./shared1"; +import "./common1"; + +it("should be able to load the split chunk on demand (shared)", () => { + return import(/* webpackChunkName: "theName" */ "./shared2"); +}); + +it("should be able to load the split chunk on demand (common)", () => { + return Promise.all([ + import(/* webpackChunkName: "otherName1" */ "./common2"), + import(/* webpackChunkName: "otherName2" */ "./common3") + ]); +}); + +it("should have files", () => { + const files = require("fs").readdirSync(__dirname); + expect(files).toContain("a.js"); + expect(files).toContain("b.js"); + expect(files).toContain("common-common1_js.js"); + expect(files).toContain("common-common2_js.js"); + expect(files).toContain("common-common3_js.js"); + expect(files).toContain("shared-shared-shared1_js.js"); + expect(files).toContain("shared-shared-shared2_js.js"); +}); diff --git a/packages/rspack-test-tools/tests/configCases/split-chunks/custom-filename-function/b.js b/packages/rspack-test-tools/tests/configCases/split-chunks/custom-filename-function/b.js new file mode 100644 index 000000000000..f7422f1f99e1 --- /dev/null +++ b/packages/rspack-test-tools/tests/configCases/split-chunks/custom-filename-function/b.js @@ -0,0 +1,5 @@ +import "./shared1"; +import "./shared2"; +import "./common1"; +import "./common2"; +import "./common3"; diff --git a/packages/rspack-test-tools/tests/configCases/split-chunks/custom-filename-function/common1.js b/packages/rspack-test-tools/tests/configCases/split-chunks/custom-filename-function/common1.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/packages/rspack-test-tools/tests/configCases/split-chunks/custom-filename-function/common2.js b/packages/rspack-test-tools/tests/configCases/split-chunks/custom-filename-function/common2.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/packages/rspack-test-tools/tests/configCases/split-chunks/custom-filename-function/common3.js b/packages/rspack-test-tools/tests/configCases/split-chunks/custom-filename-function/common3.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/packages/rspack-test-tools/tests/configCases/split-chunks/custom-filename-function/rspack.config.js b/packages/rspack-test-tools/tests/configCases/split-chunks/custom-filename-function/rspack.config.js new file mode 100644 index 000000000000..3dbab2563af8 --- /dev/null +++ b/packages/rspack-test-tools/tests/configCases/split-chunks/custom-filename-function/rspack.config.js @@ -0,0 +1,34 @@ +/** @type {import("@rspack/core").Configuration} */ +module.exports = { + mode: "development", + entry: { + a: "./a", + b: "./b" + }, + output: { + filename: "[name].js", + libraryTarget: "commonjs2" + }, + optimization: { + chunkIds: "named", + splitChunks: { + cacheGroups: { + shared: { + chunks: "all", + test: /shared/, + filename: (pathData, assetInfo) => { + expect(pathData).toBeDefined() + expect(typeof assetInfo).toBe('object') + return "shared-[name].js" + }, + enforce: true + }, + common: { + chunks: "all", + test: /common/, + enforce: true + } + } + } + } +}; diff --git a/packages/rspack-test-tools/tests/configCases/split-chunks/custom-filename-function/shared1.js b/packages/rspack-test-tools/tests/configCases/split-chunks/custom-filename-function/shared1.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/packages/rspack-test-tools/tests/configCases/split-chunks/custom-filename-function/shared2.js b/packages/rspack-test-tools/tests/configCases/split-chunks/custom-filename-function/shared2.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/packages/rspack-test-tools/tests/configCases/split-chunks/custom-filename-function/test.config.js b/packages/rspack-test-tools/tests/configCases/split-chunks/custom-filename-function/test.config.js new file mode 100644 index 000000000000..a8c9e9360a0c --- /dev/null +++ b/packages/rspack-test-tools/tests/configCases/split-chunks/custom-filename-function/test.config.js @@ -0,0 +1,6 @@ +/** @type {import("../../../..").TConfigCaseConfig} */ +module.exports = { + findBundle: function (i, options) { + return ["a.js"]; + } +}; diff --git a/packages/rspack/etc/core.api.md b/packages/rspack/etc/core.api.md index 44c0b52eaee6..5834d2de8f26 100644 --- a/packages/rspack/etc/core.api.md +++ b/packages/rspack/etc/core.api.md @@ -4131,7 +4131,7 @@ export type OptimizationSplitChunksCacheGroup = { test?: string | RegExp | ((module: Module) => unknown); priority?: number; enforce?: boolean; - filename?: string; + filename?: Filename; reuseExistingChunk?: boolean; type?: string | RegExp; idHint?: string; @@ -6973,14 +6973,14 @@ export const rspackOptions: z.ZodObject<{ test: z.ZodOptional]>, z.ZodFunction], z.ZodUnknown>, z.ZodUnknown>]>>; priority: z.ZodOptional; enforce: z.ZodOptional; - filename: z.ZodOptional; + filename: z.ZodOptional, z.ZodOptional>], z.ZodUnknown>, z.ZodString>]>>; reuseExistingChunk: z.ZodOptional; type: z.ZodOptional]>>; idHint: z.ZodOptional; }, "strict", z.ZodTypeAny, { name?: string | false | ((args_0: Module | undefined, ...args: unknown[]) => unknown) | undefined; type?: string | RegExp | undefined; - filename?: string | undefined; + filename?: string | ((args_0: PathData, args_1: JsAssetInfo | undefined, ...args: unknown[]) => string) | undefined; chunks?: RegExp | "initial" | "async" | "all" | ((args_0: Chunk, ...args: unknown[]) => boolean) | undefined; usedExports?: boolean | undefined; defaultSizeTypes?: string[] | undefined; @@ -7000,7 +7000,7 @@ export const rspackOptions: z.ZodObject<{ }, { name?: string | false | ((args_0: Module | undefined, ...args: unknown[]) => unknown) | undefined; type?: string | RegExp | undefined; - filename?: string | undefined; + filename?: string | ((args_0: PathData, args_1: JsAssetInfo | undefined, ...args: unknown[]) => string) | undefined; chunks?: RegExp | "initial" | "async" | "all" | ((args_0: Chunk, ...args: unknown[]) => boolean) | undefined; usedExports?: boolean | undefined; defaultSizeTypes?: string[] | undefined; @@ -7049,7 +7049,7 @@ export const rspackOptions: z.ZodObject<{ cacheGroups?: Record unknown) | undefined; type?: string | RegExp | undefined; - filename?: string | undefined; + filename?: string | ((args_0: PathData, args_1: JsAssetInfo | undefined, ...args: unknown[]) => string) | undefined; chunks?: RegExp | "initial" | "async" | "all" | ((args_0: Chunk, ...args: unknown[]) => boolean) | undefined; usedExports?: boolean | undefined; defaultSizeTypes?: string[] | undefined; @@ -7092,7 +7092,7 @@ export const rspackOptions: z.ZodObject<{ cacheGroups?: Record unknown) | undefined; type?: string | RegExp | undefined; - filename?: string | undefined; + filename?: string | ((args_0: PathData, args_1: JsAssetInfo | undefined, ...args: unknown[]) => string) | undefined; chunks?: RegExp | "initial" | "async" | "all" | ((args_0: Chunk, ...args: unknown[]) => boolean) | undefined; usedExports?: boolean | undefined; defaultSizeTypes?: string[] | undefined; @@ -7167,7 +7167,7 @@ export const rspackOptions: z.ZodObject<{ cacheGroups?: Record unknown) | undefined; type?: string | RegExp | undefined; - filename?: string | undefined; + filename?: string | ((args_0: PathData, args_1: JsAssetInfo | undefined, ...args: unknown[]) => string) | undefined; chunks?: RegExp | "initial" | "async" | "all" | ((args_0: Chunk, ...args: unknown[]) => boolean) | undefined; usedExports?: boolean | undefined; defaultSizeTypes?: string[] | undefined; @@ -7233,7 +7233,7 @@ export const rspackOptions: z.ZodObject<{ cacheGroups?: Record unknown) | undefined; type?: string | RegExp | undefined; - filename?: string | undefined; + filename?: string | ((args_0: PathData, args_1: JsAssetInfo | undefined, ...args: unknown[]) => string) | undefined; chunks?: RegExp | "initial" | "async" | "all" | ((args_0: Chunk, ...args: unknown[]) => boolean) | undefined; usedExports?: boolean | undefined; defaultSizeTypes?: string[] | undefined; @@ -8669,7 +8669,7 @@ export const rspackOptions: z.ZodObject<{ cacheGroups?: Record unknown) | undefined; type?: string | RegExp | undefined; - filename?: string | undefined; + filename?: string | ((args_0: PathData, args_1: JsAssetInfo | undefined, ...args: unknown[]) => string) | undefined; chunks?: RegExp | "initial" | "async" | "all" | ((args_0: Chunk, ...args: unknown[]) => boolean) | undefined; usedExports?: boolean | undefined; defaultSizeTypes?: string[] | undefined; @@ -9271,7 +9271,7 @@ export const rspackOptions: z.ZodObject<{ cacheGroups?: Record unknown) | undefined; type?: string | RegExp | undefined; - filename?: string | undefined; + filename?: string | ((args_0: PathData, args_1: JsAssetInfo | undefined, ...args: unknown[]) => string) | undefined; chunks?: RegExp | "initial" | "async" | "all" | ((args_0: Chunk, ...args: unknown[]) => boolean) | undefined; usedExports?: boolean | undefined; defaultSizeTypes?: string[] | undefined; diff --git a/packages/rspack/src/config/types.ts b/packages/rspack/src/config/types.ts index 879843399e42..7dcaf48c9258 100644 --- a/packages/rspack/src/config/types.ts +++ b/packages/rspack/src/config/types.ts @@ -2165,7 +2165,7 @@ export type OptimizationSplitChunksCacheGroup = { enforce?: boolean; /** Allows to override the filename when and only when it's an initial chunk. */ - filename?: string; + filename?: Filename; /** * Whether to reuse existing chunks when possible. diff --git a/packages/rspack/src/config/zod.ts b/packages/rspack/src/config/zod.ts index 1efac5c3f035..9099f8ae6e78 100644 --- a/packages/rspack/src/config/zod.ts +++ b/packages/rspack/src/config/zod.ts @@ -1218,7 +1218,7 @@ const optimizationSplitChunksCacheGroup = z.strictObject({ .optional(), priority: z.number().optional(), enforce: z.boolean().optional(), - filename: z.string().optional(), + filename: filename.optional(), reuseExistingChunk: z.boolean().optional(), type: z.string().or(z.instanceof(RegExp)).optional(), idHint: z.string().optional(), diff --git a/website/docs/en/plugins/webpack/split-chunks-plugin.mdx b/website/docs/en/plugins/webpack/split-chunks-plugin.mdx index acdf30125f15..238997423f23 100644 --- a/website/docs/en/plugins/webpack/split-chunks-plugin.mdx +++ b/website/docs/en/plugins/webpack/split-chunks-plugin.mdx @@ -325,7 +325,7 @@ Sets the hint for chunk id. It will be added to chunk's filename. #### splitChunks.cacheGroups.\{cacheGroup\}.filename -- **Type:** `string` +- **Type:** `string | function` Allows to override the filename when and only when it's an initial chunk. All placeholders available in output.filename are also available here. @@ -337,6 +337,10 @@ module.exports = { cacheGroups: { defaultVendors: { filename: 'vendors-[name].js', + // or + filename: (pathData, assetInfo) => { + return `${pathData.chunk.name}-bundle.js`; + }, }, }, }, diff --git a/website/docs/zh/plugins/webpack/split-chunks-plugin.mdx b/website/docs/zh/plugins/webpack/split-chunks-plugin.mdx index 88da4d415023..4c5e37d352e8 100644 --- a/website/docs/zh/plugins/webpack/split-chunks-plugin.mdx +++ b/website/docs/zh/plugins/webpack/split-chunks-plugin.mdx @@ -315,7 +315,7 @@ module.exports = { #### splitChunks.cacheGroups.\{cacheGroup\}.filename -- **类型:** `string` +- **类型:** `string | function` 仅在初始 chunk 时才允许覆盖文件名。 也可以在 output.filename 中使用所有占位符。 @@ -327,6 +327,10 @@ module.exports = { cacheGroups: { defaultVendors: { filename: 'vendors-[name].js', + // or + filename: (pathData, assetInfo) => { + return `${pathData.chunk.name}-bundle.js`; + }, }, }, },