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