Skip to main content

turbopack_browser/ecmascript/
chunk.rs

1use anyhow::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/// Development Ecmascript chunk.
19#[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    /// Creates a new [`Vc<EcmascriptDevChunk>`].
30    #[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 ident_for_path(&self) -> Result<Vc<AssetIdent>> {
55        Ok(self
56            .chunk
57            .ident()
58            .owned()
59            .await?
60            .with_modifier(rcstr!("ecmascript dev chunk"))
61            .into_vc())
62    }
63}
64
65#[turbo_tasks::value_impl]
66impl OutputChunk for EcmascriptBrowserChunk {
67    #[turbo_tasks::function]
68    async fn runtime_info(&self) -> Result<Vc<OutputChunkRuntimeInfo>> {
69        Ok(OutputChunkRuntimeInfo {
70            included_ids: Some(self.chunk.entry_ids().to_resolved().await?),
71            ..Default::default()
72        }
73        .cell())
74    }
75}
76
77#[turbo_tasks::value_impl]
78impl EcmascriptBrowserChunk {
79    #[turbo_tasks::function]
80    async fn own_content(self: Vc<Self>) -> Result<Vc<EcmascriptBrowserChunkContent>> {
81        let this = self.await?;
82        Ok(EcmascriptBrowserChunkContent::new(
83            *this.chunking_context,
84            self,
85            this.chunk.chunk_content(),
86            self.source_map(),
87        ))
88    }
89
90    #[turbo_tasks::function]
91    pub fn chunk(&self) -> Result<Vc<Box<dyn Chunk>>> {
92        Ok(Vc::upcast(*self.chunk))
93    }
94}
95
96#[turbo_tasks::value_impl]
97impl OutputAssetsReference for EcmascriptBrowserChunk {
98    #[turbo_tasks::function]
99    async fn references(self: Vc<Self>) -> Result<Vc<OutputAssetsWithReferenced>> {
100        let this = self.await?;
101        let chunk_references = this.chunk.references().await?;
102        let include_source_map = *this
103            .chunking_context
104            .reference_chunk_source_maps(Vc::upcast(self))
105            .await?;
106        let ref_assets = chunk_references.assets.await?;
107        let mut assets =
108            Vec::with_capacity(ref_assets.len() + if include_source_map { 1 } else { 0 });
109
110        assets.extend(ref_assets.iter().copied());
111
112        if include_source_map {
113            assets.push(ResolvedVc::upcast(self.source_map().to_resolved().await?));
114        }
115
116        Ok(OutputAssetsWithReferenced {
117            assets: ResolvedVc::cell(assets),
118            referenced_assets: chunk_references.referenced_assets,
119            references: chunk_references.references,
120        }
121        .cell())
122    }
123}
124
125#[turbo_tasks::value_impl]
126impl OutputAsset for EcmascriptBrowserChunk {
127    #[turbo_tasks::function]
128    async fn path(self: Vc<Self>) -> Result<Vc<FileSystemPath>> {
129        let this = self.await?;
130        let ident = this.ident_for_path().await?;
131        Ok(this
132            .chunking_context
133            .chunk_path(Some(Vc::upcast(self)), ident, None, rcstr!(".js")))
134    }
135}
136
137#[turbo_tasks::value_impl]
138impl Asset for EcmascriptBrowserChunk {
139    #[turbo_tasks::function]
140    fn content(self: Vc<Self>) -> Vc<AssetContent> {
141        self.own_content().content()
142    }
143
144    #[turbo_tasks::function]
145    fn versioned_content(self: Vc<Self>) -> Vc<Box<dyn VersionedContent>> {
146        Vc::upcast(self.own_content())
147    }
148}
149
150#[turbo_tasks::value_impl]
151impl GenerateSourceMap for EcmascriptBrowserChunk {
152    #[turbo_tasks::function]
153    fn generate_source_map(self: Vc<Self>) -> Vc<FileContent> {
154        self.own_content().generate_source_map()
155    }
156
157    #[turbo_tasks::function]
158    fn by_section(self: Vc<Self>, section: RcStr) -> Vc<FileContent> {
159        self.own_content().by_section(section)
160    }
161}
162
163#[turbo_tasks::value_impl]
164impl Introspectable for EcmascriptBrowserChunk {
165    #[turbo_tasks::function]
166    fn ty(&self) -> Vc<RcStr> {
167        Vc::cell(rcstr!("dev ecmascript chunk"))
168    }
169
170    #[turbo_tasks::function]
171    fn title(self: Vc<Self>) -> Vc<RcStr> {
172        self.path().to_string()
173    }
174
175    #[turbo_tasks::function]
176    fn details(&self) -> Vc<RcStr> {
177        Vc::cell(rcstr!("generates a development ecmascript chunk"))
178    }
179
180    #[turbo_tasks::function]
181    fn children(&self) -> Result<Vc<IntrospectableChildren>> {
182        let mut children = FxIndexSet::default();
183        let chunk = ResolvedVc::upcast::<Box<dyn Introspectable>>(self.chunk);
184        children.insert((rcstr!("chunk"), chunk));
185        Ok(Vc::cell(children))
186    }
187}