Skip to content

Commit

Permalink
refactor: build info save module asset (#9230)
Browse files Browse the repository at this point in the history
* fix: build info save module asset

* fix: ci

* test: add test case
  • Loading branch information
jerrykingxyz authored Feb 11, 2025
1 parent 548b20e commit 7f11461
Show file tree
Hide file tree
Showing 21 changed files with 210 additions and 150 deletions.
3 changes: 1 addition & 2 deletions crates/node_binding/binding.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,6 @@ export declare class JsCompilation {
deleteAssetSource(name: string): void
getAssetFilenames(): Array<string>
hasAsset(name: string): boolean
emitAssetFromLoader(filename: string, source: JsCompatSource, assetInfo: JsAssetInfo, module: string): void
emitAsset(filename: string, source: JsCompatSource, assetInfo: JsAssetInfo): void
deleteAsset(filename: string): void
renameAsset(filename: string, newName: string): void
Expand Down Expand Up @@ -242,6 +241,7 @@ export declare class JsModule {
libIdent(options: JsLibIdentOptions): string | null
get resourceResolveData(): JsResourceData | undefined
get matchResource(): string | undefined
emitFile(filename: string, source: JsCompatSource, assetInfo: JsAssetInfo): void
}

export declare class JsModuleGraph {
Expand Down Expand Up @@ -672,7 +672,6 @@ export interface JsExecuteModuleResult {
buildDependencies: Array<string>
missingDependencies: Array<string>
cacheable: boolean
assets: Array<string>
id: number
error?: string
}
Expand Down
26 changes: 0 additions & 26 deletions crates/rspack_binding_values/src/compilation/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ use rspack_core::rspack_sources::BoxSource;
use rspack_core::AssetInfo;
use rspack_core::BoxDependency;
use rspack_core::Compilation;
use rspack_core::CompilationAsset;
use rspack_core::CompilationId;
use rspack_core::EntryDependency;
use rspack_core::EntryOptions;
Expand Down Expand Up @@ -323,29 +322,6 @@ impl JsCompilation {
Ok(compilation.assets().contains_key(&name))
}

#[napi]
pub fn emit_asset_from_loader(
&mut self,
filename: String,
source: JsCompatSource,
asset_info: JsAssetInfo,
module: String,
) -> Result<()> {
let compilation = self.as_mut()?;

compilation.emit_asset(
filename.clone(),
CompilationAsset::new(Some(source.into()), asset_info.into()),
);

compilation
.module_assets
.entry(ModuleIdentifier::from(module))
.or_default()
.insert(filename);
Ok(())
}

#[napi]
pub fn emit_asset(
&mut self,
Expand Down Expand Up @@ -676,7 +652,6 @@ impl JsCompilation {
.into_iter()
.map(|d| d.to_string_lossy().to_string())
.collect(),
assets: res.assets.into_iter().collect(),
id: res.id,
error: res.error,
};
Expand Down Expand Up @@ -884,7 +859,6 @@ pub struct JsExecuteModuleResult {
pub build_dependencies: Vec<String>,
pub missing_dependencies: Vec<String>,
pub cacheable: bool,
pub assets: Vec<String>,
pub id: u32,
pub error: Option<String>,
}
Expand Down
24 changes: 20 additions & 4 deletions crates/rspack_binding_values/src/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ use napi::JsString;
use napi_derive::napi;
use rspack_collections::IdentifierMap;
use rspack_core::{
BuildMeta, BuildMetaDefaultObject, BuildMetaExportsType, Compilation, CompilationId,
ExportsArgument, LibIdentOptions, Module, ModuleArgument, ModuleIdentifier, RuntimeModuleStage,
SourceType,
BuildMeta, BuildMetaDefaultObject, BuildMetaExportsType, Compilation, CompilationAsset,
CompilationId, ExportsArgument, LibIdentOptions, Module, ModuleArgument, ModuleIdentifier,
RuntimeModuleStage, SourceType,
};
use rspack_napi::{napi::bindgen_prelude::*, threadsafe_function::ThreadsafeFunction, OneShotRef};
use rspack_plugin_runtime::RuntimeModuleFromJs;
Expand All @@ -15,7 +15,7 @@ use rustc_hash::FxHashMap as HashMap;

use super::JsCompatSourceOwned;
use crate::{
JsChunkWrapper, JsCodegenerationResults, JsCompatSource, JsDependenciesBlockWrapper,
JsAssetInfo, JsChunkWrapper, JsCodegenerationResults, JsCompatSource, JsDependenciesBlockWrapper,
JsDependencyWrapper, JsResourceData, ToJsCompatSource,
};

Expand Down Expand Up @@ -325,6 +325,22 @@ impl JsModule {
None => Either::B(()),
})
}

#[napi]
pub fn emit_file(
&mut self,
filename: String,
source: JsCompatSource,
asset_info: JsAssetInfo,
) -> napi::Result<()> {
let module = self.as_mut()?;

module.build_info_mut().assets.insert(
filename,
CompilationAsset::new(Some(source.into()), asset_info.into()),
);
Ok(())
}
}

type ModuleInstanceRefs = IdentifierMap<OneShotRef<JsModule>>;
Expand Down
49 changes: 48 additions & 1 deletion crates/rspack_cacheable/src/with/as_preset/serde_json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use rkyv::{
with::{ArchiveWith, DeserializeWith, SerializeWith},
Place,
};
use serde_json::Value;
use serde_json::{Map, Value};

use super::AsPreset;
use crate::{DeserializeError, SerializeError};
Expand All @@ -15,6 +15,7 @@ pub struct SerdeJsonResolver {
value: String,
}

// for Value
impl ArchiveWith<Value> for AsPreset {
type Archived = ArchivedString;
type Resolver = SerdeJsonResolver;
Expand Down Expand Up @@ -49,3 +50,49 @@ where
.map_err(|_| DeserializeError::MessageError("deserialize serde_json value failed"))
}
}

