Skip to content

Commit

Permalink
allow to pass available chunk items when creating a chunk group (verc…
Browse files Browse the repository at this point in the history
…el/turborepo#6988)

### Description

This allows to create a chunk group based on another chunk group (which
skips all available modules at this point)

Similar to `webpack` `dependOn`.


Closes PACK-2229
  • Loading branch information
sokra authored Jan 17, 2024
1 parent 55d3cc1 commit a38e262
Show file tree
Hide file tree
Showing 13 changed files with 289 additions and 120 deletions.
45 changes: 34 additions & 11 deletions crates/turbopack-build/src/chunking_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,13 @@ use turbopack_core::{
chunk::{
availability_info::AvailabilityInfo,
chunk_group::{make_chunk_group, MakeChunkGroupResult},
Chunk, ChunkItem, ChunkableModule, ChunkingContext, EvaluatableAssets, ModuleId,
Chunk, ChunkGroupResult, ChunkItem, ChunkableModule, ChunkingContext, EvaluatableAssets,
ModuleId,
},
environment::Environment,
ident::AssetIdent,
module::Module,
output::{OutputAsset, OutputAssets},
output::OutputAsset,
};
use turbopack_ecmascript::{
chunk::{EcmascriptChunk, EcmascriptChunkPlaceable, EcmascriptChunkingContext},
Expand Down Expand Up @@ -141,6 +142,12 @@ impl BuildChunkingContext {
}
}

#[turbo_tasks::value]
pub struct EntryChunkGroupResult {
pub asset: Vc<Box<dyn OutputAsset>>,
pub availability_info: AvailabilityInfo,
}

#[turbo_tasks::value_impl]
impl BuildChunkingContext {
#[turbo_tasks::function]
Expand All @@ -163,10 +170,14 @@ impl BuildChunkingContext {
path: Vc<FileSystemPath>,
module: Vc<Box<dyn EcmascriptChunkPlaceable>>,
evaluatable_assets: Vc<EvaluatableAssets>,
) -> Result<Vc<Box<dyn OutputAsset>>> {
let availability_info = AvailabilityInfo::Root;
availability_info: Value<AvailabilityInfo>,
) -> Result<Vc<EntryChunkGroupResult>> {
let availability_info = availability_info.into_value();

let MakeChunkGroupResult { chunks } = make_chunk_group(
let MakeChunkGroupResult {
chunks,
availability_info,
} = make_chunk_group(
Vc::upcast(self),
once(Vc::upcast(module)).chain(
evaluatable_assets
Expand All @@ -191,7 +202,11 @@ impl BuildChunkingContext {
module,
));

Ok(asset)
Ok(EntryChunkGroupResult {
asset,
availability_info,
}
.cell())
}

#[turbo_tasks::function]
Expand Down Expand Up @@ -312,10 +327,13 @@ impl ChunkingContext for BuildChunkingContext {
self: Vc<Self>,
module: Vc<Box<dyn ChunkableModule>>,
availability_info: Value<AvailabilityInfo>,
) -> Result<Vc<OutputAssets>> {
) -> Result<Vc<ChunkGroupResult>> {
let span = tracing::info_span!("chunking", module = *module.ident().to_string().await?);
async move {
let MakeChunkGroupResult { chunks } = make_chunk_group(
let MakeChunkGroupResult {
chunks,
availability_info,
} = make_chunk_group(
Vc::upcast(self),
[Vc::upcast(module)],
availability_info.into_value(),
Expand All @@ -332,18 +350,23 @@ impl ChunkingContext for BuildChunkingContext {
*asset = asset.resolve().await?;
}

Ok(Vc::cell(assets))
Ok(ChunkGroupResult {
assets: Vc::cell(assets),
availability_info,
}
.cell())
}
.instrument(span)
.await
}

#[turbo_tasks::function]
async fn evaluated_chunk_group(
fn evaluated_chunk_group(
self: Vc<Self>,
_ident: Vc<AssetIdent>,
_evaluatable_assets: Vc<EvaluatableAssets>,
) -> Result<Vc<OutputAssets>> {
_availability_info: Value<AvailabilityInfo>,
) -> Result<Vc<ChunkGroupResult>> {
// TODO(alexkirsz) This method should be part of a separate trait that is
// only implemented for client/edge runtimes.
bail!("the build chunking context does not support evaluated chunk groups")
Expand Down
4 changes: 3 additions & 1 deletion crates/turbopack-build/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
pub(crate) mod chunking_context;
pub(crate) mod ecmascript;

pub use chunking_context::{BuildChunkingContext, BuildChunkingContextBuilder, MinifyType};
pub use chunking_context::{
BuildChunkingContext, BuildChunkingContextBuilder, EntryChunkGroupResult, MinifyType,
};

pub fn register() {
turbo_tasks::register();
Expand Down
49 changes: 27 additions & 22 deletions crates/turbopack-cli/src/build/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ use turbopack_build::{BuildChunkingContext, MinifyType};
use turbopack_cli_utils::issue::{ConsoleUi, LogOptions};
use turbopack_core::{
asset::Asset,
chunk::{ChunkableModule, ChunkingContextExt, EvaluatableAssets},
chunk::{
availability_info::AvailabilityInfo, ChunkableModule, ChunkingContextExt, EvaluatableAssets,
},
environment::{BrowserEnvironment, Environment, ExecutionEnvironment},
issue::{handle_issues, IssueReporter, IssueSeverity},
module::Module,
Expand Down Expand Up @@ -245,31 +247,34 @@ async fn build_internal(
if let Some(ecmascript) =
Vc::try_resolve_downcast_type::<EcmascriptModuleAsset>(entry_module).await?
{
Vc::cell(vec![Vc::try_resolve_downcast_type::<BuildChunkingContext>(
chunking_context,
)
.await?
.unwrap()
.entry_chunk_group(
build_output_root
.join(
ecmascript
.ident()
.path()
.file_stem()
.await?
.as_deref()
.unwrap()
.to_string(),
Vc::cell(vec![
Vc::try_resolve_downcast_type::<BuildChunkingContext>(chunking_context)
.await?
.unwrap()
.entry_chunk_group(
build_output_root
.join(
ecmascript
.ident()
.path()
.file_stem()
.await?
.as_deref()
.unwrap()
.to_string(),
)
.with_extension("entry.js".to_string()),
Vc::upcast(ecmascript),
EvaluatableAssets::one(Vc::upcast(ecmascript)),
Value::new(AvailabilityInfo::Root),
)
.with_extension("entry.js".to_string()),
Vc::upcast(ecmascript),
EvaluatableAssets::one(Vc::upcast(ecmascript)),
)])
.await?
.asset,
])
} else if let Some(chunkable) =
Vc::try_resolve_sidecast::<Box<dyn ChunkableModule>>(entry_module).await?
{
chunking_context.root_chunk_group(chunkable)
chunking_context.root_chunk_group_assets(chunkable)
} else {
// TODO convert into a serve-able asset
bail!(
Expand Down
55 changes: 27 additions & 28 deletions crates/turbopack-core/src/chunk/chunk_group.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use crate::{module::Module, output::OutputAssets, reference::ModuleReference};

pub struct MakeChunkGroupResult {
pub chunks: Vec<Vc<Box<dyn Chunk>>>,
pub availability_info: AvailabilityInfo,
}

/// Creates a chunk group from a set of entries.
Expand Down Expand Up @@ -100,35 +101,30 @@ pub async fn make_chunk_group(
);
}

// Insert async chunk loaders for every referenced async module
let async_loaders = if async_modules.is_empty() {
vec![]
} else {
// Compute new [AvailabilityInfo]
let inner_availability_info = {
let map = chunk_items
.iter()
.map(|(&chunk_item, async_info)| {
(
chunk_item,
AvailableChunkItemInfo {
is_async: async_info.is_some(),
},
)
})
.collect();
let map = Vc::cell(map);
availability_info.with_chunk_items(map).await?
};

async_modules
.into_iter()
.map(|module| {
chunking_context
.async_loader_chunk_item(module, Value::new(inner_availability_info))
// Compute new [AvailabilityInfo]
let availability_info = {
let map = chunk_items
.iter()
.map(|(&chunk_item, async_info)| {
(
chunk_item,
AvailableChunkItemInfo {
is_async: async_info.is_some(),
},
)
})
.collect::<Vec<_>>()
.collect();
let map = Vc::cell(map);
availability_info.with_chunk_items(map).await?
};

// Insert async chunk loaders for every referenced async module
let async_loaders = async_modules
.into_iter()
.map(|module| {
chunking_context.async_loader_chunk_item(module, Value::new(availability_info))
})
.collect::<Vec<_>>();
let async_loader_chunk_items = async_loaders.iter().map(|&chunk_item| (chunk_item, None));

// And also add output assets referenced by async chunk loaders
Expand Down Expand Up @@ -165,7 +161,10 @@ pub async fn make_chunk_group(
// concatenate chunks
chunks.extend(async_loader_chunks);

Ok(MakeChunkGroupResult { chunks })
Ok(MakeChunkGroupResult {
chunks,
availability_info,
})
}

async fn references_to_output_assets(
Expand Down
107 changes: 103 additions & 4 deletions crates/turbopack-core/src/chunk/chunking_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ use crate::{
output::{OutputAsset, OutputAssets},
};

#[turbo_tasks::value(shared)]
pub struct ChunkGroupResult {
pub assets: Vc<OutputAssets>,
pub availability_info: AvailabilityInfo,
}

/// A context for the chunking that influences the way chunks are created
#[turbo_tasks::value_trait]
pub trait ChunkingContext {
Expand Down Expand Up @@ -62,13 +68,14 @@ pub trait ChunkingContext {
self: Vc<Self>,
module: Vc<Box<dyn ChunkableModule>>,
availability_info: Value<AvailabilityInfo>,
) -> Vc<OutputAssets>;
) -> Vc<ChunkGroupResult>;

fn evaluated_chunk_group(
self: Vc<Self>,
ident: Vc<AssetIdent>,
evaluatable_assets: Vc<EvaluatableAssets>,
) -> Vc<OutputAssets>;
availability_info: Value<AvailabilityInfo>,
) -> Vc<ChunkGroupResult>;

async fn chunk_item_id_from_ident(
self: Vc<Self>,
Expand All @@ -83,13 +90,105 @@ pub trait ChunkingContext {
}

pub trait ChunkingContextExt {
fn root_chunk_group(self: Vc<Self>, module: Vc<Box<dyn ChunkableModule>>) -> Vc<OutputAssets>
fn root_chunk_group(
self: Vc<Self>,
module: Vc<Box<dyn ChunkableModule>>,
) -> Vc<ChunkGroupResult>
where
Self: Send;

fn root_chunk_group_assets(
self: Vc<Self>,
module: Vc<Box<dyn ChunkableModule>>,
) -> Vc<OutputAssets>
where
Self: Send;

fn evaluated_chunk_group_assets(
self: Vc<Self>,
ident: Vc<AssetIdent>,
evaluatable_assets: Vc<EvaluatableAssets>,
availability_info: Value<AvailabilityInfo>,
) -> Vc<OutputAssets>
where
Self: Send;

fn chunk_group_assets(
self: Vc<Self>,
module: Vc<Box<dyn ChunkableModule>>,
availability_info: Value<AvailabilityInfo>,
) -> Vc<OutputAssets>
where
Self: Send;
}

impl<T: ChunkingContext + Send + Upcast<Box<dyn ChunkingContext>>> ChunkingContextExt for T {
fn root_chunk_group(self: Vc<Self>, module: Vc<Box<dyn ChunkableModule>>) -> Vc<OutputAssets> {
fn root_chunk_group(
self: Vc<Self>,
module: Vc<Box<dyn ChunkableModule>>,
) -> Vc<ChunkGroupResult> {
self.chunk_group(module, Value::new(AvailabilityInfo::Root))
}

fn root_chunk_group_assets(
self: Vc<Self>,
module: Vc<Box<dyn ChunkableModule>>,
) -> Vc<OutputAssets> {
root_chunk_group_assets(Vc::upcast(self), module)
}

fn evaluated_chunk_group_assets(
self: Vc<Self>,
ident: Vc<AssetIdent>,
evaluatable_assets: Vc<EvaluatableAssets>,
availability_info: Value<AvailabilityInfo>,
) -> Vc<OutputAssets> {
evaluated_chunk_group_assets(
Vc::upcast(self),
ident,
evaluatable_assets,
availability_info,
)
}

fn chunk_group_assets(
self: Vc<Self>,
module: Vc<Box<dyn ChunkableModule>>,
availability_info: Value<AvailabilityInfo>,
) -> Vc<OutputAssets> {
chunk_group_assets(Vc::upcast(self), module, availability_info)
}
}

#[turbo_tasks::function]
async fn root_chunk_group_assets(
chunking_context: Vc<Box<dyn ChunkingContext>>,
module: Vc<Box<dyn ChunkableModule>>,
) -> Result<Vc<OutputAssets>> {
Ok(chunking_context.root_chunk_group(module).await?.assets)
}

#[turbo_tasks::function]
async fn evaluated_chunk_group_assets(
chunking_context: Vc<Box<dyn ChunkingContext>>,
ident: Vc<AssetIdent>,
evaluatable_assets: Vc<EvaluatableAssets>,
availability_info: Value<AvailabilityInfo>,
) -> Result<Vc<OutputAssets>> {
Ok(chunking_context
.evaluated_chunk_group(ident, evaluatable_assets, availability_info)
.await?
.assets)
}

#[turbo_tasks::function]
async fn chunk_group_assets(
chunking_context: Vc<Box<dyn ChunkingContext>>,
module: Vc<Box<dyn ChunkableModule>>,
availability_info: Value<AvailabilityInfo>,
) -> Result<Vc<OutputAssets>> {
Ok(chunking_context
.chunk_group(module, availability_info)
.await?
.assets)
}
Loading

0 comments on commit a38e262

Please sign in to comment.