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
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/node_binding/napi-binding.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2290,6 +2290,7 @@ export interface RawExperiments {
newCache: boolean
deferImport: boolean
sourceImport: boolean
fasterModuleConcatenation: boolean
pureFunctions: boolean
runtimeMode?: "webpack" | "rspack"
}
Expand Down
11 changes: 11 additions & 0 deletions crates/rspack/src/builder/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3684,6 +3684,8 @@ pub struct ExperimentsBuilder {
defer_import: Option<bool>,
/// Whether to enable source import.
source_import: Option<bool>,
/// Whether to enable the faster module concatenation implementation.
faster_module_concatenation: Option<bool>,
// TODO: lazy compilation
pure_functions: Option<bool>,
runtime_mode: Option<RuntimeMode>,
Expand All @@ -3698,6 +3700,7 @@ impl From<Experiments> for ExperimentsBuilder {
async_web_assembly: None,
defer_import: Some(value.defer_import),
source_import: Some(value.source_import),
faster_module_concatenation: Some(value.faster_module_concatenation),
pure_functions: Some(value.pure_functions),
runtime_mode: Some(value.runtime_mode),
}
Expand All @@ -3713,6 +3716,7 @@ impl From<&mut ExperimentsBuilder> for ExperimentsBuilder {
async_web_assembly: value.async_web_assembly.take(),
defer_import: value.defer_import.take(),
source_import: value.source_import.take(),
faster_module_concatenation: value.faster_module_concatenation.take(),
pure_functions: value.pure_functions.take(),
runtime_mode: value.runtime_mode.take(),
}
Expand Down Expand Up @@ -3756,6 +3760,12 @@ impl ExperimentsBuilder {
self
}

/// Set whether to enable the faster module concatenation implementation.
pub fn faster_module_concatenation(&mut self, faster_module_concatenation: bool) -> &mut Self {
self.faster_module_concatenation = Some(faster_module_concatenation);
self
}

/// Build [`Experiments`] from options.
///
/// [`Experiments`]: rspack_core::options::Experiments
Expand All @@ -3775,6 +3785,7 @@ impl ExperimentsBuilder {
new_cache: d!(self.new_cache, false),
defer_import: d!(self.defer_import, false),
source_import: d!(self.source_import, false),
faster_module_concatenation: d!(self.faster_module_concatenation, false),
pure_functions: d!(self.pure_functions, _production),
runtime_mode: d!(self.runtime_mode, RuntimeMode::Webpack),
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1751,6 +1751,7 @@ CompilerOptions {
new_cache: false,
defer_import: false,
source_import: false,
faster_module_concatenation: false,
pure_functions: false,
runtime_mode: Webpack,
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ pub struct RawExperiments {
pub new_cache: bool,
pub defer_import: bool,
pub source_import: bool,
pub faster_module_concatenation: bool,
pub pure_functions: bool,
#[napi(ts_type = "\"webpack\" | \"rspack\"")]
pub runtime_mode: Option<String>,
Expand All @@ -34,6 +35,7 @@ impl From<RawExperiments> for Experiments {
new_cache: value.new_cache,
defer_import: value.defer_import,
source_import: value.source_import,
faster_module_concatenation: value.faster_module_concatenation,
pure_functions: value.pure_functions,
runtime_mode,
}
Expand Down
1 change: 1 addition & 0 deletions crates/rspack_core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ indoc = { workspace = true }
inventory = { workspace = true }
itertools = { workspace = true }
json = { workspace = true }
memchr = { workspace = true }
mime_guess = { workspace = true }
napi = { workspace = true, optional = true }
num-bigint = { workspace = true }
Expand Down
74 changes: 49 additions & 25 deletions crates/rspack_core/src/artifacts/code_generation_results.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ use rustc_hash::{FxHashMap as HashMap, FxHashSet};
use serde::Serialize;

use crate::{
ArtifactExt, AssetInfo, BindingCell, ChunkInitFragments, ConcatenationScope, ModuleIdentifier,
RuntimeGlobals, RuntimeSpec, RuntimeSpecMap, SourceType, incremental::IncrementalPasses,
ArtifactExt, AssetInfo, BindingCell, ChunkInitFragments, ConcatenationCodeGenerationSource,
ConcatenationScope, ModuleIdentifier, RenderedInitFragments, RuntimeGlobals, RuntimeSpec,
RuntimeSpecMap, SourceType, incremental::IncrementalPasses,
};

#[derive(Clone, Debug)]
Expand Down Expand Up @@ -92,6 +93,26 @@ impl CodeGenerationDataTopLevelDeclarations {
}
}

/// Typed [`CodeGenerationData`] entry for the digest of rendered init fragments.
///
/// `CodeGenerationData` is keyed by `TypeId`, so the newtype keeps this digest
/// distinct from other `RspackHashDigest` values stored as code generation data.
#[derive(Clone, Debug)]
pub struct RenderedInitFragmentsDigest(RspackHashDigest);

impl RenderedInitFragmentsDigest {
pub fn new(inner: RspackHashDigest) -> Self {
Self(inner)
}
}

impl RspackHash for RenderedInitFragmentsDigest {
fn hash(&self, state: &mut RspackHasher) {
state.write(b"RenderedInitFragmentsDigest");
self.0.hash(state);
}
}

#[derive(Debug, Default, Clone)]
pub struct CodeGenerationData {
inner: anymap::Map<dyn CloneAny + Send + Sync>,
Expand All @@ -114,6 +135,9 @@ impl DerefMut for CodeGenerationData {
#[derive(Debug, Default, Clone)]
pub struct CodeGenerationResult {
pub inner: BindingCell<HashMap<SourceType, BoxSource>>,
/// Editable JavaScript output used only while generating a concatenated
/// module. Keeping it typed avoids inferring mutability from `BoxSource`.
pub concatenation_source: Option<Box<ConcatenationCodeGenerationSource>>,
/// [definition in webpack](https://github.com/webpack/webpack/blob/4b4ca3bb53f36a5b8fc6bc1bd976ed7af161bd80/lib/Module.js#L75)
pub data: CodeGenerationData,
pub chunk_init_fragments: ChunkInitFragments,
Expand Down Expand Up @@ -142,37 +166,37 @@ impl CodeGenerationResult {
debug_assert!(result.is_none());
}

pub fn set_hash(
&mut self,
hash_function: &HashFunction,
hash_digest: &HashDigest,
hash_salt: &HashSalt,
) {
let mut hasher = RspackHasher::with_salt(hash_function, hash_salt);
for (source_type, source) in self.inner.as_ref() {
source_type.hash(&mut hasher);
std::hash::Hash::hash(source, &mut hasher);
}
self.chunk_init_fragments.hash(&mut hasher);
self.runtime_requirements.hash(&mut hasher);
self.hash = Some(hasher.digest(hash_digest));
pub fn set_concatenation_source(&mut self, source: Box<ConcatenationCodeGenerationSource>) {
let previous = self.concatenation_source.replace(source);
debug_assert!(previous.is_none());
}

/// Concatenated modules already encode the generated module bodies into
/// `ConcatenatedModule::get_runtime_hash`, so we can reuse that digest here
/// and only mix in codegen-specific metadata instead of hashing the large
/// concatenated source again.
pub fn set_hash_for_concatenated_module(
pub fn set_hash(
&mut self,
runtime_hash: &RspackHashDigest,
hash_function: &HashFunction,
hash_digest: &HashDigest,
hash_salt: &HashSalt,
concatenated_module_hash: Option<&RspackHashDigest>,
) {
let mut hasher = RspackHasher::with_salt(hash_function, hash_salt);
runtime_hash.hash(&mut hasher);
for source_type in self.inner.as_ref().keys() {
source_type.hash(&mut hasher);
if let Some(concatenated_module_hash) = concatenated_module_hash {
concatenated_module_hash.hash(&mut hasher);
for source_type in self.inner.as_ref().keys() {
source_type.hash(&mut hasher);
}
if let Some(digest) = self.data.get::<RenderedInitFragmentsDigest>() {
digest.hash(&mut hasher);
}
} else {
for (source_type, source) in self.inner.as_ref() {
source_type.hash(&mut hasher);
std::hash::Hash::hash(source, &mut hasher);
}
if let Some(fragments) = self.data.get::<RenderedInitFragments>()
&& !fragments.is_empty()
{
fragments.hash(&mut hasher);
}
}
self.chunk_init_fragments.hash(&mut hasher);
self.runtime_requirements.hash(&mut hasher);
Expand Down
27 changes: 10 additions & 17 deletions crates/rspack_core/src/compilation/code_generation/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -194,23 +194,15 @@ pub(crate) async fn code_generation_modules(
codegen_res
.runtime_requirements
.extend(*runtime_template.runtime_requirements());
if module.as_concatenated_module().is_some() {
// Concatenated modules are special here: `job.hash` already
// fingerprints the generated module bodies, so we only need
// to fold in the remaining codegen metadata.
codegen_res.set_hash_for_concatenated_module(
&job.hash,
&options.output.hash_function,
&options.output.hash_digest,
&options.output.hash_salt,
);
} else {
codegen_res.set_hash(
&options.output.hash_function,
&options.output.hash_digest,
&options.output.hash_salt,
);
}
codegen_res.set_hash(
&options.output.hash_function,
&options.output.hash_digest,
&options.output.hash_salt,
module
.as_concatenated_module()
.is_some()
.then_some(&job.hash),
);
codegen_res
})
})
Expand Down Expand Up @@ -245,6 +237,7 @@ pub(crate) async fn code_generation_modules(
&compilation.options.output.hash_function,
&compilation.options.output.hash_digest,
&compilation.options.output.hash_salt,
None,
);
codegen_res
}
Expand Down
Loading
Loading