Skip to content

Commit

Permalink
Turbopack chunking: use ChunkableModules in chunk_content, not Chun…
Browse files Browse the repository at this point in the history
…kItems (#74040)

This:

- Replaces all use of chunk items in the interface for `chunk_content`
with ChunkableModules
- Moves `is_self_async` from `ChunkItem` to `Module`
- Renames `AvailableChunkItems` to `AvailableModules` and all associated
structs and methods, using modules in place of chunk items

---------

Co-authored-by: Tobias Koppers <[email protected]>
  • Loading branch information
wbinnssmith and sokra authored Jan 10, 2025
1 parent 40a4c3b commit 4ef926b
Show file tree
Hide file tree
Showing 31 changed files with 652 additions and 468 deletions.
2 changes: 1 addition & 1 deletion crates/next-api/src/server_actions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ async fn build_manifest(
&key,
ActionManifestWorkerEntry {
module_id: ActionManifestModuleId::String(loader_id.as_str()),
is_async: *chunk_item.is_self_async().await?,
is_async: *chunk_item.module().is_self_async().await?,
},
);
entry.layer.insert(&key, *layer);
Expand Down
52 changes: 30 additions & 22 deletions crates/next-core/src/next_manifests/client_reference_manifest.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
use anyhow::Result;
use anyhow::{Context, Result};
use indoc::formatdoc;
use turbo_rcstr::RcStr;
use turbo_tasks::{FxIndexSet, ResolvedVc, TryJoinIterExt, Value, ValueToString, Vc};
use turbo_tasks_fs::{File, FileSystemPath};
use turbopack_core::{
asset::{Asset, AssetContent},
chunk::{
availability_info::AvailabilityInfo, ChunkItem, ChunkItemExt, ChunkableModule,
ChunkingContext, ModuleId as TurbopackModuleId,
availability_info::AvailabilityInfo, ChunkItemExt, ChunkableModule, ChunkingContext,
ModuleId as TurbopackModuleId,
},
output::{OutputAsset, OutputAssets},
virtual_output::VirtualOutputAsset,
Expand Down Expand Up @@ -75,8 +75,8 @@ impl ClientReferenceManifest {

let server_path = ecmascript_client_reference.server_ident.to_string().await?;

let client_chunk_item = ecmascript_client_reference
.client_module
let client_module = ecmascript_client_reference.client_module;
let client_chunk_item = client_module
.as_chunk_item(Vc::upcast(client_chunking_context))
.to_resolved()
.await?;
Expand Down Expand Up @@ -107,28 +107,32 @@ impl ClientReferenceManifest {
.map(RcStr::from)
.collect::<Vec<_>>();

let is_async =
is_item_async(client_availability_info, client_chunk_item).await?;
let is_async = is_item_async(
client_availability_info,
ResolvedVc::upcast(client_module),
)
.await?;

(chunk_paths, is_async)
} else {
(Vec::new(), false)
};

if let Some(ssr_chunking_context) = ssr_chunking_context {
let ssr_chunk_item = ecmascript_client_reference
.ssr_module
let ssr_module = ecmascript_client_reference.ssr_module;
let ssr_chunk_item = ssr_module
.as_chunk_item(Vc::upcast(ssr_chunking_context))
.to_resolved()
.await?;
let ssr_module_id = ssr_chunk_item.id().await?;

let rsc_chunk_item: ResolvedVc<Box<dyn ChunkItem>> =
ResolvedVc::try_downcast_type::<EcmascriptClientReferenceProxyModule>(
parent_module,
)
.await?
.unwrap()
let rsc_module = ResolvedVc::try_downcast_type::<
EcmascriptClientReferenceProxyModule,
>(parent_module)
.await?
.context("Expected EcmascriptClientReferenceProxyModule")?;

let rsc_chunk_item = rsc_module
.as_chunk_item(Vc::upcast(ssr_chunking_context))
.to_resolved()
.await?;
Expand Down Expand Up @@ -161,7 +165,9 @@ impl ClientReferenceManifest {
.map(RcStr::from)
.collect::<Vec<_>>();

let is_async = is_item_async(ssr_availability_info, ssr_chunk_item).await?;
let is_async =
is_item_async(ssr_availability_info, ResolvedVc::upcast(ssr_module))
.await?;

(chunk_paths, is_async)
} else {
Expand All @@ -188,9 +194,11 @@ impl ClientReferenceManifest {
.map(RcStr::from)
.collect::<Vec<_>>();

let is_async =
is_item_async(&rsc_app_entry_chunks_availability, rsc_chunk_item)
.await?;
let is_async = is_item_async(
&rsc_app_entry_chunks_availability,
ResolvedVc::upcast(rsc_module),
)
.await?;

(chunk_paths, is_async)
};
Expand Down Expand Up @@ -368,13 +376,13 @@ pub fn get_client_reference_module_key(server_path: &str, export_name: &str) ->

async fn is_item_async(
availability_info: &AvailabilityInfo,
chunk_item: ResolvedVc<Box<dyn ChunkItem>>,
module: ResolvedVc<Box<dyn ChunkableModule>>,
) -> Result<bool> {
let Some(available_chunk_items) = availability_info.available_chunk_items() else {
let Some(available_modules) = availability_info.available_modules() else {
return Ok(false);
};

let Some(info) = available_chunk_items.await?.get(chunk_item).await? else {
let Some(info) = &*available_modules.get(*module).await? else {
return Ok(false);
};

Expand Down
6 changes: 2 additions & 4 deletions turbopack/crates/turbopack-browser/src/chunking_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -422,11 +422,9 @@ impl ChunkingContext for BrowserChunkingContext {
AvailabilityInfo::Untracked => {
ident = ident.with_modifier(Vc::cell("untracked".into()));
}
AvailabilityInfo::Complete {
available_chunk_items,
} => {
AvailabilityInfo::Complete { available_modules } => {
ident = ident.with_modifier(Vc::cell(
available_chunk_items.hash().await?.to_string().into(),
available_modules.hash().await?.to_string().into(),
));
}
}
Expand Down
30 changes: 25 additions & 5 deletions turbopack/crates/turbopack-browser/src/ecmascript/content_entry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@ use anyhow::Result;
use tracing::{info_span, Instrument};
use turbo_tasks::{FxIndexMap, ReadRef, ResolvedVc, TryJoinIterExt, ValueToString, Vc};
use turbopack_core::{
chunk::{AsyncModuleInfo, ChunkItem, ChunkItemExt, ModuleId},
chunk::{AsyncModuleInfo, ChunkItem, ChunkItemExt, ChunkItemTy, ModuleId},
code_builder::{Code, CodeBuilder},
error::PrettyPrintError,
issue::{code_gen::CodeGenerationIssue, IssueExt, IssueSeverity, StyledString},
};
use turbopack_ecmascript::chunk::{
EcmascriptChunkContent, EcmascriptChunkItem, EcmascriptChunkItemExt,
EcmascriptChunkItemWithAsyncInfo,
};

/// A chunk item's content entry.
Expand All @@ -28,7 +29,7 @@ pub struct EcmascriptDevChunkContentEntry {

impl EcmascriptDevChunkContentEntry {
pub async fn new(
chunk_item: Vc<Box<dyn EcmascriptChunkItem>>,
chunk_item: ResolvedVc<Box<dyn EcmascriptChunkItem>>,
async_module_info: Option<Vc<AsyncModuleInfo>>,
) -> Result<Self> {
let code = chunk_item.code(async_module_info).to_resolved().await?;
Expand All @@ -52,15 +53,34 @@ impl EcmascriptDevChunkContentEntries {
) -> Result<Vc<EcmascriptDevChunkContentEntries>> {
let chunk_content = chunk_content.await?;

let entries: FxIndexMap<_, _> = chunk_content
let included_chunk_items = chunk_content
.chunk_items
.iter()
.map(|&(chunk_item, async_module_info)| async move {
.map(
async |EcmascriptChunkItemWithAsyncInfo {
ty,
chunk_item,
async_info,
}| {
if matches!(ty, ChunkItemTy::Included) {
Ok(Some((chunk_item, async_info)))
} else {
Ok(None)
}
},
)
.try_join()
.await?
.into_iter()
.flatten();

let entries: FxIndexMap<_, _> = included_chunk_items
.map(|(&chunk_item, &async_module_info)| async move {
async move {
Ok((
chunk_item.id().await?,
EcmascriptDevChunkContentEntry::new(
*chunk_item,
chunk_item,
async_module_info.map(|info| *info),
)
.await?,
Expand Down
1 change: 1 addition & 0 deletions turbopack/crates/turbopack-browser/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#![feature(async_closure)]
#![feature(iter_intersperse)]
#![feature(int_roundings)]
#![feature(arbitrary_self_types)]
Expand Down
26 changes: 10 additions & 16 deletions turbopack/crates/turbopack-core/src/chunk/availability_info.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use anyhow::Result;
use turbo_tasks::{ResolvedVc, Vc};

use super::available_chunk_items::{AvailableChunkItemInfoMap, AvailableChunkItems};
use super::available_modules::{AvailableModuleInfoMap, AvailableModules};

#[turbo_tasks::value(serialization = "auto_for_input")]
#[derive(Hash, Clone, Copy, Debug)]
Expand All @@ -12,36 +12,30 @@ pub enum AvailabilityInfo {
Root,
/// There are modules already available.
Complete {
available_chunk_items: ResolvedVc<AvailableChunkItems>,
available_modules: ResolvedVc<AvailableModules>,
},
}

impl AvailabilityInfo {
pub fn available_chunk_items(&self) -> Option<ResolvedVc<AvailableChunkItems>> {
pub fn available_modules(&self) -> Option<ResolvedVc<AvailableModules>> {
match self {
Self::Untracked => None,
Self::Root => None,
Self::Complete {
available_chunk_items,
..
} => Some(*available_chunk_items),
available_modules, ..
} => Some(*available_modules),
}
}

pub async fn with_chunk_items(
self,
chunk_items: Vc<AvailableChunkItemInfoMap>,
) -> Result<Self> {
pub async fn with_modules(self, modules: Vc<AvailableModuleInfoMap>) -> Result<Self> {
Ok(match self {
AvailabilityInfo::Untracked => AvailabilityInfo::Untracked,
AvailabilityInfo::Root => AvailabilityInfo::Complete {
available_chunk_items: AvailableChunkItems::new(chunk_items).to_resolved().await?,
available_modules: AvailableModules::new(modules).to_resolved().await?,
},
AvailabilityInfo::Complete {
available_chunk_items,
} => AvailabilityInfo::Complete {
available_chunk_items: available_chunk_items
.with_chunk_items(chunk_items)
AvailabilityInfo::Complete { available_modules } => AvailabilityInfo::Complete {
available_modules: available_modules
.with_modules(modules)
.to_resolved()
.await?,
},
Expand Down
101 changes: 101 additions & 0 deletions turbopack/crates/turbopack-core/src/chunk/available_modules.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
use anyhow::Result;
use serde::{Deserialize, Serialize};
use turbo_tasks::{
debug::ValueDebugFormat, trace::TraceRawVcs, FxIndexMap, NonLocalValue, ResolvedVc,
TryFlatJoinIterExt, TryJoinIterExt, ValueToString, Vc,
};
use turbo_tasks_hash::Xxh3Hash64Hasher;

use super::ChunkableModule;
use crate::module::Module;

#[derive(
PartialEq, Eq, TraceRawVcs, Copy, Clone, Serialize, Deserialize, ValueDebugFormat, NonLocalValue,
)]
pub struct AvailableModulesInfo {
pub is_async: bool,
}

#[turbo_tasks::value(transparent)]
pub struct OptionAvailableModulesInfo(Option<AvailableModulesInfo>);

#[turbo_tasks::value(transparent)]
pub struct AvailableModuleInfoMap(
FxIndexMap<ResolvedVc<Box<dyn ChunkableModule>>, AvailableModulesInfo>,
);

/// Allows to gather information about which assets are already available.
/// Adding more roots will form a linked list like structure to allow caching
/// `include` queries.
#[turbo_tasks::value]
pub struct AvailableModules {
parent: Option<ResolvedVc<AvailableModules>>,
modules: ResolvedVc<AvailableModuleInfoMap>,
}

#[turbo_tasks::value_impl]
impl AvailableModules {
#[turbo_tasks::function]
pub fn new(modules: ResolvedVc<AvailableModuleInfoMap>) -> Vc<Self> {
AvailableModules {
parent: None,
modules,
}
.cell()
}

#[turbo_tasks::function]
pub async fn with_modules(
self: ResolvedVc<Self>,
modules: ResolvedVc<AvailableModuleInfoMap>,
) -> Result<Vc<Self>> {
let modules = modules
.await?
.into_iter()
.map(|(&module, &info)| async move {
Ok(self.get(*module).await?.is_none().then_some((module, info)))
})
.try_flat_join()
.await?;
Ok(AvailableModules {
parent: Some(self),
modules: ResolvedVc::cell(modules.into_iter().collect()),
}
.cell())
}

#[turbo_tasks::function]
pub async fn hash(&self) -> Result<Vc<u64>> {
let mut hasher = Xxh3Hash64Hasher::new();
if let Some(parent) = self.parent {
hasher.write_value(parent.hash().await?);
} else {
hasher.write_value(0u64);
}
let item_idents = self
.modules
.await?
.iter()
.map(|(&module, _)| module.ident().to_string())
.try_join()
.await?;
for ident in item_idents {
hasher.write_value(ident);
}
Ok(Vc::cell(hasher.finish()))
}

#[turbo_tasks::function]
pub async fn get(
&self,
module: ResolvedVc<Box<dyn ChunkableModule>>,
) -> Result<Vc<OptionAvailableModulesInfo>> {
if let Some(&info) = self.modules.await?.get(&module) {
return Ok(Vc::cell(Some(info)));
};
if let Some(parent) = self.parent {
return Ok(parent.get(*module));
}
Ok(Vc::cell(None))
}
}
Loading

0 comments on commit 4ef926b

Please sign in to comment.