turbopack_ecmascript/chunk/
mod.rs1pub(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 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 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}