turbopack_browser/ecmascript/
chunk.rs

1use anyhow::Result;
2use turbo_rcstr::{RcStr, rcstr};
3use turbo_tasks::{FxIndexSet, ResolvedVc, ValueToString, Vc};
4use turbo_tasks_fs::FileSystemPath;
5use turbopack_core::{
6    asset::{Asset, AssetContent},
7    chunk::{Chunk, ChunkingContext, OutputChunk, OutputChunkRuntimeInfo},
8    ident::AssetIdent,
9    introspect::{Introspectable, IntrospectableChildren},
10    output::{OutputAsset, OutputAssets},
11    source_map::{GenerateSourceMap, OptionStringifiedSourceMap, 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)]
20pub struct EcmascriptBrowserChunk {
21    chunking_context: ResolvedVc<BrowserChunkingContext>,
22    chunk: ResolvedVc<EcmascriptChunk>,
23}
24
25#[turbo_tasks::value_impl]
26impl EcmascriptBrowserChunk {
27    /// Creates a new [`Vc<EcmascriptDevChunk>`].
28    #[turbo_tasks::function]
29    pub fn new(
30        chunking_context: ResolvedVc<BrowserChunkingContext>,
31        chunk: ResolvedVc<EcmascriptChunk>,
32    ) -> Vc<Self> {
33        EcmascriptBrowserChunk {
34            chunking_context,
35            chunk,
36        }
37        .cell()
38    }
39
40    #[turbo_tasks::function]
41    async fn source_map(self: Vc<Self>) -> Result<Vc<SourceMapAsset>> {
42        let this = self.await?;
43        Ok(SourceMapAsset::new(
44            Vc::upcast(*this.chunking_context),
45            this.ident_for_path(),
46            Vc::upcast(self),
47        ))
48    }
49}
50
51impl EcmascriptBrowserChunk {
52    fn ident_for_path(&self) -> Vc<AssetIdent> {
53        self.chunk
54            .ident()
55            .with_modifier(rcstr!("ecmascript dev chunk"))
56    }
57}
58
59#[turbo_tasks::value_impl]
60impl ValueToString for EcmascriptBrowserChunk {
61    #[turbo_tasks::function]
62    fn to_string(&self) -> Vc<RcStr> {
63        Vc::cell(rcstr!("Ecmascript Dev Chunk"))
64    }
65}
66
67#[turbo_tasks::value_impl]
68impl OutputChunk for EcmascriptBrowserChunk {
69    #[turbo_tasks::function]
70    async fn runtime_info(&self) -> Result<Vc<OutputChunkRuntimeInfo>> {
71        Ok(OutputChunkRuntimeInfo {
72            included_ids: Some(self.chunk.entry_ids().to_resolved().await?),
73            ..Default::default()
74        }
75        .cell())
76    }
77}
78
79#[turbo_tasks::value_impl]
80impl EcmascriptBrowserChunk {
81    #[turbo_tasks::function]
82    async fn own_content(self: Vc<Self>) -> Result<Vc<EcmascriptBrowserChunkContent>> {
83        let this = self.await?;
84        Ok(EcmascriptBrowserChunkContent::new(
85            *this.chunking_context,
86            self,
87            this.chunk.chunk_content(),
88            self.source_map(),
89        ))
90    }
91
92    #[turbo_tasks::function]
93    pub fn chunk(&self) -> Result<Vc<Box<dyn Chunk>>> {
94        Ok(Vc::upcast(*self.chunk))
95    }
96}
97
98#[turbo_tasks::value_impl]
99impl OutputAsset for EcmascriptBrowserChunk {
100    #[turbo_tasks::function]
101    async fn path(self: Vc<Self>) -> Result<Vc<FileSystemPath>> {
102        let this = self.await?;
103        let ident = this.ident_for_path();
104        Ok(this
105            .chunking_context
106            .chunk_path(Some(Vc::upcast(self)), ident, rcstr!(".js")))
107    }
108
109    #[turbo_tasks::function]
110    fn size_bytes(self: Vc<Self>) -> Vc<Option<u64>> {
111        self.own_content().content().len()
112    }
113
114    #[turbo_tasks::function]
115    async fn references(self: Vc<Self>) -> Result<Vc<OutputAssets>> {
116        let this = self.await?;
117        let chunk_references = this.chunk.references().await?;
118        let include_source_map = *this
119            .chunking_context
120            .reference_chunk_source_maps(Vc::upcast(self))
121            .await?;
122        let mut references =
123            Vec::with_capacity(chunk_references.len() + if include_source_map { 1 } else { 0 });
124
125        references.extend(chunk_references.iter().copied());
126
127        if include_source_map {
128            references.push(ResolvedVc::upcast(self.source_map().to_resolved().await?));
129        }
130
131        Ok(Vc::cell(references))
132    }
133}
134
135#[turbo_tasks::value_impl]
136impl Asset for EcmascriptBrowserChunk {
137    #[turbo_tasks::function]
138    fn content(self: Vc<Self>) -> Vc<AssetContent> {
139        self.own_content().content()
140    }
141
142    #[turbo_tasks::function]
143    fn versioned_content(self: Vc<Self>) -> Vc<Box<dyn VersionedContent>> {
144        Vc::upcast(self.own_content())
145    }
146}
147
148#[turbo_tasks::value_impl]
149impl GenerateSourceMap for EcmascriptBrowserChunk {
150    #[turbo_tasks::function]
151    fn generate_source_map(self: Vc<Self>) -> Vc<OptionStringifiedSourceMap> {
152        self.own_content().generate_source_map()
153    }
154
155    #[turbo_tasks::function]
156    fn by_section(self: Vc<Self>, section: RcStr) -> Vc<OptionStringifiedSourceMap> {
157        self.own_content().by_section(section)
158    }
159}
160
161#[turbo_tasks::value_impl]
162impl Introspectable for EcmascriptBrowserChunk {
163    #[turbo_tasks::function]
164    fn ty(&self) -> Vc<RcStr> {
165        Vc::cell(rcstr!("dev ecmascript chunk"))
166    }
167
168    #[turbo_tasks::function]
169    fn title(self: Vc<Self>) -> Vc<RcStr> {
170        self.path().to_string()
171    }
172
173    #[turbo_tasks::function]
174    fn details(&self) -> Vc<RcStr> {
175        Vc::cell(rcstr!("generates a development ecmascript chunk"))
176    }
177
178    #[turbo_tasks::function]
179    fn children(&self) -> Result<Vc<IntrospectableChildren>> {
180        let mut children = FxIndexSet::default();
181        let chunk = ResolvedVc::upcast::<Box<dyn Introspectable>>(self.chunk);
182        children.insert((rcstr!("chunk"), chunk));
183        Ok(Vc::cell(children))
184    }
185}