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