Skip to main content

turbopack_ecmascript/chunk/
content_entry.rs

1use anyhow::Result;
2use either::Either;
3use turbo_tasks::{FxIndexMap, ResolvedVc, TryFlatJoinIterExt, TryJoinIterExt, Vc};
4use turbopack_core::{
5    chunk::{AsyncModuleInfo, ChunkItemExt, ModuleId},
6    code_builder::Code,
7};
8
9use crate::chunk::{
10    EcmascriptChunkContent, EcmascriptChunkItem, EcmascriptChunkItemExt,
11    EcmascriptChunkItemOrBatchWithAsyncInfo, EcmascriptChunkItemWithAsyncInfo,
12};
13
14/// A chunk item's content entry.
15///
16/// Instead of storing the [`Vc<Box<dyn EcmascriptChunkItem>>`] itself from
17/// which `code` and `hash` are derived, we store `Vc`s directly. This avoids
18/// creating tasks in a hot loop when iterating over thousands of entries when
19/// computing updates.
20#[turbo_tasks::value]
21#[derive(Debug)]
22pub struct EcmascriptChunkContentEntry {
23    pub code: ResolvedVc<Code>,
24    pub hash: ResolvedVc<u64>,
25}
26
27impl EcmascriptChunkContentEntry {
28    pub async fn new(
29        chunk_item: ResolvedVc<Box<dyn EcmascriptChunkItem>>,
30        async_module_info: Option<Vc<AsyncModuleInfo>>,
31    ) -> Result<Self> {
32        let code = chunk_item.code(async_module_info).to_resolved().await?;
33        Ok(EcmascriptChunkContentEntry {
34            code,
35            hash: code.source_code_hash().to_resolved().await?,
36        })
37    }
38}
39
40#[turbo_tasks::value(transparent)]
41pub struct EcmascriptChunkContentEntries(
42    #[bincode(with = "turbo_bincode::indexmap")] FxIndexMap<ModuleId, EcmascriptChunkContentEntry>,
43);
44
45#[turbo_tasks::value_impl]
46impl EcmascriptChunkContentEntries {
47    #[turbo_tasks::function]
48    pub async fn new(
49        chunk_content: Vc<EcmascriptChunkContent>,
50    ) -> Result<Vc<EcmascriptChunkContentEntries>> {
51        let chunk_content = chunk_content.await?;
52
53        let entries: FxIndexMap<_, _> = chunk_content
54            .chunk_items
55            .iter()
56            .map(async |item| {
57                Ok(match item {
58                    &EcmascriptChunkItemOrBatchWithAsyncInfo::ChunkItem(
59                        EcmascriptChunkItemWithAsyncInfo {
60                            chunk_item,
61                            async_info,
62                        },
63                    ) => Either::Left(std::iter::once((
64                        chunk_item.id().await?,
65                        EcmascriptChunkContentEntry::new(chunk_item, async_info.map(|info| *info))
66                            .await?,
67                    ))),
68                    EcmascriptChunkItemOrBatchWithAsyncInfo::Batch(batch) => {
69                        let batch = batch.await?;
70                        Either::Right(
71                            batch
72                                .chunk_items
73                                .iter()
74                                .map(|item| async move {
75                                    Ok((
76                                        item.chunk_item.id().await?,
77                                        EcmascriptChunkContentEntry::new(
78                                            item.chunk_item,
79                                            item.async_info.map(|info| *info),
80                                        )
81                                        .await?,
82                                    ))
83                                })
84                                .try_join()
85                                .await?
86                                .into_iter(),
87                        )
88                    }
89                })
90            })
91            .try_flat_join()
92            .await?
93            .into_iter()
94            .collect();
95
96        Ok(Vc::cell(entries))
97    }
98}