turbopack_ecmascript/manifest/
chunk_asset.rs1use anyhow::Result;
2use indoc::formatdoc;
3use turbo_rcstr::{RcStr, rcstr};
4use turbo_tasks::{ResolvedVc, TryJoinIterExt, Vc};
5use turbopack_core::{
6 chunk::{
7 AsyncModuleInfo, ChunkData, ChunkableModule, ChunkingContext, ChunkingContextExt,
8 ChunksData, availability_info::AvailabilityInfo,
9 },
10 ident::AssetIdent,
11 module::{Module, ModuleSideEffects},
12 module_graph::{
13 ModuleGraph, chunk_group_info::ChunkGroup, module_batch::ChunkableModuleOrBatch,
14 },
15 output::OutputAssetsWithReferenced,
16 reference::{ModuleReferences, SingleOutputAssetReference},
17};
18
19use crate::{
20 chunk::{
21 EcmascriptChunkItemContent, EcmascriptChunkPlaceable, EcmascriptExports,
22 data::EcmascriptChunkData, ecmascript_chunk_item,
23 },
24 runtime_functions::TURBOPACK_EXPORT_VALUE,
25 utils::StringifyJs,
26};
27
28#[turbo_tasks::value(shared)]
40pub struct ManifestAsyncModule {
41 pub inner: ResolvedVc<Box<dyn ChunkableModule>>,
42 pub module_graph: ResolvedVc<ModuleGraph>,
43 pub chunking_context: ResolvedVc<Box<dyn ChunkingContext>>,
44 pub availability_info: AvailabilityInfo,
45}
46
47#[turbo_tasks::value_impl]
48impl ManifestAsyncModule {
49 #[turbo_tasks::function]
50 pub fn new(
51 module: ResolvedVc<Box<dyn ChunkableModule>>,
52 module_graph: ResolvedVc<ModuleGraph>,
53 chunking_context: ResolvedVc<Box<dyn ChunkingContext>>,
54 availability_info: AvailabilityInfo,
55 ) -> Vc<Self> {
56 Self::cell(ManifestAsyncModule {
57 inner: module,
58 module_graph,
59 chunking_context,
60 availability_info,
61 })
62 }
63
64 #[turbo_tasks::function]
65 pub(super) fn chunk_group(&self) -> Vc<OutputAssetsWithReferenced> {
66 self.chunking_context.chunk_group_assets(
67 self.inner.ident(),
68 ChunkGroup::Async(ResolvedVc::upcast(self.inner)),
69 *self.module_graph,
70 self.availability_info,
71 )
72 }
73
74 #[turbo_tasks::function]
75 pub async fn manifest_chunk_group(
76 self: ResolvedVc<Self>,
77 ) -> Result<Vc<OutputAssetsWithReferenced>> {
78 let this = self.await?;
79 if let Some(chunk_items) = this.availability_info.available_modules() {
80 let inner_module = ResolvedVc::upcast(this.inner);
81 let batches = this
82 .module_graph
83 .module_batches(this.chunking_context.batching_config())
84 .await?;
85 let module_or_batch = batches.get_entry(inner_module).await?;
86 if let Some(chunkable_module_or_batch) =
87 ChunkableModuleOrBatch::from_module_or_batch(module_or_batch)
88 && *chunk_items.get(chunkable_module_or_batch.into()).await?
89 {
90 return Ok(OutputAssetsWithReferenced {
91 assets: ResolvedVc::cell(vec![]),
92 referenced_assets: ResolvedVc::cell(vec![]),
93 references: ResolvedVc::cell(vec![]),
94 }
95 .cell());
96 }
97 }
98 Ok(this.chunking_context.chunk_group_assets(
99 self.ident(),
100 ChunkGroup::Async(ResolvedVc::upcast(self)),
101 *this.module_graph,
102 this.availability_info,
103 ))
104 }
105
106 #[turbo_tasks::function]
107 pub fn module_ident(&self) -> Vc<AssetIdent> {
108 self.inner.ident()
109 }
110
111 #[turbo_tasks::function]
112 pub async fn content_ident(&self) -> Result<Vc<AssetIdent>> {
113 let mut ident = self.inner.ident();
114 if let Some(available_modules) = self.availability_info.available_modules() {
115 ident = ident.with_modifier(available_modules.hash().await?.to_string().into());
116 }
117 Ok(ident)
118 }
119
120 #[turbo_tasks::function]
121 async fn chunks_data(self: Vc<Self>) -> Result<Vc<ChunksData>> {
122 let this = self.await?;
123 Ok(ChunkData::from_assets(
124 this.chunking_context.output_root().owned().await?,
125 *self.chunk_group().await?.assets,
126 ))
127 }
128}
129
130fn manifest_chunk_reference_description() -> RcStr {
131 rcstr!("manifest chunk")
132}
133
134#[turbo_tasks::value_impl]
135impl Module for ManifestAsyncModule {
136 #[turbo_tasks::function]
137 fn ident(&self) -> Vc<AssetIdent> {
138 self.inner
139 .ident()
140 .with_modifier(manifest_chunk_reference_description())
141 }
142
143 #[turbo_tasks::function]
144 fn source(&self) -> Vc<turbopack_core::source::OptionSource> {
145 Vc::cell(None)
146 }
147
148 #[turbo_tasks::function]
149 async fn references(self: Vc<Self>) -> Result<Vc<ModuleReferences>> {
150 let assets = self.chunk_group().expand_all_assets().await?;
151
152 Ok(Vc::cell(
153 assets
154 .into_iter()
155 .copied()
156 .map(|chunk| async move {
157 Ok(ResolvedVc::upcast(
158 SingleOutputAssetReference::new(
159 *chunk,
160 manifest_chunk_reference_description(),
161 )
162 .to_resolved()
163 .await?,
164 ))
165 })
166 .try_join()
167 .await?,
168 ))
169 }
170
171 #[turbo_tasks::function]
172 fn side_effects(self: Vc<Self>) -> Vc<ModuleSideEffects> {
173 ModuleSideEffects::SideEffectFree.cell()
174 }
175}
176
177#[turbo_tasks::value_impl]
178impl ChunkableModule for ManifestAsyncModule {
179 #[turbo_tasks::function]
180 fn as_chunk_item(
181 self: ResolvedVc<Self>,
182 module_graph: ResolvedVc<ModuleGraph>,
183 chunking_context: ResolvedVc<Box<dyn ChunkingContext>>,
184 ) -> Vc<Box<dyn turbopack_core::chunk::ChunkItem>> {
185 ecmascript_chunk_item(ResolvedVc::upcast(self), module_graph, chunking_context)
186 }
187}
188
189#[turbo_tasks::value_impl]
190impl EcmascriptChunkPlaceable for ManifestAsyncModule {
191 #[turbo_tasks::function]
192 fn get_exports(&self) -> Vc<EcmascriptExports> {
193 EcmascriptExports::Value.cell()
194 }
195
196 #[turbo_tasks::function]
197 async fn chunk_item_content(
198 self: Vc<Self>,
199 _chunking_context: Vc<Box<dyn ChunkingContext>>,
200 _module_graph: Vc<ModuleGraph>,
201 _async_module_info: Option<Vc<AsyncModuleInfo>>,
202 _estimated: bool,
203 ) -> Result<Vc<EcmascriptChunkItemContent>> {
204 let chunks_data = self.chunks_data().await?;
205 let chunks_data = chunks_data.iter().try_join().await?;
206 let chunks_data: Vec<_> = chunks_data
207 .iter()
208 .map(|chunk_data| EcmascriptChunkData::new(chunk_data))
209 .collect();
210
211 let code = formatdoc! {
212 r#"
213 {TURBOPACK_EXPORT_VALUE}({:#});
214 "#,
215 StringifyJs(&chunks_data)
216 };
217
218 Ok(EcmascriptChunkItemContent {
219 inner_code: code.into(),
220 ..Default::default()
221 }
222 .cell())
223 }
224
225 #[turbo_tasks::function]
226 fn chunk_item_content_ident(
227 self: Vc<Self>,
228 _chunking_context: Vc<Box<dyn ChunkingContext>>,
229 _module_graph: Vc<ModuleGraph>,
230 ) -> Vc<AssetIdent> {
231 self.content_ident()
232 }
233
234 #[turbo_tasks::function]
235 fn chunk_item_output_assets(
236 self: Vc<Self>,
237 _chunking_context: Vc<Box<dyn ChunkingContext>>,
238 _module_graph: Vc<ModuleGraph>,
239 ) -> Vc<OutputAssetsWithReferenced> {
240 self.chunk_group()
241 }
242}