turbopack_ecmascript/manifest/
loader_item.rs1use std::io::Write as _;
2
3use anyhow::{Result, anyhow};
4use indoc::writedoc;
5use turbo_rcstr::RcStr;
6use turbo_tasks::{ResolvedVc, TryJoinIterExt, Vc};
7use turbopack_core::{
8 chunk::{
9 ChunkData, ChunkItem, ChunkType, ChunkableModule, ChunkingContext, ChunksData,
10 ModuleChunkItemIdExt,
11 },
12 ident::AssetIdent,
13 module::Module,
14 module_graph::ModuleGraph,
15 output::OutputAssets,
16};
17
18use super::chunk_asset::ManifestAsyncModule;
19use crate::{
20 chunk::{
21 EcmascriptChunkItem, EcmascriptChunkItemContent, EcmascriptChunkPlaceable,
22 EcmascriptChunkType, data::EcmascriptChunkData,
23 },
24 runtime_functions::{TURBOPACK_EXPORT_VALUE, TURBOPACK_LOAD, TURBOPACK_REQUIRE},
25 utils::{StringifyJs, StringifyModuleId},
26};
27
28#[turbo_tasks::function]
29fn modifier() -> Vc<RcStr> {
30 Vc::cell("loader".into())
31}
32
33#[turbo_tasks::value]
48pub struct ManifestLoaderChunkItem {
49 manifest: ResolvedVc<ManifestAsyncModule>,
50 module_graph: ResolvedVc<ModuleGraph>,
51 chunking_context: ResolvedVc<Box<dyn ChunkingContext>>,
52}
53
54#[turbo_tasks::value_impl]
55impl ManifestLoaderChunkItem {
56 #[turbo_tasks::function]
57 pub fn new(
58 manifest: ResolvedVc<ManifestAsyncModule>,
59 module_graph: ResolvedVc<ModuleGraph>,
60 chunking_context: ResolvedVc<Box<dyn ChunkingContext>>,
61 ) -> Vc<Self> {
62 Self::cell(ManifestLoaderChunkItem {
63 manifest,
64 module_graph,
65 chunking_context,
66 })
67 }
68
69 #[turbo_tasks::function]
70 pub fn chunks_data(&self) -> Vc<ChunksData> {
71 let chunks = self.manifest.manifest_chunks();
72 ChunkData::from_assets(self.chunking_context.output_root(), chunks)
73 }
74
75 #[turbo_tasks::function]
76 pub fn asset_ident_for(module: Vc<Box<dyn ChunkableModule>>) -> Vc<AssetIdent> {
77 module.ident().with_modifier(modifier())
78 }
79}
80
81#[turbo_tasks::function]
82fn manifest_loader_chunk_reference_description() -> Vc<RcStr> {
83 Vc::cell("manifest loader chunk".into())
84}
85
86#[turbo_tasks::function]
87fn chunk_data_reference_description() -> Vc<RcStr> {
88 Vc::cell("chunk data reference".into())
89}
90
91#[turbo_tasks::value_impl]
92impl ChunkItem for ManifestLoaderChunkItem {
93 #[turbo_tasks::function]
94 fn asset_ident(&self) -> Vc<AssetIdent> {
95 self.manifest.module_ident().with_modifier(modifier())
96 }
97
98 #[turbo_tasks::function]
99 fn content_ident(&self) -> Vc<AssetIdent> {
100 self.manifest.content_ident().with_modifier(modifier())
101 }
102
103 #[turbo_tasks::function]
104 async fn references(self: Vc<Self>) -> Result<Vc<OutputAssets>> {
105 let this = self.await?;
106 let mut references = (*this.manifest.manifest_chunks().await?).clone();
107 for chunk_data in &*self.chunks_data().await? {
108 references.extend(chunk_data.references().await?);
109 }
110
111 Ok(Vc::cell(references))
112 }
113
114 #[turbo_tasks::function]
115 fn chunking_context(&self) -> Vc<Box<dyn ChunkingContext>> {
116 *ResolvedVc::upcast(self.chunking_context)
117 }
118
119 #[turbo_tasks::function]
120 async fn ty(&self) -> Result<Vc<Box<dyn ChunkType>>> {
121 Ok(Vc::upcast(
122 Vc::<EcmascriptChunkType>::default().resolve().await?,
123 ))
124 }
125
126 #[turbo_tasks::function]
127 fn module(&self) -> Vc<Box<dyn Module>> {
128 *ResolvedVc::upcast(self.manifest)
129 }
130}
131
132#[turbo_tasks::value_impl]
133impl EcmascriptChunkItem for ManifestLoaderChunkItem {
134 #[turbo_tasks::function]
135 async fn content(self: Vc<Self>) -> Result<Vc<EcmascriptChunkItemContent>> {
136 let this = &*self.await?;
137 let mut code = Vec::new();
138
139 let manifest = this.manifest.await?;
140
141 let chunks_server_data = &*self.chunks_data().await?.iter().try_join().await?;
146
147 let item_id = &*this
150 .manifest
151 .chunk_item_id(*ResolvedVc::upcast(manifest.chunking_context))
152 .await?;
153
154 let placeable =
157 ResolvedVc::try_downcast::<Box<dyn EcmascriptChunkPlaceable>>(manifest.inner)
158 .ok_or_else(|| anyhow!("asset is not placeable in ecmascript chunk"))?;
159 let dynamic_id = &*placeable
160 .chunk_item_id(*ResolvedVc::upcast(manifest.chunking_context))
161 .await?;
162
163 writedoc!(
170 code,
171 r#"
172 {TURBOPACK_EXPORT_VALUE}((parentImport) => {{
173 return Promise.all({chunks_server_data}.map((chunk) => {TURBOPACK_LOAD}(chunk))).then(() => {{
174 return {TURBOPACK_REQUIRE}({item_id});
175 }}).then((chunks) => {{
176 return Promise.all(chunks.map((chunk) => {TURBOPACK_LOAD}(chunk)));
177 }}).then(() => {{
178 return parentImport({dynamic_id});
179 }});
180 }});
181 "#,
182 chunks_server_data = StringifyJs(
183 &chunks_server_data
184 .iter()
185 .map(|chunk_data| EcmascriptChunkData::new(chunk_data))
186 .collect::<Vec<_>>()
187 ),
188 item_id = StringifyModuleId(item_id),
189 dynamic_id = StringifyModuleId(dynamic_id),
190 )?;
191
192 Ok(EcmascriptChunkItemContent {
193 inner_code: code.into(),
194 ..Default::default()
195 }
196 .into())
197 }
198}