turbopack_browser/ecmascript/
chunk.rs1use anyhow::{Context, Result};
2use turbo_rcstr::{RcStr, rcstr};
3use turbo_tasks::{FxIndexSet, ResolvedVc, ValueToString, Vc};
4use turbo_tasks_fs::{FileContent, FileSystemPath};
5use turbopack_core::{
6 asset::{Asset, AssetContent},
7 chunk::{Chunk, ChunkingContext, OutputChunk, OutputChunkRuntimeInfo},
8 ident::AssetIdent,
9 introspect::{Introspectable, IntrospectableChildren},
10 output::{OutputAsset, OutputAssetsReference, OutputAssetsWithReferenced},
11 source_map::{GenerateSourceMap, SourceMapAsset},
12 version::VersionedContent,
13};
14use turbopack_ecmascript::chunk::EcmascriptChunk;
15
16use crate::{BrowserChunkingContext, ecmascript::content::EcmascriptBrowserChunkContent};
17
18#[turbo_tasks::value(shared)]
20#[derive(ValueToString)]
21#[value_to_string("Ecmascript Dev Chunk")]
22pub struct EcmascriptBrowserChunk {
23 chunking_context: ResolvedVc<BrowserChunkingContext>,
24 chunk: ResolvedVc<EcmascriptChunk>,
25}
26
27#[turbo_tasks::value_impl]
28impl EcmascriptBrowserChunk {
29 #[turbo_tasks::function]
31 pub fn new(
32 chunking_context: ResolvedVc<BrowserChunkingContext>,
33 chunk: ResolvedVc<EcmascriptChunk>,
34 ) -> Vc<Self> {
35 EcmascriptBrowserChunk {
36 chunking_context,
37 chunk,
38 }
39 .cell()
40 }
41
42 #[turbo_tasks::function]
43 async fn source_map(self: Vc<Self>) -> Result<Vc<SourceMapAsset>> {
44 let this = self.await?;
45 Ok(SourceMapAsset::new(
46 Vc::upcast(*this.chunking_context),
47 this.ident_for_path().await?,
48 Vc::upcast(self),
49 ))
50 }
51}
52
53impl EcmascriptBrowserChunk {
54 async fn component_chunk_assets(&self) -> Result<Vec<ResolvedVc<Box<dyn OutputAsset>>>> {
55 let component_chunks = self.chunk.component_chunks().await?;
56 let mut assets = Vec::with_capacity(component_chunks.len());
57 for &component in component_chunks.iter() {
58 let component_chunk = ResolvedVc::try_downcast_type::<EcmascriptChunk>(component)
59 .context("merged chunk component_chunks must be ecmascript chunks")?;
60 assets.push(ResolvedVc::upcast(
61 EcmascriptBrowserChunk::new(*self.chunking_context, *component_chunk)
62 .to_resolved()
63 .await?,
64 ));
65 }
66 Ok(assets)
67 }
68
69 async fn ident_for_path(&self) -> Result<Vc<AssetIdent>> {
70 Ok(self
71 .chunk
72 .ident()
73 .owned()
74 .await?
75 .with_modifier(rcstr!("ecmascript dev chunk"))
76 .into_vc())
77 }
78}
79
80#[turbo_tasks::value_impl]
81impl OutputChunk for EcmascriptBrowserChunk {
82 #[turbo_tasks::function]
83 async fn runtime_info(&self) -> Result<Vc<OutputChunkRuntimeInfo>> {
84 let component_assets = self.component_chunk_assets().await?;
85 let module_chunks = if component_assets.is_empty() {
86 None
87 } else {
88 Some(ResolvedVc::cell(component_assets))
89 };
90 Ok(OutputChunkRuntimeInfo {
91 included_ids: Some(self.chunk.entry_ids().to_resolved().await?),
92 module_chunks,
93 ..Default::default()
94 }
95 .cell())
96 }
97}
98
99#[turbo_tasks::value_impl]
100impl EcmascriptBrowserChunk {
101 #[turbo_tasks::function]
102 pub(crate) async fn own_content(self: Vc<Self>) -> Result<Vc<EcmascriptBrowserChunkContent>> {
103 let this = self.await?;
104 Ok(EcmascriptBrowserChunkContent::new(
105 *this.chunking_context,
106 self,
107 this.chunk.chunk_content(),
108 self.source_map(),
109 ))
110 }
111
112 #[turbo_tasks::function]
113 pub fn chunk(&self) -> Result<Vc<Box<dyn Chunk>>> {
114 Ok(Vc::upcast(*self.chunk))
115 }
116}
117
118#[turbo_tasks::value_impl]
119impl OutputAssetsReference for EcmascriptBrowserChunk {
120 #[turbo_tasks::function]
121 async fn references(self: Vc<Self>) -> Result<Vc<OutputAssetsWithReferenced>> {
122 let this = self.await?;
123 let chunk_references = this.chunk.references().await?;
124 let include_source_map = *this
125 .chunking_context
126 .reference_chunk_source_maps(Vc::upcast(self))
127 .await?;
128 let ref_assets = chunk_references.assets.await?;
129 let mut assets =
130 Vec::with_capacity(ref_assets.len() + if include_source_map { 1 } else { 0 });
131
132 assets.extend(ref_assets.iter().copied());
133
134 if include_source_map {
135 assets.push(ResolvedVc::upcast(self.source_map().to_resolved().await?));
136 }
137
138 let component_assets = this.component_chunk_assets().await?;
142 let referenced_assets = if component_assets.is_empty() {
143 chunk_references.referenced_assets
144 } else {
145 let mut referenced: Vec<_> = chunk_references
146 .referenced_assets
147 .await?
148 .iter()
149 .copied()
150 .collect();
151 referenced.extend(component_assets);
152 ResolvedVc::cell(referenced)
153 };
154
155 Ok(OutputAssetsWithReferenced {
156 assets: ResolvedVc::cell(assets),
157 referenced_assets,
158 references: chunk_references.references,
159 }
160 .cell())
161 }
162}
163
164#[turbo_tasks::value_impl]
165impl OutputAsset for EcmascriptBrowserChunk {
166 #[turbo_tasks::function]
167 async fn path(self: Vc<Self>) -> Result<Vc<FileSystemPath>> {
168 let this = self.await?;
169 let ident = this.ident_for_path().await?;
170 Ok(this
171 .chunking_context
172 .chunk_path(Some(Vc::upcast(self)), ident, None, rcstr!(".js")))
173 }
174}
175
176#[turbo_tasks::value_impl]
177impl Asset for EcmascriptBrowserChunk {
178 #[turbo_tasks::function]
179 fn content(self: Vc<Self>) -> Vc<AssetContent> {
180 self.own_content().content()
181 }
182
183 #[turbo_tasks::function]
184 fn versioned_content(self: Vc<Self>) -> Vc<Box<dyn VersionedContent>> {
185 Vc::upcast(self.own_content())
186 }
187}
188
189#[turbo_tasks::value_impl]
190impl GenerateSourceMap for EcmascriptBrowserChunk {
191 #[turbo_tasks::function]
192 fn generate_source_map(self: Vc<Self>) -> Vc<FileContent> {
193 self.own_content().generate_source_map()
194 }
195
196 #[turbo_tasks::function]
197 fn by_section(self: Vc<Self>, section: RcStr) -> Vc<FileContent> {
198 self.own_content().by_section(section)
199 }
200}
201
202#[turbo_tasks::value_impl]
203impl Introspectable for EcmascriptBrowserChunk {
204 #[turbo_tasks::function]
205 fn ty(&self) -> Vc<RcStr> {
206 Vc::cell(rcstr!("dev ecmascript chunk"))
207 }
208
209 #[turbo_tasks::function]
210 fn title(self: Vc<Self>) -> Vc<RcStr> {
211 self.path().to_string()
212 }
213
214 #[turbo_tasks::function]
215 fn details(&self) -> Vc<RcStr> {
216 Vc::cell(rcstr!("generates a development ecmascript chunk"))
217 }
218
219 #[turbo_tasks::function]
220 fn children(&self) -> Result<Vc<IntrospectableChildren>> {
221 let mut children = FxIndexSet::default();
222 let chunk = ResolvedVc::upcast::<Box<dyn Introspectable>>(self.chunk);
223 children.insert((rcstr!("chunk"), chunk));
224 Ok(Vc::cell(children))
225 }
226}