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, rcstr};
13use turbo_tasks::{ResolvedVc, TryJoinIterExt, 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::{OutputAssetsReference, OutputAssetsWithReferenced},
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 useful
65        Vc::cell(Default::default())
66    }
67}
68
69#[turbo_tasks::value_impl]
70impl OutputAssetsReference for EcmascriptChunk {
71    #[turbo_tasks::function]
72    async fn references(&self) -> Result<Vc<OutputAssetsWithReferenced>> {
73        let content = self.content.await?;
74        let references = content
75            .chunk_items
76            .iter()
77            .map(async |with_info| {
78                let r = with_info.references().await?;
79                Ok((
80                    r.assets.await?,
81                    r.referenced_assets.await?,
82                    r.references.await?,
83                ))
84            })
85            .try_join()
86            .await?;
87        Ok(OutputAssetsWithReferenced {
88            assets: ResolvedVc::cell(
89                references
90                    .iter()
91                    .flat_map(|(assets, _, _)| assets.into_iter().copied())
92                    .collect(),
93            ),
94            referenced_assets: ResolvedVc::cell(
95                references
96                    .iter()
97                    .flat_map(|(_, referenced_assets, _)| referenced_assets.into_iter().copied())
98                    .collect(),
99            ),
100            references: ResolvedVc::cell(
101                references
102                    .iter()
103                    .flat_map(|(_, _, references)| references.into_iter().copied())
104                    .collect(),
105            ),
106        }
107        .cell())
108    }
109}
110
111#[turbo_tasks::value_impl]
112impl Chunk for EcmascriptChunk {
113    #[turbo_tasks::function]
114    async fn ident(&self) -> Result<Vc<AssetIdent>> {
115        let chunk_items = &*self.content.included_chunk_items().await?;
116        let mut common_path = if let Some(chunk_item) = chunk_items.first() {
117            let path = chunk_item.asset_ident().path().owned().await?;
118            Some(path)
119        } else {
120            None
121        };
122
123        // The included chunk items describe the chunk uniquely
124        for &chunk_item in chunk_items.iter() {
125            if let Some(common_path_ref) = common_path.as_mut() {
126                let path = chunk_item.asset_ident().path().await?;
127                while !path.is_inside_or_equal_ref(common_path_ref) {
128                    let parent = common_path_ref.parent();
129                    if parent == *common_path_ref {
130                        common_path = None;
131                        break;
132                    }
133                    *common_path_ref = parent;
134                }
135            }
136        }
137
138        let assets = chunk_items
139            .iter()
140            .map(|&chunk_item| async move {
141                Ok((
142                    rcstr!("chunk item"),
143                    chunk_item.content_ident().to_resolved().await?,
144                ))
145            })
146            .try_join()
147            .await?;
148
149        let ident = AssetIdent {
150            path: if let Some(common_path) = common_path {
151                common_path
152            } else {
153                ServerFileSystem::new().root().owned().await?
154            },
155            query: RcStr::default(),
156            fragment: RcStr::default(),
157            assets,
158            modifiers: Vec::new(),
159            parts: Vec::new(),
160            layer: None,
161            content_type: None,
162        };
163
164        Ok(AssetIdent::new(ident))
165    }
166
167    #[turbo_tasks::function]
168    fn chunking_context(&self) -> Vc<Box<dyn ChunkingContext>> {
169        *self.chunking_context
170    }
171
172    #[turbo_tasks::function]
173    fn chunk_items(&self) -> Vc<ChunkItems> {
174        self.content.included_chunk_items()
175    }
176}
177
178#[turbo_tasks::value_impl]
179impl ValueToString for EcmascriptChunk {
180    #[turbo_tasks::function]
181    async fn to_string(self: Vc<Self>) -> Result<Vc<RcStr>> {
182        Ok(Vc::cell(
183            format!("chunk {}", self.ident().to_string().await?).into(),
184        ))
185    }
186}
187
188#[turbo_tasks::value_impl]
189impl EcmascriptChunk {
190    #[turbo_tasks::function]
191    pub fn chunk_content(&self) -> Vc<EcmascriptChunkContent> {
192        *self.content
193    }
194}
195
196#[turbo_tasks::value_impl]
197impl Introspectable for EcmascriptChunk {
198    #[turbo_tasks::function]
199    fn ty(&self) -> Vc<RcStr> {
200        Vc::cell(rcstr!("ecmascript chunk"))
201    }
202
203    #[turbo_tasks::function]
204    fn title(self: Vc<Self>) -> Vc<RcStr> {
205        self.ident().to_string()
206    }
207
208    #[turbo_tasks::function]
209    async fn details(self: Vc<Self>) -> Result<Vc<RcStr>> {
210        let mut details = String::new();
211        let this = self.await?;
212        details += "Chunk items:\n\n";
213        for chunk_item in this.content.included_chunk_items().await? {
214            writeln!(details, "- {}", chunk_item.asset_ident().to_string().await?)?;
215        }
216        Ok(Vc::cell(details.into()))
217    }
218
219    #[turbo_tasks::function]
220    async fn children(self: Vc<Self>) -> Result<Vc<IntrospectableChildren>> {
221        let mut children = children_from_output_assets(self.references())
222            .owned()
223            .await?;
224        for chunk_item in self.await?.content.included_chunk_items().await? {
225            children.insert((
226                rcstr!("module"),
227                IntrospectableModule::new(chunk_item.module())
228                    .to_resolved()
229                    .await?,
230            ));
231        }
232        Ok(Vc::cell(children))
233    }
234}