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<u128>,
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 factory = chunk_item.code(async_module_info).await?;
33        let code = factory.code.to_code().to_resolved().await?;
34        Ok(EcmascriptChunkContentEntry {
35            code,
36            hash: code.source_code_hash().to_resolved().await?,
37        })
38    }
39}
40
41#[turbo_tasks::value(transparent)]
42pub struct EcmascriptChunkContentEntries(
43    #[bincode(with = "turbo_bincode::indexmap")] FxIndexMap<ModuleId, EcmascriptChunkContentEntry>,
44);
45
46#[turbo_tasks::value_impl]
47impl EcmascriptChunkContentEntries {
48    #[turbo_tasks::function]
49    pub async fn new(
50        chunk_content: Vc<EcmascriptChunkContent>,
51    ) -> Result<Vc<EcmascriptChunkContentEntries>> {
52        let chunk_content = chunk_content.await?;
53
54        let entries: FxIndexMap<_, _> = chunk_content
55            .chunk_items
56            .iter()
57            .map(async |item| {
58                Ok(match item {
59                    &EcmascriptChunkItemOrBatchWithAsyncInfo::ChunkItem(
60                        EcmascriptChunkItemWithAsyncInfo {
61                            chunk_item,
62                            async_info,
63                        },
64                    ) => Either::Left(std::iter::once((
65                        chunk_item.id().await?,
66                        EcmascriptChunkContentEntry::new(chunk_item, async_info.map(|info| *info))
67                            .await?,
68                    ))),
69                    EcmascriptChunkItemOrBatchWithAsyncInfo::Batch(batch) => {
70                        let batch = batch.await?;
71                        Either::Right(
72                            batch
73                                .chunk_items
74                                .iter()
75                                .map(async |item| {
76                                    Ok((
77                                        item.chunk_item.id().await?,
78                                        EcmascriptChunkContentEntry::new(
79                                            item.chunk_item,
80                                            item.async_info.map(|info| *info),
81                                        )
82                                        .await?,
83                                    ))
84                                })
85                                .try_join()
86                                .await?
87                                .into_iter(),
88                        )
89                    }
90                })
91            })
92            .try_flat_join()
93            .await?
94            .into_iter()
95            .collect();
96
97        Ok(Vc::cell(entries))
98    }
99}