Skip to main content

turbopack_ecmascript/chunk/
mod.rs

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