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
23 changes: 11 additions & 12 deletions turbopack/crates/turbopack-browser/src/chunking_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -546,26 +546,26 @@ impl ChunkingContext for BrowserChunkingContext {
content_hashing: _,
} = &*self.chunk_path_info().await?;

// Await ident once and reuse it
let ident_ref = ident.await?;
let output_name = ident
.output_name(root_path.clone(), prefix, extension.clone())
.owned()
.await?;

let mut filename = match asset {
Some(asset) => {
let ident = ident.await?;

let mut evaluate = false;
let mut dev_chunk_list = false;
ident.modifiers.iter().for_each(|m| {
ident_ref.modifiers.iter().for_each(|m| {
if m.contains("evaluate") {
evaluate = true;
}
if m.contains("dev chunk list") {
dev_chunk_list = true;
}
});
let query = QString::from(ident.query.as_str());
let query = QString::from(ident_ref.query.as_str());
let name = if dev_chunk_list {
output_name.as_str()
} else {
Expand All @@ -579,8 +579,8 @@ impl ChunkingContext for BrowserChunkingContext {
};

match filename_template {
Some(filename) => {
let mut filename = filename.to_string();
Some(filename_template_str) => {
let mut filename = filename_template_str.to_string();

if match_name_placeholder(&filename) {
filename = replace_name_placeholder(&filename, name);
Expand All @@ -590,17 +590,15 @@ impl ChunkingContext for BrowserChunkingContext {
let content = asset.content().await?;
if let AssetContent::File(file) = &*content {
let content_hash = hash_xxh3_hash64(&file.await?);
filename = replace_content_hash_placeholder(
&filename,
&format!("{content_hash:016x}"),
);
let hash_str = format!("{content_hash:016x}");
filename = replace_content_hash_placeholder(&filename, &hash_str);
} else {
bail!(
"chunk_path requires an asset with file content when content \
hashing is enabled"
);
}
};
}

filename
}
Expand Down Expand Up @@ -808,9 +806,10 @@ impl ChunkingContext for BrowserChunkingContext {
module_graph: Vc<ModuleGraph>,
input_availability_info: AvailabilityInfo,
) -> Result<Vc<ChunkGroupResult>> {
let ident_str = ident.to_string().await?;
let span = tracing::info_span!(
"chunking",
name = display(ident.to_string().await?),
name = display(ident_str.clone()),
chunking_type = "evaluated",
);
async move {
Expand Down
38 changes: 32 additions & 6 deletions turbopack/crates/turbopack-ecmascript/src/chunk/chunk_type.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use anyhow::{Result, bail};
use turbo_rcstr::{RcStr, rcstr};
use turbo_tasks::{ResolvedVc, TryJoinIterExt, ValueDefault, ValueToString, Vc};
use turbo_tasks::{ReadRef, ResolvedVc, TryJoinIterExt, ValueDefault, ValueToString, Vc};
use turbopack_core::chunk::{
AsyncModuleInfo, Chunk, ChunkItem, ChunkItemBatchGroup, ChunkItemOrBatchWithAsyncModuleInfo,
ChunkType, ChunkingContext, round_chunk_item_size,
Expand Down Expand Up @@ -35,12 +35,38 @@ impl ChunkType for EcmascriptChunkType {
chunk_items: Vec<ChunkItemOrBatchWithAsyncModuleInfo>,
batch_groups: Vec<ResolvedVc<ChunkItemBatchGroup>>,
) -> Result<Vc<Box<dyn Chunk>>> {
// Convert and sort chunk items by their content identifier for deterministic output
let mut chunk_items_with_ident: Vec<_> = chunk_items
.iter()
.map(|item| async move {
let ecma_item =
EcmascriptChunkItemOrBatchWithAsyncInfo::from_chunk_item_or_batch(item).await?;
let ident_str = match &ecma_item {
EcmascriptChunkItemOrBatchWithAsyncInfo::ChunkItem(item) => {
item.chunk_item.content_ident().to_string().await?
}
EcmascriptChunkItemOrBatchWithAsyncInfo::Batch(batch) => {
let batch_ref = batch.await?;
if let Some(first_item) = batch_ref.chunk_items.first() {
first_item.chunk_item.content_ident().to_string().await?
} else {
ReadRef::new_owned(RcStr::default())
}
}
};
Ok((ident_str, ecma_item))
})
.try_join()
.await?;

// Sort by identifier string for deterministic ordering
chunk_items_with_ident.sort_by(|a, b| a.0.cmp(&b.0));

let content = EcmascriptChunkContent {
chunk_items: chunk_items
.iter()
.map(EcmascriptChunkItemOrBatchWithAsyncInfo::from_chunk_item_or_batch)
.try_join()
.await?,
chunk_items: chunk_items_with_ident
.into_iter()
.map(|(_, item)| item)
.collect(),
batch_groups: batch_groups
.into_iter()
.map(|batch_group| {
Expand Down
18 changes: 13 additions & 5 deletions turbopack/crates/turbopack-ecmascript/src/chunk/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,17 +135,25 @@ impl Chunk for EcmascriptChunk {
}
}

let assets = chunk_items
// Sort chunk items by their content identifier for deterministic asset ordering
let mut assets_with_sort_key: Vec<_> = chunk_items
Copy link

Choose a reason for hiding this comment

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

感觉可以提到上游了

.iter()
.map(|&chunk_item| async move {
Ok((
rcstr!("chunk item"),
chunk_item.content_ident().to_resolved().await?,
))
let ident = chunk_item.content_ident().to_resolved().await?;
let ident_str = ident.to_string().await?;
Ok((ident, ident_str))
})
.try_join()
.await?;

// Sort by identifier string
assets_with_sort_key.sort_by(|a, b| a.1.cmp(&b.1));

let assets: Vec<(RcStr, ResolvedVc<AssetIdent>)> = assets_with_sort_key
.into_iter()
.map(|(ident, _)| (rcstr!("chunk item"), ident))
.collect();

let ident = AssetIdent {
path: if let Some(common_path) = common_path {
common_path
Expand Down
Loading