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 && *self.own_content().has_source_map().await?;
129 let ref_assets = chunk_references.assets.await?;
130 let mut assets =
131 Vec::with_capacity(ref_assets.len() + if include_source_map { 1 } else { 0 });
132
133 assets.extend(ref_assets.iter().copied());
134
135 if include_source_map {
136 assets.push(ResolvedVc::upcast(self.source_map().to_resolved().await?));
137 }
138
139 let component_assets = this.component_chunk_assets().await?;
143 let referenced_assets = if component_assets.is_empty() {
144 chunk_references.referenced_assets
145 } else {
146 let mut referenced: Vec<_> = chunk_references
147 .referenced_assets
148 .await?
149 .iter()
150 .copied()
151 .collect();
152 referenced.extend(component_assets);
153 ResolvedVc::cell(referenced)
154 };
155
156 Ok(OutputAssetsWithReferenced {
157 assets: ResolvedVc::cell(assets),
158 referenced_assets,
159 references: chunk_references.references,
160 }
161 .cell())
162 }
163}
164
165#[turbo_tasks::value_impl]
166impl OutputAsset for EcmascriptBrowserChunk {
167 #[turbo_tasks::function]
168 async fn path(self: Vc<Self>) -> Result<Vc<FileSystemPath>> {
169 let this = self.await?;
170 let ident = this.ident_for_path().await?;
171 Ok(this
172 .chunking_context
173 .chunk_path(Some(Vc::upcast(self)), ident, None, rcstr!(".js")))
174 }
175}
176
177#[turbo_tasks::value_impl]
178impl Asset for EcmascriptBrowserChunk {
179 #[turbo_tasks::function]
180 fn content(self: Vc<Self>) -> Vc<AssetContent> {
181 self.own_content().content()
182 }
183
184 #[turbo_tasks::function]
185 fn versioned_content(self: Vc<Self>) -> Vc<Box<dyn VersionedContent>> {
186 Vc::upcast(self.own_content())
187 }
188}
189
190#[turbo_tasks::value_impl]
191impl GenerateSourceMap for EcmascriptBrowserChunk {
192 #[turbo_tasks::function]
193 fn generate_source_map(self: Vc<Self>) -> Vc<FileContent> {
194 self.own_content().generate_source_map()
195 }
196
197 #[turbo_tasks::function]
198 fn by_section(self: Vc<Self>, section: RcStr) -> Vc<FileContent> {
199 self.own_content().by_section(section)
200 }
201}
202
203#[turbo_tasks::value_impl]
204impl Introspectable for EcmascriptBrowserChunk {
205 #[turbo_tasks::function]
206 fn ty(&self) -> Vc<RcStr> {
207 Vc::cell(rcstr!("dev ecmascript chunk"))
208 }
209
210 #[turbo_tasks::function]
211 fn title(self: Vc<Self>) -> Vc<RcStr> {
212 self.path().to_string()
213 }
214
215 #[turbo_tasks::function]
216 fn details(&self) -> Vc<RcStr> {
217 Vc::cell(rcstr!("generates a development ecmascript chunk"))
218 }
219
220 #[turbo_tasks::function]
221 fn children(&self) -> Result<Vc<IntrospectableChildren>> {
222 let mut children = FxIndexSet::default();
223 let chunk = ResolvedVc::upcast::<Box<dyn Introspectable>>(self.chunk);
224 children.insert((rcstr!("chunk"), chunk));
225 Ok(Vc::cell(children))
226 }
227}