diff --git a/crates/node_binding/binding.d.ts b/crates/node_binding/binding.d.ts index e7b2fc3370d..d592b8bd0b8 100644 --- a/crates/node_binding/binding.d.ts +++ b/crates/node_binding/binding.d.ts @@ -139,6 +139,7 @@ export enum BuiltinPluginName { ConsumeSharedPlugin = 'ConsumeSharedPlugin', ModuleFederationRuntimePlugin = 'ModuleFederationRuntimePlugin', NamedModuleIdsPlugin = 'NamedModuleIdsPlugin', + NaturalModuleIdsPlugin = 'NaturalModuleIdsPlugin', DeterministicModuleIdsPlugin = 'DeterministicModuleIdsPlugin', NamedChunkIdsPlugin = 'NamedChunkIdsPlugin', DeterministicChunkIdsPlugin = 'DeterministicChunkIdsPlugin', diff --git a/crates/rspack_binding_options/src/options/raw_builtins/mod.rs b/crates/rspack_binding_options/src/options/raw_builtins/mod.rs index 4e02139ed3e..06f2e2074ec 100644 --- a/crates/rspack_binding_options/src/options/raw_builtins/mod.rs +++ b/crates/rspack_binding_options/src/options/raw_builtins/mod.rs @@ -19,7 +19,7 @@ use rspack_core::{BoxPlugin, Define, DefinePlugin, Plugin, PluginExt, Provide, P use rspack_error::Result; use rspack_ids::{ DeterministicChunkIdsPlugin, DeterministicModuleIdsPlugin, NamedChunkIdsPlugin, - NamedModuleIdsPlugin, + NamedModuleIdsPlugin, NaturalModuleIdsPlugin, }; use rspack_napi::NapiResultExt; use rspack_plugin_asset::AssetPlugin; @@ -126,6 +126,7 @@ pub enum BuiltinPluginName { ConsumeSharedPlugin, ModuleFederationRuntimePlugin, NamedModuleIdsPlugin, + NaturalModuleIdsPlugin, DeterministicModuleIdsPlugin, NamedChunkIdsPlugin, DeterministicChunkIdsPlugin, @@ -323,6 +324,9 @@ impl BuiltinPlugin { BuiltinPluginName::NamedModuleIdsPlugin => { plugins.push(NamedModuleIdsPlugin::default().boxed()) } + BuiltinPluginName::NaturalModuleIdsPlugin => { + plugins.push(NaturalModuleIdsPlugin::default().boxed()) + } BuiltinPluginName::DeterministicModuleIdsPlugin => { plugins.push(DeterministicModuleIdsPlugin::default().boxed()) } diff --git a/crates/rspack_core/src/utils/mod.rs b/crates/rspack_core/src/utils/mod.rs index d7c35098479..e49d01fd61a 100644 --- a/crates/rspack_core/src/utils/mod.rs +++ b/crates/rspack_core/src/utils/mod.rs @@ -1,7 +1,9 @@ use std::{cmp::Ordering, fmt::Display}; use itertools::Itertools; +use rspack_identifier::Identifier; use rspack_util::comparators::compare_ids; +use rspack_util::comparators::compare_numbers; use rustc_hash::FxHashMap as HashMap; use crate::{ @@ -143,6 +145,20 @@ pub fn compare_chunk_group( } } +pub fn compare_modules_by_pre_order_index_or_identifier( + module_graph: &ModuleGraph, + a: &Identifier, + b: &Identifier, +) -> std::cmp::Ordering { + if let Some(a) = module_graph.get_pre_order_index(a) + && let Some(b) = module_graph.get_pre_order_index(b) + { + compare_numbers(a, b) + } else { + compare_ids(a, b) + } +} + pub fn compare_modules_by_identifier(a: &BoxModule, b: &BoxModule) -> std::cmp::Ordering { compare_ids(&a.identifier(), &b.identifier()) } diff --git a/crates/rspack_ids/src/lib.rs b/crates/rspack_ids/src/lib.rs index 1c65b7187c3..e12bc1456bf 100644 --- a/crates/rspack_ids/src/lib.rs +++ b/crates/rspack_ids/src/lib.rs @@ -8,3 +8,5 @@ mod named_chunk_ids_plugin; pub use named_chunk_ids_plugin::*; mod deterministic_chunk_ids_plugin; pub use deterministic_chunk_ids_plugin::DeterministicChunkIdsPlugin; +mod natural_module_ids_plugin; +pub use natural_module_ids_plugin::NaturalModuleIdsPlugin; diff --git a/crates/rspack_ids/src/natural_module_ids_plugin.rs b/crates/rspack_ids/src/natural_module_ids_plugin.rs new file mode 100644 index 00000000000..da7318715b9 --- /dev/null +++ b/crates/rspack_ids/src/natural_module_ids_plugin.rs @@ -0,0 +1,53 @@ +use rspack_core::{ + compare_modules_by_pre_order_index_or_identifier, ApplyContext, CompilationModuleIds, + CompilerOptions, Plugin, PluginContext, +}; +use rspack_error::Result; +use rspack_hook::{plugin, plugin_hook}; + +use crate::id_helpers::{assign_ascending_module_ids, get_used_module_ids_and_modules}; + +#[plugin] +#[derive(Debug, Default)] +pub struct NaturalModuleIdsPlugin; + +#[plugin_hook(CompilationModuleIds for NaturalModuleIdsPlugin)] +fn module_ids(&self, compilation: &mut rspack_core::Compilation) -> Result<()> { + let (used_ids, mut modules_in_natural_order) = get_used_module_ids_and_modules(compilation, None); + + let mut chunk_graph = std::mem::take(&mut compilation.chunk_graph); + let module_graph = compilation.get_module_graph(); + + modules_in_natural_order + .sort_unstable_by(|a, b| compare_modules_by_pre_order_index_or_identifier(&module_graph, a, b)); + + let modules_in_natural_order = modules_in_natural_order + .into_iter() + .filter_map(|i| module_graph.module_by_identifier(&i)) + .collect::>(); + + assign_ascending_module_ids(&used_ids, modules_in_natural_order, &mut chunk_graph); + + compilation.chunk_graph = chunk_graph; + + Ok(()) +} + +impl Plugin for NaturalModuleIdsPlugin { + fn name(&self) -> &'static str { + "NaturalModuleIdsPlugin" + } + + fn apply( + &self, + ctx: PluginContext<&mut ApplyContext>, + _options: &mut CompilerOptions, + ) -> Result<()> { + ctx + .context + .compilation_hooks + .module_ids + .tap(module_ids::new(self)); + Ok(()) + } +} diff --git a/packages/rspack-test-tools/tests/configCases/loader/options/rspack.config.js b/packages/rspack-test-tools/tests/configCases/loader/options/rspack.config.js index 56d11578126..4cb750d31c7 100644 --- a/packages/rspack-test-tools/tests/configCases/loader/options/rspack.config.js +++ b/packages/rspack-test-tools/tests/configCases/loader/options/rspack.config.js @@ -1,6 +1,9 @@ /** @type {import("@rspack/core").Configuration} */ module.exports = { mode: "none", + optimization: { + moduleIds: 'named' + }, module: { rules: [ { diff --git a/packages/rspack-test-tools/tests/configCases/optimization/module-ids-natural/a.js b/packages/rspack-test-tools/tests/configCases/optimization/module-ids-natural/a.js new file mode 100644 index 00000000000..b5500157d08 --- /dev/null +++ b/packages/rspack-test-tools/tests/configCases/optimization/module-ids-natural/a.js @@ -0,0 +1,15 @@ +export const a = 42; + +import b from "./b.js"; + +it("should load c.js", () => { + expect(b).toBe("foo"); + + const d = require("./d.js"); + + expect(d.default).toEqual({}); +}); + +export { b } + +export const c = require("./c.js"); diff --git a/packages/rspack-test-tools/tests/configCases/optimization/module-ids-natural/b.js b/packages/rspack-test-tools/tests/configCases/optimization/module-ids-natural/b.js new file mode 100644 index 00000000000..e7134e7006d --- /dev/null +++ b/packages/rspack-test-tools/tests/configCases/optimization/module-ids-natural/b.js @@ -0,0 +1 @@ +module.exports = "foo"; diff --git a/packages/rspack-test-tools/tests/configCases/optimization/module-ids-natural/c.js b/packages/rspack-test-tools/tests/configCases/optimization/module-ids-natural/c.js new file mode 100644 index 00000000000..cf3532e11f9 --- /dev/null +++ b/packages/rspack-test-tools/tests/configCases/optimization/module-ids-natural/c.js @@ -0,0 +1,3 @@ +export function c() { + return "bar" +} diff --git a/packages/rspack-test-tools/tests/configCases/optimization/module-ids-natural/d.js b/packages/rspack-test-tools/tests/configCases/optimization/module-ids-natural/d.js new file mode 100644 index 00000000000..b1c6ea436a5 --- /dev/null +++ b/packages/rspack-test-tools/tests/configCases/optimization/module-ids-natural/d.js @@ -0,0 +1 @@ +export default {} diff --git a/packages/rspack-test-tools/tests/configCases/optimization/module-ids-natural/index.js b/packages/rspack-test-tools/tests/configCases/optimization/module-ids-natural/index.js new file mode 100644 index 00000000000..94fb5e4a625 --- /dev/null +++ b/packages/rspack-test-tools/tests/configCases/optimization/module-ids-natural/index.js @@ -0,0 +1,7 @@ +import { a, b } from "./a.js"; + +it('should load a.js', () => { + expect(a).toBe(42) + + expect(b).toBe("foo") +}) diff --git a/packages/rspack-test-tools/tests/configCases/optimization/module-ids-natural/rspack.config.js b/packages/rspack-test-tools/tests/configCases/optimization/module-ids-natural/rspack.config.js new file mode 100644 index 00000000000..e53a16578cc --- /dev/null +++ b/packages/rspack-test-tools/tests/configCases/optimization/module-ids-natural/rspack.config.js @@ -0,0 +1,6 @@ +/** @type {import("@rspack/core").Configuration} */ +module.exports = { + optimization: { + moduleIds: "natural" + }, +}; diff --git a/packages/rspack/etc/api.md b/packages/rspack/etc/api.md index 17b95490242..560fded0885 100644 --- a/packages/rspack/etc/api.md +++ b/packages/rspack/etc/api.md @@ -6000,7 +6000,7 @@ export type Optimization = z.infer; // @public (undocumented) const optimization: z.ZodObject<{ - moduleIds: z.ZodOptional>; + moduleIds: z.ZodOptional>; chunkIds: z.ZodOptional>; minimize: z.ZodOptional; minimizer: z.ZodOptional, z.ZodUnion<[z.ZodType, z.ZodType, z.ZodUnion<[z.ZodLiteral, z.ZodLiteral<0>, z.ZodLiteral<"">, z.ZodNull, z.ZodUndefined]>]>]>, "many">>; @@ -6199,7 +6199,7 @@ const optimization: z.ZodObject<{ mangleExports: z.ZodOptional, z.ZodBoolean]>>; nodeEnv: z.ZodOptional]>>; }, "strict", z.ZodTypeAny, { - moduleIds?: "named" | "deterministic" | undefined; + moduleIds?: "named" | "natural" | "deterministic" | undefined; chunkIds?: "named" | "deterministic" | undefined; minimize?: boolean | undefined; minimizer?: (false | "" | 0 | RspackPluginInstance | "..." | RspackPluginFunction | null | undefined)[] | undefined; @@ -6260,7 +6260,7 @@ const optimization: z.ZodObject<{ mangleExports?: boolean | "deterministic" | "size" | undefined; nodeEnv?: string | false | undefined; }, { - moduleIds?: "named" | "deterministic" | undefined; + moduleIds?: "named" | "natural" | "deterministic" | undefined; chunkIds?: "named" | "deterministic" | undefined; minimize?: boolean | undefined; minimizer?: (false | "" | 0 | RspackPluginInstance | "..." | RspackPluginFunction | null | undefined)[] | undefined; @@ -9372,7 +9372,7 @@ export const rspackOptions: z.ZodObject<{ }>]>>; snapshot: z.ZodOptional>; optimization: z.ZodOptional>; + moduleIds: z.ZodOptional>; chunkIds: z.ZodOptional>; minimize: z.ZodOptional; minimizer: z.ZodOptional, z.ZodUnion<[z.ZodType, z.ZodType, z.ZodUnion<[z.ZodLiteral, z.ZodLiteral<0>, z.ZodLiteral<"">, z.ZodNull, z.ZodUndefined]>]>]>, "many">>; @@ -9571,7 +9571,7 @@ export const rspackOptions: z.ZodObject<{ mangleExports: z.ZodOptional, z.ZodBoolean]>>; nodeEnv: z.ZodOptional]>>; }, "strict", z.ZodTypeAny, { - moduleIds?: "named" | "deterministic" | undefined; + moduleIds?: "named" | "natural" | "deterministic" | undefined; chunkIds?: "named" | "deterministic" | undefined; minimize?: boolean | undefined; minimizer?: (false | "" | 0 | RspackPluginInstance | "..." | RspackPluginFunction | null | undefined)[] | undefined; @@ -9632,7 +9632,7 @@ export const rspackOptions: z.ZodObject<{ mangleExports?: boolean | "deterministic" | "size" | undefined; nodeEnv?: string | false | undefined; }, { - moduleIds?: "named" | "deterministic" | undefined; + moduleIds?: "named" | "natural" | "deterministic" | undefined; chunkIds?: "named" | "deterministic" | undefined; minimize?: boolean | undefined; minimizer?: (false | "" | 0 | RspackPluginInstance | "..." | RspackPluginFunction | null | undefined)[] | undefined; @@ -10735,7 +10735,7 @@ export const rspackOptions: z.ZodObject<{ } | undefined; snapshot?: {} | undefined; optimization?: { - moduleIds?: "named" | "deterministic" | undefined; + moduleIds?: "named" | "natural" | "deterministic" | undefined; chunkIds?: "named" | "deterministic" | undefined; minimize?: boolean | undefined; minimizer?: (false | "" | 0 | RspackPluginInstance | "..." | RspackPluginFunction | null | undefined)[] | undefined; @@ -11184,7 +11184,7 @@ export const rspackOptions: z.ZodObject<{ } | undefined; snapshot?: {} | undefined; optimization?: { - moduleIds?: "named" | "deterministic" | undefined; + moduleIds?: "named" | "natural" | "deterministic" | undefined; chunkIds?: "named" | "deterministic" | undefined; minimize?: boolean | undefined; minimizer?: (false | "" | 0 | RspackPluginInstance | "..." | RspackPluginFunction | null | undefined)[] | undefined; diff --git a/packages/rspack/src/builtin-plugin/NaturalModuleIdsPlugin.ts b/packages/rspack/src/builtin-plugin/NaturalModuleIdsPlugin.ts new file mode 100644 index 00000000000..8045ba8e90c --- /dev/null +++ b/packages/rspack/src/builtin-plugin/NaturalModuleIdsPlugin.ts @@ -0,0 +1,9 @@ +import { BuiltinPluginName } from "@rspack/binding"; + +import { create } from "./base"; + +export const NaturalModuleIdsPlugin = create( + BuiltinPluginName.NaturalModuleIdsPlugin, + () => {}, + "compilation" +); diff --git a/packages/rspack/src/builtin-plugin/index.ts b/packages/rspack/src/builtin-plugin/index.ts index b2178c63ace..b9a5f3b42a0 100644 --- a/packages/rspack/src/builtin-plugin/index.ts +++ b/packages/rspack/src/builtin-plugin/index.ts @@ -43,6 +43,7 @@ export * from "./ModuleChunkFormatPlugin"; export * from "./ModuleConcatenationPlugin"; export * from "./NamedChunkIdsPlugin"; export * from "./NamedModuleIdsPlugin"; +export * from "./NaturalModuleIdsPlugin"; export * from "./NodeTargetPlugin"; export * from "./ProgressPlugin"; export * from "./ProvidePlugin"; diff --git a/packages/rspack/src/config/defaults.ts b/packages/rspack/src/config/defaults.ts index c0092f73929..cb0f2f5f300 100644 --- a/packages/rspack/src/config/defaults.ts +++ b/packages/rspack/src/config/defaults.ts @@ -893,8 +893,10 @@ const applyOptimizationDefaults = ( D(optimization, "removeAvailableModules", true); D(optimization, "removeEmptyChunks", true); D(optimization, "mergeDuplicateChunks", true); - F(optimization, "moduleIds", (): "named" | "deterministic" => { + F(optimization, "moduleIds", (): "natural" | "named" | "deterministic" => { if (production) return "deterministic"; + if (development) return "named"; + // TODO(rspack@1.0): change to `"natural"` return "named"; }); F(optimization, "chunkIds", (): "named" | "deterministic" => { diff --git a/packages/rspack/src/config/zod.ts b/packages/rspack/src/config/zod.ts index 4c1052bab81..be9d77ec28a 100644 --- a/packages/rspack/src/config/zod.ts +++ b/packages/rspack/src/config/zod.ts @@ -1175,7 +1175,7 @@ export type OptimizationSplitChunksOptions = z.infer< >; const optimization = z.strictObject({ - moduleIds: z.enum(["named", "deterministic"]).optional(), + moduleIds: z.enum(["named", "natural", "deterministic"]).optional(), chunkIds: z.enum(["named", "deterministic"]).optional(), minimize: z.boolean().optional(), minimizer: z.literal("...").or(plugin).array().optional(), diff --git a/packages/rspack/src/rspackOptionsApply.ts b/packages/rspack/src/rspackOptionsApply.ts index eb958b03443..c7a2617c8a2 100644 --- a/packages/rspack/src/rspackOptionsApply.ts +++ b/packages/rspack/src/rspackOptionsApply.ts @@ -52,6 +52,7 @@ import { ModuleConcatenationPlugin, NamedChunkIdsPlugin, NamedModuleIdsPlugin, + NaturalModuleIdsPlugin, NodeTargetPlugin, RealContentHashPlugin, RemoveEmptyChunksPlugin, @@ -308,6 +309,10 @@ export class RspackOptionsApply { new NamedModuleIdsPlugin().apply(compiler); break; } + case "natural": { + new NaturalModuleIdsPlugin().apply(compiler); + break; + } case "deterministic": { new DeterministicModuleIdsPlugin().apply(compiler); break; diff --git a/website/docs/en/config/optimization.mdx b/website/docs/en/config/optimization.mdx index 0eb06b1d103..04a73f9eed5 100644 --- a/website/docs/en/config/optimization.mdx +++ b/website/docs/en/config/optimization.mdx @@ -10,10 +10,11 @@ Rspack will select appropriate optimization configuration based on the [`mode`]( ## optimization.moduleIds - + | option | description | | --------------- | ----------------------------------------------------------------------------------------------------------------------------------- | +| `natural` | Use numeric ids in order of usage. | | `named` | Use meaningful, easy-to-debug content as id. This option is enabled by default in development mode. | | `deterministic` | Use the hashed module identifier as the id to benefit from long-term caching. This option is enabled by default in production mode. | diff --git a/website/docs/zh/config/optimization.mdx b/website/docs/zh/config/optimization.mdx index 83143310427..7d9c2f55add 100644 --- a/website/docs/zh/config/optimization.mdx +++ b/website/docs/zh/config/optimization.mdx @@ -10,10 +10,11 @@ import WebpackLicense from '@components/webpack-license'; ## optimization.moduleIds - + | 选项 | 描述 | | --------------- | --------------------------------------------------------------------------------------- | +| `natural` | 根据模块加载的顺序使用自增数字作为模块 id。 | | `named` | 使用有意义、方便调试的内容当作模块 id。此选项会在开发环境下默认开启。 | | `deterministic` | 使用对模块标识符哈希后的数字当作模块 id,有益于长期缓存。此选项会在生产环境下默认开启。 |