Skip to main content

turbopack_nodejs/ecmascript/node/
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},
8    introspect::{Introspectable, IntrospectableChildren},
9    output::{OutputAsset, OutputAssetsReference, OutputAssetsWithReferenced},
10    source_map::{GenerateSourceMap, SourceMapAsset},
11    version::VersionedContent,
12};
13use turbopack_ecmascript::chunk::{EcmascriptChunk, EcmascriptChunkContent};
14
15use super::content::EcmascriptNodeChunkContent;
16use crate::NodeJsChunkingContext;
17
18/// Production Ecmascript chunk targeting Node.js.
19#[turbo_tasks::value(shared)]
20#[derive(ValueToString)]
21#[value_to_string("Ecmascript Build Node Chunk")]
22pub struct EcmascriptBuildNodeChunk {
23    chunking_context: ResolvedVc<NodeJsChunkingContext>,
24    chunk: ResolvedVc<EcmascriptChunk>,
25}
26
27#[turbo_tasks::value_impl]
28impl EcmascriptBuildNodeChunk {
29    /// Creates a new [`Vc<EcmascriptBuildNodeChunk>`].
30    #[turbo_tasks::function]
31    pub fn new(
32        chunking_context: ResolvedVc<NodeJsChunkingContext>,
33        chunk: ResolvedVc<EcmascriptChunk>,
34    ) -> Vc<Self> {
35        EcmascriptBuildNodeChunk {
36            chunking_context,
37            chunk,
38        }
39        .cell()
40    }
41
42    /// Constituent chunk items and batches, before the Node.js output wrapper.
43    #[turbo_tasks::function]
44    pub fn chunk_content(&self) -> Vc<EcmascriptChunkContent> {
45        self.chunk.chunk_content()
46    }
47
48    #[turbo_tasks::function]
49    async fn source_map(self: Vc<Self>) -> Result<Vc<SourceMapAsset>> {
50        let this = self.await?;
51        Ok(SourceMapAsset::new(
52            Vc::upcast(*this.chunking_context),
53            this.chunk
54                .ident()
55                .owned()
56                .await?
57                .with_modifier(modifier())
58                .into_vc(),
59            Vc::upcast(self),
60        ))
61    }
62}
63
64fn modifier() -> RcStr {
65    rcstr!("ecmascript build node chunk")
66}
67
68#[turbo_tasks::value_impl]
69impl EcmascriptBuildNodeChunk {
70    #[turbo_tasks::function]
71    async fn own_content(self: Vc<Self>) -> Result<Vc<EcmascriptNodeChunkContent>> {
72        let this = self.await?;
73        Ok(EcmascriptNodeChunkContent::new(
74            *this.chunking_context,
75            self,
76            this.chunk.chunk_content(),
77            self.source_map(),
78        ))
79    }
80}
81
82#[turbo_tasks::value_impl]
83impl OutputAssetsReference for EcmascriptBuildNodeChunk {
84    #[turbo_tasks::function]
85    async fn references(self: Vc<Self>) -> Result<Vc<OutputAssetsWithReferenced>> {
86        let this = self.await?;
87        let chunk_references = this.chunk.references().await?;
88        let include_source_map = *this
89            .chunking_context
90            .reference_chunk_source_maps(Vc::upcast(self))
91            .await?;
92        let ref_assets = chunk_references.assets.await?;
93        let mut assets =
94            Vec::with_capacity(ref_assets.len() + if include_source_map { 1 } else { 0 });
95
96        assets.extend(ref_assets.iter().copied());
97
98        if include_source_map {
99            assets.push(ResolvedVc::upcast(self.source_map().to_resolved().await?));
100        }
101
102        Ok(OutputAssetsWithReferenced {
103            assets: ResolvedVc::cell(assets),
104            referenced_assets: chunk_references.referenced_assets,
105            references: chunk_references.references,
106        }
107        .cell())
108    }
109}
110
111#[turbo_tasks::value_impl]
112impl OutputAsset for EcmascriptBuildNodeChunk {
113    #[turbo_tasks::function]
114    async fn path(self: Vc<Self>) -> Result<Vc<FileSystemPath>> {
115        let this = self.await?;
116        let ident = this
117            .chunk
118            .ident()
119            .owned()
120            .await?
121            .with_modifier(modifier())
122            .into_vc();
123        Ok(this
124            .chunking_context
125            .chunk_path(Some(Vc::upcast(self)), ident, None, rcstr!(".js")))
126    }
127}
128
129#[turbo_tasks::value_impl]
130impl Asset for EcmascriptBuildNodeChunk {
131    #[turbo_tasks::function]
132    fn content(self: Vc<Self>) -> Vc<AssetContent> {
133        self.own_content().content()
134    }
135
136    #[turbo_tasks::function]
137    fn versioned_content(self: Vc<Self>) -> Vc<Box<dyn VersionedContent>> {
138        Vc::upcast(self.own_content())
139    }
140}
141
142#[turbo_tasks::value_impl]
143impl GenerateSourceMap for EcmascriptBuildNodeChunk {
144    #[turbo_tasks::function]
145    fn generate_source_map(self: Vc<Self>) -> Vc<FileContent> {
146        self.own_content().generate_source_map()
147    }
148}
149
150#[turbo_tasks::value_impl]
151impl Introspectable for EcmascriptBuildNodeChunk {
152    #[turbo_tasks::function]
153    fn ty(&self) -> Vc<RcStr> {
154        Vc::cell(rcstr!("ecmascript build node chunk"))
155    }
156
157    #[turbo_tasks::function]
158    fn title(self: Vc<Self>) -> Vc<RcStr> {
159        self.path().to_string()
160    }
161
162    #[turbo_tasks::function]
163    fn details(&self) -> Vc<RcStr> {
164        Vc::cell(rcstr!(
165            "generates a production EcmaScript chunk targeting Node.js"
166        ))
167    }
168
169    #[turbo_tasks::function]
170    fn children(&self) -> Result<Vc<IntrospectableChildren>> {
171        let mut children = FxIndexSet::default();
172        let introspectable_chunk = ResolvedVc::upcast::<Box<dyn Introspectable>>(self.chunk);
173        children.insert((rcstr!("chunk"), introspectable_chunk));
174        Ok(Vc::cell(children))
175    }
176}