// for Map<String, Value>
impl ArchiveWith<Map<String, Value>> for AsPreset {
type Archived = ArchivedString;
type Resolver = SerdeJsonResolver;

#[inline]
fn resolve_with(
_field: &Map<String, Value>,
resolver: Self::Resolver,
out: Place<Self::Archived>,
) {
let SerdeJsonResolver { inner, value } = resolver;
ArchivedString::resolve_from_str(&value, inner, out);
}
}

impl<S> SerializeWith<Map<String, Value>, S> for AsPreset
where
S: Fallible<Error = SerializeError> + Writer,
{
#[inline]
fn serialize_with(
field: &Map<String, Value>,
serializer: &mut S,
) -> Result<Self::Resolver, SerializeError> {
let value = serde_json::to_string(field)
.map_err(|_| SerializeError::MessageError("serialize serde_json value failed"))?;
let inner = ArchivedString::serialize_from_str(&value, serializer)?;
Ok(SerdeJsonResolver { value, inner })
}
}

impl<D> DeserializeWith<ArchivedString, Map<String, Value>, D> for AsPreset
where
D: Fallible<Error = DeserializeError>,
{
#[inline]
fn deserialize_with(
field: &ArchivedString,
_: &mut D,
) -> Result<Map<String, Value>, DeserializeError> {
serde_json::from_str(field)
.map_err(|_| DeserializeError::MessageError("deserialize serde_json value failed"))
}
}
47 changes: 31 additions & 16 deletions crates/rspack_core/src/compiler/compilation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@ use dashmap::DashSet;
use indexmap::{IndexMap, IndexSet};
use itertools::Itertools;
use rayon::prelude::*;
use rspack_cacheable::cacheable;
use rspack_cacheable::{
cacheable,
with::{AsOption, AsPreset},
};
use rspack_collections::{
DatabaseItem, Identifiable, IdentifierDashMap, IdentifierMap, IdentifierSet, UkeyMap, UkeySet,
};
Expand Down Expand Up @@ -173,7 +176,6 @@ pub struct Compilation {
pub entrypoints: IndexMap<String, ChunkGroupUkey>,
pub async_entrypoints: Vec<ChunkGroupUkey>,
assets: CompilationAssets,
pub module_assets: IdentifierMap<HashSet<String>>,
pub emitted_assets: DashSet<String, BuildHasherDefault<FxHasher>>,
diagnostics: Vec<Diagnostic>,
logging: CompilationLogging,
Expand Down Expand Up @@ -296,7 +298,6 @@ impl Compilation {
entrypoints: Default::default(),
async_entrypoints: Default::default(),
assets: Default::default(),
module_assets: Default::default(),
emitted_assets: Default::default(),
diagnostics: Default::default(),
logging: Default::default(),
Expand Down Expand Up @@ -618,7 +619,6 @@ impl Compilation {
filename: &str,
updater: impl FnOnce(BoxSource, AssetInfo) -> Result<(BoxSource, AssetInfo)>,
) -> Result<()> {
// Safety: we don't move anything from compilation
let assets = &mut self.assets;

let (new_source, new_info) = match assets.remove(filename) {
Expand Down Expand Up @@ -996,29 +996,39 @@ impl Compilation {

#[instrument("Compilation:create_module_assets", skip_all)]
async fn create_module_assets(&mut self, _plugin_driver: SharedPluginDriver) {
let mut temp = vec![];
for (module_identifier, assets) in self.module_assets.iter() {
let mut chunk_asset_map = vec![];
let mut module_assets = vec![];
let mg = self.get_module_graph();
for (identifier, module) in mg.modules() {
let assets = &module.build_info().assets;
if assets.is_empty() {
continue;
}

for (name, asset) in assets {
module_assets.push((name.clone(), asset.clone()));
}
// assets of executed modules are not in this compilation
if self
.chunk_graph
.chunk_graph_module_by_module_identifier
.contains_key(module_identifier)
.contains_key(&identifier)
{
for chunk in self
.chunk_graph
.get_module_chunks(*module_identifier)
.iter()
{
for asset in assets {
temp.push((*chunk, asset.clone()))
for chunk in self.chunk_graph.get_module_chunks(identifier).iter() {
for name in assets.keys() {
chunk_asset_map.push((*chunk, name.clone()))
}
}
}
}

for (chunk, asset) in temp {
for (name, asset) in module_assets {
self.emit_asset(name, asset);
}

for (chunk, asset_name) in chunk_asset_map {
let chunk = self.chunk_by_ukey.expect_get_mut(&chunk);
chunk.add_auxiliary_file(asset);
chunk.add_auxiliary_file(asset_name);
}
}

Expand Down Expand Up @@ -2260,8 +2270,10 @@ impl Compilation {

pub type CompilationAssets = HashMap<String, CompilationAsset>;

#[cacheable]
#[derive(Debug, Clone)]
pub struct CompilationAsset {
#[cacheable(with=AsOption<AsPreset>)]
pub source: Option<BoxSource>,
pub info: AssetInfo,
}
Expand Down Expand Up @@ -2302,6 +2314,7 @@ impl CompilationAsset {
}
}

#[cacheable]
#[derive(Debug, Default, Clone)]
pub struct AssetInfo {
/// if the asset can be long term cached forever (contains a hash)
Expand Down Expand Up @@ -2339,6 +2352,7 @@ pub struct AssetInfo {
/// But Napi.rs does not support Intersectiont types. This is a hack to store the additional fields
/// in the rust struct and have the Js side to reshape and align with webpack.
/// Related: packages/rspack/src/Compilation.ts
#[cacheable(with=AsPreset)]
pub extras: serde_json::Map<String, serde_json::Value>,
/// whether this asset is over the size limit
pub is_over_size_limit: Option<bool>,
Expand Down Expand Up @@ -2437,6 +2451,7 @@ impl AssetInfo {
}
}

#[cacheable]
#[derive(Debug, Default, Clone)]
pub struct AssetInfoRelated {
pub source_map: Option<String>,
Expand Down
24 changes: 9 additions & 15 deletions crates/rspack_core/src/compiler/module_executor/execute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ pub struct ExecuteModuleResult {
pub missing_dependencies: HashSet<ArcPath>,
pub build_dependencies: HashSet<ArcPath>,
pub code_generated_modules: IdentifierSet,
pub assets: HashSet<String>,
pub id: ExecuteModuleId,
}

Expand Down Expand Up @@ -82,14 +81,19 @@ impl Task<MakeTaskContext> for ExecuteTask {
.expect("should have module")
.identifier();
let mut queue = vec![entry_module_identifier];
let mut assets = CompilationAssets::default();
let mut modules = IdentifierSet::default();

while let Some(m) = queue.pop() {
modules.insert(m);
for m in mg.get_outgoing_connections(&m) {
let module = mg.module_by_identifier(&m).expect("should have module");
for (name, asset) in &module.build_info().assets {
assets.insert(name.clone(), asset.clone());
}
for c in mg.get_outgoing_connections(&m) {
// TODO: handle circle
if !modules.contains(m.module_identifier()) {
queue.push(*m.module_identifier());
if !modules.contains(c.module_identifier()) {
queue.push(*c.module_identifier());
}
}
}
Expand Down Expand Up @@ -263,18 +267,8 @@ impl Task<MakeTaskContext> for ExecuteTask {
}
};

let assets = std::mem::take(compilation.assets_mut());
assets.extend(std::mem::take(compilation.assets_mut()));
let code_generated_modules = std::mem::take(&mut compilation.code_generated_modules);
let module_assets = std::mem::take(&mut compilation.module_assets);
if execute_result.error.is_none() {
execute_result.assets = assets.keys().cloned().collect::<HashSet<_>>();
execute_result.assets.extend(
module_assets
.values()
.flat_map(|m| m.iter().map(|i| i.to_owned()).collect_vec())
.collect::<HashSet<String>>(),
);
}
let executed_runtime_modules = runtime_modules
.iter()
.map(|runtime_id| {
Expand Down
Loading

2 comments on commit 7f11461

@github-actions
Copy link
Contributor

@github-actions github-actions bot commented on 7f11461 Feb 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Ecosystem CI detail: Open

suite result
modernjs ❌ failure
rspress ✅ success
rslib ✅ success
rsbuild ❌ failure
rsdoctor ❌ failure
examples ✅ success
devserver ✅ success
nuxt ✅ success

@github-actions
Copy link
Contributor

@github-actions github-actions bot commented on 7f11461 Feb 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Benchmark detail: Open

Name Base (2025-02-11 9d82335) Current Change
10000_big_production-mode_disable-minimize + exec 37.7 s ± 637 ms 39.4 s ± 1.05 s +4.36 %
10000_development-mode + exec 1.88 s ± 89 ms 1.87 s ± 174 ms -0.14 %
10000_development-mode_hmr + exec 685 ms ± 7.4 ms 693 ms ± 28 ms +1.18 %
10000_production-mode + exec 2.28 s ± 51 ms 2.3 s ± 153 ms +1.07 %
10000_production-mode_persistent-cold + exec 2.47 s ± 72 ms 2.43 s ± 72 ms -1.56 %
10000_production-mode_persistent-hot + exec 1.65 s ± 61 ms 1.68 s ± 88 ms +1.84 %
arco-pro_development-mode + exec 1.78 s ± 145 ms 1.79 s ± 33 ms +0.53 %
arco-pro_development-mode_hmr + exec 389 ms ± 2.1 ms 387 ms ± 2.4 ms -0.36 %
arco-pro_production-mode + exec 3.59 s ± 217 ms 3.64 s ± 151 ms +1.25 %
arco-pro_production-mode_generate-package-json-webpack-plugin + exec 3.72 s ± 229 ms 3.67 s ± 94 ms -1.18 %
arco-pro_production-mode_persistent-cold + exec 3.85 s ± 164 ms 3.84 s ± 179 ms -0.22 %
arco-pro_production-mode_persistent-hot + exec 2.36 s ± 99 ms 2.38 s ± 44 ms +0.85 %
arco-pro_production-mode_traverse-chunk-modules + exec 3.63 s ± 69 ms 3.67 s ± 262 ms +1.18 %
large-dyn-imports_development-mode + exec 2.09 s ± 24 ms 2.15 s ± 112 ms +2.58 %
large-dyn-imports_production-mode + exec 2.15 s ± 71 ms 2.15 s ± 40 ms +0.03 %
threejs_development-mode_10x + exec 1.54 s ± 25 ms 1.57 s ± 31 ms +1.98 %
threejs_development-mode_10x_hmr + exec 779 ms ± 7 ms 787 ms ± 11 ms +1.01 %
threejs_production-mode_10x + exec 5.2 s ± 32 ms 5.23 s ± 64 ms +0.58 %
threejs_production-mode_10x_persistent-cold + exec 5.27 s ± 65 ms 5.35 s ± 206 ms +1.41 %
threejs_production-mode_10x_persistent-hot + exec 4.53 s ± 220 ms 4.51 s ± 84 ms -0.33 %
10000_big_production-mode_disable-minimize + rss memory 8706 MiB ± 32.4 MiB 8708 MiB ± 77 MiB +0.03 %
10000_development-mode + rss memory 649 MiB ± 12.6 MiB 664 MiB ± 21.8 MiB +2.31 %
10000_development-mode_hmr + rss memory 1344 MiB ± 112 MiB 1323 MiB ± 162 MiB -1.55 %
10000_production-mode + rss memory 621 MiB ± 21.8 MiB 631 MiB ± 26.3 MiB +1.61 %
10000_production-mode_persistent-cold + rss memory 746 MiB ± 24.7 MiB 744 MiB ± 24.6 MiB -0.38 %
10000_production-mode_persistent-hot + rss memory 717 MiB ± 23.3 MiB 715 MiB ± 24.7 MiB -0.24 %
arco-pro_development-mode + rss memory 569 MiB ± 17.5 MiB 576 MiB ± 19.8 MiB +1.27 %
arco-pro_development-mode_hmr + rss memory 643 MiB ± 49.1 MiB 656 MiB ± 55.3 MiB +2.11 %
arco-pro_production-mode + rss memory 714 MiB ± 28.8 MiB 697 MiB ± 15.3 MiB -2.43 %
arco-pro_production-mode_generate-package-json-webpack-plugin + rss memory 732 MiB ± 22.4 MiB 726 MiB ± 26.9 MiB -0.81 %
arco-pro_production-mode_persistent-cold + rss memory 853 MiB ± 45.5 MiB 834 MiB ± 30 MiB -2.22 %
arco-pro_production-mode_persistent-hot + rss memory 708 MiB ± 27.8 MiB 701 MiB ± 29 MiB -0.94 %
arco-pro_production-mode_traverse-chunk-modules + rss memory 727 MiB ± 48.2 MiB 715 MiB ± 30.6 MiB -1.65 %
large-dyn-imports_development-mode + rss memory 644 MiB ± 5.26 MiB 638 MiB ± 8.45 MiB -0.86 %
large-dyn-imports_production-mode + rss memory 526 MiB ± 7.84 MiB 525 MiB ± 8.45 MiB -0.26 %
threejs_development-mode_10x + rss memory 553 MiB ± 16.3 MiB 554 MiB ± 14.1 MiB +0.19 %
threejs_development-mode_10x_hmr + rss memory 1145 MiB ± 140 MiB 1146 MiB ± 70.1 MiB +0.08 %
threejs_production-mode_10x + rss memory 828 MiB ± 50.8 MiB 831 MiB ± 60.7 MiB +0.32 %
threejs_production-mode_10x_persistent-cold + rss memory 960 MiB ± 14.5 MiB 953 MiB ± 49 MiB -0.72 %
threejs_production-mode_10x_persistent-hot + rss memory 877 MiB ± 54.8 MiB 865 MiB ± 26 MiB -1.44 %

Please sign in to comment.