turbopack_ecmascript/chunk/
mod.rs

1pub(crate) mod batch;
2pub(crate) mod chunk_type;
3pub(crate) mod code_and_ids;
4pub(crate) mod content;
5pub(crate) mod data;
6pub(crate) mod item;
7pub(crate) mod placeable;
8
9use std::fmt::Write;
10
11use anyhow::Result;
12use turbo_rcstr::RcStr;
13use turbo_tasks::{ResolvedVc, TryFlatJoinIterExt, TryJoinIterExt, Value, ValueToString, Vc};
14use turbo_tasks_fs::FileSystem;
15use turbopack_core::{
16    chunk::{Chunk, ChunkItem, ChunkItems, ChunkingContext, ModuleIds},
17    ident::AssetIdent,
18    introspect::{
19        Introspectable, IntrospectableChildren, module::IntrospectableModule,
20        utils::children_from_output_assets,
21    },
22    output::{OutputAsset, OutputAssets},
23    server_fs::ServerFileSystem,
24};
25
26pub use self::{
27    batch::{
28        EcmascriptChunkBatchWithAsyncInfo, EcmascriptChunkItemBatchGroup,
29        EcmascriptChunkItemOrBatchWithAsyncInfo,
30    },
31    chunk_type::EcmascriptChunkType,
32    code_and_ids::{BatchGroupCodeAndIds, CodeAndIds, batch_group_code_and_ids, item_code_and_ids},
33    content::EcmascriptChunkContent,
34    data::EcmascriptChunkData,
35    item::{
36        EcmascriptChunkItem, EcmascriptChunkItemContent, EcmascriptChunkItemExt,
37        EcmascriptChunkItemOptions, EcmascriptChunkItemWithAsyncInfo,
38    },
39    placeable::{EcmascriptChunkPlaceable, EcmascriptExports},
40};
41
42#[turbo_tasks::value]
43pub struct EcmascriptChunk {
44    pub chunking_context: ResolvedVc<Box<dyn ChunkingContext>>,
45    pub content: ResolvedVc<EcmascriptChunkContent>,
46}
47
48#[turbo_tasks::value_impl]
49impl EcmascriptChunk {
50    #[turbo_tasks::function]
51    pub fn new(
52        chunking_context: ResolvedVc<Box<dyn ChunkingContext>>,
53        content: ResolvedVc<EcmascriptChunkContent>,
54    ) -> Vc<Self> {
55        EcmascriptChunk {
56            chunking_context,
57            content,
58        }
59        .cell()
60    }
61
62    #[turbo_tasks::function]
63    pub fn entry_ids(self: Vc<Self>) -> Vc<ModuleIds> {
64        // TODO return something usefull
65        Vc::cell(Default::default())
66    }
67}
68
69#[turbo_tasks::function]
70fn chunk_item_key() -> Vc<RcStr> {
71    Vc::cell("chunk item".into())
72}
73
74#[turbo_tasks::function]
75fn availability_root_key() -> Vc<RcStr> {
76    Vc::cell("current_availability_root".into())
77}
78
79#[turbo_tasks::value_impl]
80impl Chunk for EcmascriptChunk {
81    #[turbo_tasks::function]
82    async fn ident(&self) -> Result<Vc<AssetIdent>> {
83        let chunk_items = &*self.content.included_chunk_items().await?;
84        let mut common_path = if let Some(chunk_item) = chunk_items.first() {
85            let path = chunk_item.asset_ident().path().to_resolved().await?;
86            Some((path, path.await?))
87        } else {
88            None
89        };
90
91        // The included chunk items describe the chunk uniquely
92        for &chunk_item in chunk_items.iter() {
93            if let Some((common_path_vc, common_path_ref)) = common_path.as_mut() {
94                let path = chunk_item.asset_ident().path().await?;
95                while !path.is_inside_or_equal_ref(common_path_ref) {
96                    let parent = common_path_vc.parent().to_resolved().await?;
97                    if parent == *common_path_vc {
98                        common_path = None;
99                        break;
100                    }
101                    *common_path_vc = parent;
102                    *common_path_ref = (*common_path_vc).await?;
103                }
104            }
105        }
106
107        let chunk_item_key = chunk_item_key().to_resolved().await?;
108        let assets = chunk_items
109            .iter()
110            .map(|&chunk_item| async move {
111                Ok((
112                    chunk_item_key,
113                    chunk_item.content_ident().to_resolved().await?,
114                ))
115            })
116            .try_join()
117            .await?;
118
119        let ident = AssetIdent {
120            path: if let Some((common_path, _)) = common_path {
121                common_path
122            } else {
123                ServerFileSystem::new().root().to_resolved().await?
124            },
125            query: ResolvedVc::cell(RcStr::default()),
126            fragment: None,
127            assets,
128            modifiers: Vec::new(),
129            parts: Vec::new(),
130            layer: None,
131            content_type: None,
132        };
133
134        Ok(AssetIdent::new(Value::new(ident)))
135    }
136
137    #[turbo_tasks::function]
138    fn chunking_context(&self) -> Vc<Box<dyn ChunkingContext>> {
139        *ResolvedVc::upcast(self.chunking_context)
140    }
141
142    #[turbo_tasks::function]
143    async fn references(&self) -> Result<Vc<OutputAssets>> {
144        let content = self.content.await?;
145        let mut referenced_output_assets: Vec<ResolvedVc<Box<dyn OutputAsset>>> = content
146            .chunk_items
147            .iter()
148            .map(async |with_info| Ok(with_info.references().await?.into_iter().copied()))
149            .try_flat_join()
150            .await?;
151        referenced_output_assets.extend(content.referenced_output_assets.iter().copied());
152        Ok(Vc::cell(referenced_output_assets))
153    }
154
155    #[turbo_tasks::function]
156    async fn chunk_items(&self) -> Vc<ChunkItems> {
157        self.content.included_chunk_items()
158    }
159}
160
161#[turbo_tasks::value_impl]
162impl ValueToString for EcmascriptChunk {
163    #[turbo_tasks::function]
164    async fn to_string(self: Vc<Self>) -> Result<Vc<RcStr>> {
165        Ok(Vc::cell(
166            format!("chunk {}", self.ident().to_string().await?).into(),
167        ))
168    }
169}
170
171#[turbo_tasks::value_impl]
172impl EcmascriptChunk {
173    #[turbo_tasks::function]
174    pub fn chunk_content(&self) -> Vc<EcmascriptChunkContent> {
175        *self.content
176    }
177}
178
179#[turbo_tasks::function]
180fn introspectable_type() -> Vc<RcStr> {
181    Vc::cell("ecmascript chunk".into())
182}
183
184#[turbo_tasks::function]
185fn chunk_item_module_key() -> Vc<RcStr> {
186    Vc::cell("module".into())
187}
188
189#[turbo_tasks::value_impl]
190impl Introspectable for EcmascriptChunk {
191    #[turbo_tasks::function]
192    fn ty(&self) -> Vc<RcStr> {
193        introspectable_type()
194    }
195
196    #[turbo_tasks::function]
197    fn title(self: Vc<Self>) -> Vc<RcStr> {
198        self.ident().to_string()
199    }
200
201    #[turbo_tasks::function]
202    async fn details(self: Vc<Self>) -> Result<Vc<RcStr>> {
203        let mut details = String::new();
204        let this = self.await?;
205        details += "Chunk items:\n\n";
206        for chunk_item in this.content.included_chunk_items().await? {
207            writeln!(details, "- {}", chunk_item.asset_ident().to_string().await?)?;
208        }
209        Ok(Vc::cell(details.into()))
210    }
211
212    #[turbo_tasks::function]
213    async fn children(self: Vc<Self>) -> Result<Vc<IntrospectableChildren>> {
214        let mut children = children_from_output_assets(self.references())
215            .owned()
216            .await?;
217        let chunk_item_module_key = chunk_item_module_key().to_resolved().await?;
218        for chunk_item in self.await?.content.included_chunk_items().await? {
219            children.insert((
220                chunk_item_module_key,
221                IntrospectableModule::new(chunk_item.module())
222                    .to_resolved()
223                    .await?,
224            ));
225        }
226        Ok(Vc::cell(children))
227    }
228}