Skip to content

Commit

Permalink
refactor: JsChunkGroup
Browse files Browse the repository at this point in the history
  • Loading branch information
SyMind committed Dec 9, 2024
1 parent 9543df1 commit cac16e1
Show file tree
Hide file tree
Showing 9 changed files with 200 additions and 101 deletions.
32 changes: 14 additions & 18 deletions crates/node_binding/src/plugins/interceptor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ use rspack_binding_values::{
JsAfterEmitData, JsAfterResolveData, JsAfterResolveOutput, JsAfterTemplateExecutionData,
JsAlterAssetTagGroupsData, JsAlterAssetTagsData, JsAssetEmittedArgs,
JsBeforeAssetTagGenerationData, JsBeforeEmitData, JsBeforeResolveArgs, JsBeforeResolveOutput,
JsChunk, JsChunkAssetArgs, JsCompilationWrapper, JsContextModuleFactoryAfterResolveDataWrapper,
JsContextModuleFactoryAfterResolveResult, JsContextModuleFactoryBeforeResolveDataWrapper,
JsContextModuleFactoryBeforeResolveResult, JsCreateData, JsExecuteModuleArg, JsFactorizeArgs,
JsFactorizeOutput, JsModuleWrapper, JsNormalModuleFactoryCreateModuleArgs, JsResolveArgs,
JsResolveForSchemeArgs, JsResolveForSchemeOutput, JsResolveOutput, JsRuntimeGlobals,
JsRuntimeModule, JsRuntimeModuleArg, JsRuntimeRequirementInTreeArg,
JsRuntimeRequirementInTreeResult, ToJsCompatSourceOwned,
JsChunk, JsChunkAssetArgs, JsChunkWrapper, JsCompilationWrapper,
JsContextModuleFactoryAfterResolveDataWrapper, JsContextModuleFactoryAfterResolveResult,
JsContextModuleFactoryBeforeResolveDataWrapper, JsContextModuleFactoryBeforeResolveResult,
JsCreateData, JsExecuteModuleArg, JsFactorizeArgs, JsFactorizeOutput, JsModuleWrapper,
JsNormalModuleFactoryCreateModuleArgs, JsResolveArgs, JsResolveForSchemeArgs,
JsResolveForSchemeOutput, JsResolveOutput, JsRuntimeGlobals, JsRuntimeModule, JsRuntimeModuleArg,
JsRuntimeRequirementInTreeArg, JsRuntimeRequirementInTreeResult, ToJsCompatSourceOwned,
};
use rspack_collections::IdentifierSet;
use rspack_core::{
Expand Down Expand Up @@ -1191,9 +1191,8 @@ impl CompilationAdditionalTreeRuntimeRequirements
chunk_ukey: &ChunkUkey,
runtime_requirements: &mut RuntimeGlobals,
) -> rspack_error::Result<()> {
let chunk = compilation.chunk_by_ukey.expect_get(chunk_ukey);
let arg = JsAdditionalTreeRuntimeRequirementsArg {
chunk: JsChunk::from(chunk, compilation),
chunk: JsChunkWrapper::new(chunk_ukey, compilation),
runtime_requirements: JsRuntimeGlobals::from(*runtime_requirements),
};
let result = self.function.call_with_sync(arg).await?;
Expand All @@ -1218,9 +1217,8 @@ impl CompilationRuntimeRequirementInTree for CompilationRuntimeRequirementInTree
_runtime_requirements: &RuntimeGlobals,
runtime_requirements_mut: &mut RuntimeGlobals,
) -> rspack_error::Result<Option<()>> {
let chunk = compilation.chunk_by_ukey.expect_get(chunk_ukey);
let arg = JsRuntimeRequirementInTreeArg {
chunk: JsChunk::from(chunk, compilation),
chunk: JsChunkWrapper::new(chunk_ukey, compilation),
runtime_requirements: JsRuntimeGlobals::from(*all_runtime_requirements),
};
let result = self.function.blocking_call_with_sync(arg)?;
Expand All @@ -1245,12 +1243,12 @@ impl CompilationRuntimeModule for CompilationRuntimeModuleTap {
&self,
compilation: &mut Compilation,
m: &ModuleIdentifier,
c: &ChunkUkey,
chunk_ukey: &ChunkUkey,
) -> rspack_error::Result<()> {
let Some(module) = compilation.runtime_modules.get(m) else {
return Ok(());
};
let chunk = compilation.chunk_by_ukey.expect_get(c);
let chunk = compilation.chunk_by_ukey.expect_get(chunk_ukey);
let arg = JsRuntimeModuleArg {
module: JsRuntimeModule {
source: Some(
Expand All @@ -1267,7 +1265,7 @@ impl CompilationRuntimeModule for CompilationRuntimeModuleTap {
.cow_replace("webpack/runtime/", "")
.into_owned(),
},
chunk: JsChunk::from(chunk, compilation),
chunk: JsChunkWrapper::new(chunk_ukey, compilation),
};
if let Some(module) = self.function.call_with_sync(arg).await?
&& let Some(source) = module.source
Expand All @@ -1294,10 +1292,9 @@ impl CompilationChunkHash for CompilationChunkHashTap {
chunk_ukey: &ChunkUkey,
hasher: &mut RspackHash,
) -> rspack_error::Result<()> {
let chunk = compilation.chunk_by_ukey.expect_get(chunk_ukey);
let result = self
.function
.call_with_sync(JsChunk::from(chunk, compilation))
.call_with_sync(JsChunkWrapper::new(chunk_ukey, compilation))
.await?;
result.hash(hasher);
Ok(())
Expand Down Expand Up @@ -1661,10 +1658,9 @@ impl JavascriptModulesChunkHash for JavascriptModulesChunkHashTap {
chunk_ukey: &ChunkUkey,
hasher: &mut RspackHash,
) -> rspack_error::Result<()> {
let chunk = compilation.chunk_by_ukey.expect_get(chunk_ukey);
let result = self
.function
.call_with_sync(JsChunk::from(chunk, compilation))
.call_with_sync(JsChunkWrapper::new(chunk_ukey, compilation))
.await?;
result.hash(hasher);
Ok(())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,19 @@ use rspack_error::Result;
use rspack_napi::threadsafe_function::ThreadsafeFunction;
use rspack_plugin_banner::{BannerContent, BannerContentFnCtx, BannerPluginOptions};

#[napi(object)]
#[napi(object, object_from_js = false)]
pub struct RawBannerContentFnCtx {
pub hash: String,
pub chunk: JsChunk,
#[napi(js_name = "JsChunk")]
pub chunk: JsChunkWrapper,
pub filename: String,
}

impl<'a> From<BannerContentFnCtx<'a>> for RawBannerContentFnCtx {
fn from(value: BannerContentFnCtx) -> Self {
Self {
hash: value.hash.to_string(),
chunk: JsChunk::from(value.chunk, value.compilation),
chunk: JsChunkWrapper::new(value.chunk.ukey(), value.compilation),
filename: value.filename.to_string(),
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ pub fn create_chunks_filter(raw: Chunks) -> rspack_plugin_split_chunks::ChunkFil
let js_str = js_str.into_string();
rspack_plugin_split_chunks::create_chunk_filter_from_str(&js_str)
}
Either3::C(f) => {
Arc::new(move |chunk, compilation| block_on(f.call(JsChunk::from(chunk, compilation))))
}
Either3::C(f) => Arc::new(move |chunk, compilation| {
block_on(f.call(JsChunkWrapper::new(chunk.ukey(), compilation)))
}),
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ impl<'a> From<ChunkNameGetterFnCtx<'a>> for RawChunkOptionNameCtx {
chunks: value
.chunks
.iter()
.map(|chunk| JsChunk::from(chunk, value.compilation))
.map(|chunk| JsChunkWrapper::new(chunk.ukey(), value.compilation))
.collect(),
cache_group_key: value.cache_group_key.to_string(),
}
Expand Down
2 changes: 1 addition & 1 deletion crates/rspack_binding_values/src/chunk_graph.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use std::ptr::NonNull;

use napi::Result;
use napi_derive::napi;
use rspack_core::{Compilation, SourceType};
use rspack_napi::Result;

use crate::{JsChunk, JsChunkWrapper, JsModuleWrapper};

Expand Down
212 changes: 155 additions & 57 deletions crates/rspack_binding_values/src/chunk_group.rs
Original file line number Diff line number Diff line change
@@ -1,80 +1,178 @@
use std::{cell::RefCell, ptr::NonNull};

use napi::{bindgen_prelude::ToNapiValue, Env, JsString};
use napi_derive::napi;
use rspack_core::{ChunkGroup, ChunkGroupUkey, Compilation};
use rspack_core::{ChunkGroup, ChunkGroupUkey, Compilation, CompilationId};
use rspack_napi::OneShotRef;
use rustc_hash::FxHashMap as HashMap;

use crate::{JsChunk, JsCompilation, JsModuleWrapper};
use crate::{JsChunkWrapper, JsModuleWrapper};

#[napi(object, object_from_js = false)]
#[napi]
pub struct JsChunkGroup {
#[napi(js_name = "__inner_parents")]
pub inner_parents: Vec<u32>,
#[napi(js_name = "__inner_ukey")]
pub inner_ukey: u32,
pub chunks: Vec<JsChunk>,
pub index: Option<u32>,
pub name: Option<String>,
pub is_initial: bool,
pub origins: Vec<JsChunkGroupOrigin>,
chunk_group_ukey: ChunkGroupUkey,
compilation_id: CompilationId,
compilation: NonNull<Compilation>,
}

#[napi(object, object_from_js = false)]
pub struct JsChunkGroupOrigin {
#[napi(ts_type = "JsModule | undefined")]
pub module: Option<JsModuleWrapper>,
pub request: Option<String>,
impl JsChunkGroup {
fn as_ref(&self) -> napi::Result<(&'static Compilation, &'static ChunkGroup)> {
let compilation = unsafe { self.compilation.as_ref() };
if let Some(chunk_group) = compilation.chunk_group_by_ukey.get(&self.chunk_group_ukey) {
Ok((compilation, chunk_group))
} else {
Err(napi::Error::from_reason(format!(
"Unable to access chunk_group with id = {:?} now. The module have been removed on the Rust side.",
self.chunk_group_ukey
)))
}
}
}

#[napi]
impl JsChunkGroup {
pub fn from_chunk_group(
cg: &rspack_core::ChunkGroup,
compilation: &rspack_core::Compilation,
) -> Self {
Self {
chunks: cg
#[napi(getter, ts_return_type = "JsChunk[]")]
pub fn chunks(&self) -> napi::Result<Vec<JsChunkWrapper>> {
let (compilation, chunk_graph) = self.as_ref()?;
Ok(
chunk_graph
.chunks
.iter()
.map(|k| JsChunk::from(compilation.chunk_by_ukey.expect_get(k), compilation))
.collect(),
index: cg.index,
inner_parents: cg.parents.iter().map(|ukey| ukey.as_u32()).collect(),
inner_ukey: cg.ukey.as_u32(),
name: cg.name().map(|name| name.to_string()),
is_initial: cg.is_initial(),
origins: cg
.origins()
.iter()
.map(|origin| JsChunkGroupOrigin {
module: origin.module_id.map(|module_id| {
let module = compilation
.module_by_identifier(&module_id)
.unwrap_or_else(|| panic!("failed to retrieve module by id: {}", module_id));
JsModuleWrapper::new(module.as_ref(), compilation.id(), Some(compilation))
}),
request: origin.request.clone(),
})
.map(|ukey| JsChunkWrapper::new(*ukey, compilation))
.collect::<Vec<_>>(),
)
}

#[napi(getter)]
pub fn index(&self) -> napi::Result<Option<u32>> {
let (_, chunk_graph) = self.as_ref()?;
Ok(chunk_graph.index)
}

#[napi(getter)]
pub fn name(&self) -> napi::Result<Option<&str>> {
let (_, chunk_graph) = self.as_ref()?;
Ok(chunk_graph.name())
}

#[napi(getter)]
pub fn is_initial(&self) -> napi::Result<bool> {
let (_, chunk_graph) = self.as_ref()?;
Ok(chunk_graph.is_initial())
}

#[napi(getter)]
pub fn origins(&self, env: Env) -> napi::Result<Vec<JsChunkGroupOrigin>> {
let (compilation, chunk_graph) = self.as_ref()?;
let origins = chunk_graph.origins();
let mut js_origins = Vec::with_capacity(origins.len());

for origin in origins {
js_origins.push(JsChunkGroupOrigin {
module: origin.module_id.and_then(|module_id| {
compilation.module_by_identifier(&module_id).map(|module| {
JsModuleWrapper::new(module.as_ref(), self.compilation_id, Some(compilation))
})
}),
request: match &origin.request {
Some(request) => Some(env.create_string(request)?),
None => None,
},
})
}

Ok(js_origins)
}
}

fn chunk_group(ukey: u32, compilation: &Compilation) -> &ChunkGroup {
let ukey = ChunkGroupUkey::from(ukey);
compilation.chunk_group_by_ukey.expect_get(&ukey)
#[napi]
impl JsChunkGroup {
#[napi(ts_return_type = "JsChunkGroup[]")]
pub fn get_parents(&self) -> napi::Result<Vec<JsChunkGroupWrapper>> {
let (compilation, chunk_graph) = self.as_ref()?;
Ok(
chunk_graph
.parents
.iter()
.map(|ukey| JsChunkGroupWrapper::new(*ukey, &compilation))
.collect(),
)
}

#[napi(ts_return_type = "JsChunk")]
pub fn get_runtime_chunk(&self) -> napi::Result<JsChunkWrapper> {
let (compilation, chunk_graph) = self.as_ref()?;
let chunk_ukey = chunk_graph.get_runtime_chunk(&compilation.chunk_group_by_ukey);
Ok(JsChunkWrapper::new(chunk_ukey, compilation))
}
}

#[napi(js_name = "__chunk_group_inner_get_chunk_group")]
pub fn get_chunk_group(ukey: u32, js_compilation: &JsCompilation) -> JsChunkGroup {
let compilation = unsafe { js_compilation.inner.as_ref() };
thread_local! {
static CHUNK_GROUP_INSTANCE_REFS: RefCell<HashMap<CompilationId, HashMap<ChunkGroupUkey, OneShotRef<JsChunkGroup>>>> = Default::default();
}

let cg = chunk_group(ukey, compilation);
JsChunkGroup::from_chunk_group(cg, compilation)
pub struct JsChunkGroupWrapper {
chunk_group_ukey: ChunkGroupUkey,
compilation_id: CompilationId,
compilation: NonNull<Compilation>,
}

#[napi(js_name = "__entrypoint_inner_get_runtime_chunk")]
pub fn get_runtime_chunk(ukey: u32, js_compilation: &JsCompilation) -> JsChunk {
let compilation = unsafe { js_compilation.inner.as_ref() };
impl JsChunkGroupWrapper {
pub fn new(chunk_group_ukey: ChunkGroupUkey, compilation: &Compilation) -> Self {
#[allow(clippy::unwrap_used)]
Self {
chunk_group_ukey,
compilation_id: compilation.id(),
compilation: NonNull::new(compilation as *const Compilation as *mut Compilation).unwrap(),
}
}

let entrypoint = chunk_group(ukey, compilation);
let chunk_ukey = entrypoint.get_runtime_chunk(&compilation.chunk_group_by_ukey);
let chunk = compilation.chunk_by_ukey.expect_get(&chunk_ukey);
JsChunk::from(chunk, compilation)
pub fn cleanup_last_compilation(compilation_id: CompilationId) {
CHUNK_GROUP_INSTANCE_REFS.with(|refs| {
let mut refs_by_compilation_id = refs.borrow_mut();
refs_by_compilation_id.remove(&compilation_id)
});
}
}

impl ToNapiValue for JsChunkGroupWrapper {
unsafe fn to_napi_value(
env: napi::sys::napi_env,
val: Self,
) -> napi::Result<napi::sys::napi_value> {
CHUNK_GROUP_INSTANCE_REFS.with(|refs| {
let mut refs_by_compilation_id = refs.borrow_mut();
let entry = refs_by_compilation_id.entry(val.compilation_id);
let refs = match entry {
std::collections::hash_map::Entry::Occupied(entry) => entry.into_mut(),
std::collections::hash_map::Entry::Vacant(entry) => {
let refs = HashMap::default();
entry.insert(refs)
}
};

match refs.entry(val.chunk_group_ukey) {
std::collections::hash_map::Entry::Occupied(entry) => {
let r = entry.get();
ToNapiValue::to_napi_value(env, r)
}
std::collections::hash_map::Entry::Vacant(entry) => {
let js_module = JsChunkGroup {
chunk_group_ukey: val.chunk_group_ukey,
compilation_id: val.compilation_id,
compilation: val.compilation,
};
let r = entry.insert(OneShotRef::new(env, js_module)?);
ToNapiValue::to_napi_value(env, r)
}
}
})
}
}

#[napi(object, object_from_js = false)]
pub struct JsChunkGroupOrigin {
#[napi(ts_type = "JsModule | undefined")]
pub module: Option<JsModuleWrapper>,
pub request: Option<JsString>,
}
Loading

0 comments on commit cac16e1

Please sign in to comment.