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