turbopack_ecmascript/manifest/
loader_item.rs1use std::io::Write as _;
2
3use anyhow::{Result, anyhow};
4use indoc::writedoc;
5use turbo_rcstr::{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
28fn modifier() -> RcStr {
29 rcstr!("loader")
30}
31
32#[turbo_tasks::value]
47pub struct ManifestLoaderChunkItem {
48 manifest: ResolvedVc<ManifestAsyncModule>,
49 module_graph: ResolvedVc<ModuleGraph>,
50 chunking_context: ResolvedVc<Box<dyn ChunkingContext>>,
51}
52
53#[turbo_tasks::value_impl]
54impl ManifestLoaderChunkItem {
55 #[turbo_tasks::function]
56 pub fn new(
57 manifest: ResolvedVc<ManifestAsyncModule>,
58 module_graph: ResolvedVc<ModuleGraph>,
59 chunking_context: ResolvedVc<Box<dyn ChunkingContext>>,
60 ) -> Vc<Self> {
61 Self::cell(ManifestLoaderChunkItem {
62 manifest,
63 module_graph,
64 chunking_context,
65 })
66 }
67
68 #[turbo_tasks::function]
69 pub async fn chunks_data(&self) -> Result<Vc<ChunksData>> {
70 let chunks = self.manifest.manifest_chunk_group().await?.assets;
71 Ok(ChunkData::from_assets(
72 self.chunking_context.output_root().owned().await?,
73 *chunks,
74 ))
75 }
76
77 #[turbo_tasks::function]
78 pub fn asset_ident_for(module: Vc<Box<dyn ChunkableModule>>) -> Vc<AssetIdent> {
79 module.ident().with_modifier(modifier())
80 }
81}
82
83#[turbo_tasks::value_impl]
84impl ChunkItem for ManifestLoaderChunkItem {
85 #[turbo_tasks::function]
86 fn asset_ident(&self) -> Vc<AssetIdent> {
87 self.manifest.module_ident().with_modifier(modifier())
88 }
89
90 #[turbo_tasks::function]
91 fn content_ident(&self) -> Vc<AssetIdent> {
92 self.manifest.content_ident().with_modifier(modifier())
93 }
94
95 #[turbo_tasks::function]
96 fn references(&self) -> Vc<OutputAssets> {
97 self.manifest.manifest_chunk_group().all_assets()
98 }
99
100 #[turbo_tasks::function]
101 fn chunking_context(&self) -> Vc<Box<dyn ChunkingContext>> {
102 *self.chunking_context
103 }
104
105 #[turbo_tasks::function]
106 async fn ty(&self) -> Result<Vc<Box<dyn ChunkType>>> {
107 Ok(Vc::upcast(
108 Vc::<EcmascriptChunkType>::default().resolve().await?,
109 ))
110 }
111
112 #[turbo_tasks::function]
113 fn module(&self) -> Vc<Box<dyn Module>> {
114 *ResolvedVc::upcast(self.manifest)
115 }
116}
117
118#[turbo_tasks::value_impl]
119impl EcmascriptChunkItem for ManifestLoaderChunkItem {
120 #[turbo_tasks::function]
121 async fn content(self: Vc<Self>) -> Result<Vc<EcmascriptChunkItemContent>> {
122 let this = &*self.await?;
123 let mut code = Vec::new();
124
125 let manifest = this.manifest.await?;
126
127 let chunks_server_data = &*self.chunks_data().await?.iter().try_join().await?;
132
133 let item_id = &*this
136 .manifest
137 .chunk_item_id(*manifest.chunking_context)
138 .await?;
139
140 let placeable =
143 ResolvedVc::try_downcast::<Box<dyn EcmascriptChunkPlaceable>>(manifest.inner)
144 .ok_or_else(|| anyhow!("asset is not placeable in ecmascript chunk"))?;
145 let dynamic_id = &*placeable.chunk_item_id(*manifest.chunking_context).await?;
146
147 writedoc!(
154 code,
155 r#"
156 {TURBOPACK_EXPORT_VALUE}((parentImport) => {{
157 return Promise.all({chunks_server_data}.map((chunk) => {TURBOPACK_LOAD}(chunk))).then(() => {{
158 return {TURBOPACK_REQUIRE}({item_id});
159 }}).then((chunks) => {{
160 return Promise.all(chunks.map((chunk) => {TURBOPACK_LOAD}(chunk)));
161 }}).then(() => {{
162 return parentImport({dynamic_id});
163 }});
164 }});
165 "#,
166 chunks_server_data = StringifyJs(
167 &chunks_server_data
168 .iter()
169 .map(|chunk_data| EcmascriptChunkData::new(chunk_data))
170 .collect::<Vec<_>>()
171 ),
172 item_id = StringifyModuleId(item_id),
173 dynamic_id = StringifyModuleId(dynamic_id),
174 )?;
175
176 Ok(EcmascriptChunkItemContent {
177 inner_code: code.into(),
178 ..Default::default()
179 }
180 .into())
181 }
182}