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