turbopack_nodejs/ecmascript/node/entry/
chunk_list_content.rs1use anyhow::{Result, bail};
2use turbo_tasks::{FxIndexMap, ReadRef, ResolvedVc, TransientInstance, TryJoinIterExt, Vc};
3use turbo_tasks_fs::FileSystemPath;
4use turbopack_core::{
5 asset::{Asset, AssetContent},
6 chunk::ChunkingContext,
7 output::{
8 ExpandOutputAssetsInput, OutputAsset, OutputAssets, OutputAssetsReferences,
9 expand_output_assets,
10 },
11 version::{Update, Version, VersionedContent},
12};
13use turbopack_ecmascript::chunk_list::{
14 update::update_chunk_list,
15 version::{ChunkListVersion, compute_chunk_list_version},
16};
17
18use crate::NodeJsChunkingContext;
19
20async fn collect_chunks_contents(
22 output_root: &FileSystemPath,
23 chunks: impl Iterator<Item = ResolvedVc<Box<dyn OutputAsset>>>,
24) -> Result<FxIndexMap<String, ResolvedVc<Box<dyn VersionedContent>>>> {
25 chunks
26 .map(async |chunk| {
27 let chunk_path = chunk.path().await?;
28 let Some(path) = output_root.get_path_to(&chunk_path) else {
29 bail!("chunk {chunk_path} is not inside the output root {output_root}");
30 };
31 Ok((
32 path.to_string(),
33 chunk.versioned_content().to_resolved().await?,
34 ))
35 })
36 .try_join()
37 .await
38 .map(FxIndexMap::from_iter)
39}
40
41#[turbo_tasks::value]
50pub struct EcmascriptBuildNodeChunkListContent {
51 #[bincode(with = "turbo_bincode::indexmap")]
52 pub(super) chunks_contents: FxIndexMap<String, ResolvedVc<Box<dyn VersionedContent>>>,
53}
54
55#[turbo_tasks::value_impl]
56impl EcmascriptBuildNodeChunkListContent {
57 #[turbo_tasks::function]
58 pub async fn compute_update_from_version(
59 self: Vc<Self>,
60 from: TransientInstance<ReadRef<ChunkListVersion>>,
61 ) -> Result<Vc<Update>> {
62 let to = self.version();
63 update_chunk_list(
64 &self.await?.chunks_contents,
65 to,
66 ResolvedVc::upcast(ReadRef::resolved_cell((*from).clone())),
67 )
68 .await
69 }
70
71 #[turbo_tasks::function]
72 pub async fn new(
73 chunking_context: ResolvedVc<NodeJsChunkingContext>,
74 chunks: ResolvedVc<OutputAssets>,
75 referenced_assets: ResolvedVc<OutputAssets>,
76 references: ResolvedVc<OutputAssetsReferences>,
77 ) -> Result<Vc<Self>> {
78 let output_root = chunking_context.output_root().owned().await?;
79
80 let async_chunks = expand_output_assets(
90 referenced_assets
91 .await?
92 .iter()
93 .copied()
94 .map(ExpandOutputAssetsInput::Asset)
95 .chain(
96 references
97 .await?
98 .iter()
99 .copied()
100 .map(ExpandOutputAssetsInput::Reference),
101 ),
102 false,
103 )
104 .await?;
105
106 let chunks_contents = collect_chunks_contents(
107 &output_root,
108 chunks.await?.iter().copied().chain(async_chunks),
109 )
110 .await?;
111
112 Ok(EcmascriptBuildNodeChunkListContent { chunks_contents }.cell())
113 }
114
115 #[turbo_tasks::function]
121 pub async fn new_from_chunks(
122 chunking_context: ResolvedVc<NodeJsChunkingContext>,
123 chunks: Vc<OutputAssets>,
124 ) -> Result<Vc<Self>> {
125 let output_root = chunking_context.output_root().owned().await?;
126 let chunks_contents =
127 collect_chunks_contents(&output_root, chunks.await?.iter().copied()).await?;
128
129 Ok(EcmascriptBuildNodeChunkListContent { chunks_contents }.cell())
130 }
131
132 #[turbo_tasks::function]
133 pub async fn version(&self) -> Result<Vc<ChunkListVersion>> {
134 compute_chunk_list_version(&self.chunks_contents).await
135 }
136}
137
138#[turbo_tasks::value_impl]
139impl VersionedContent for EcmascriptBuildNodeChunkListContent {
140 #[turbo_tasks::function]
141 fn content(self: Vc<Self>) -> Result<Vc<AssetContent>> {
142 bail!("EcmascriptBuildNodeChunkListContent does not have content")
143 }
144
145 #[turbo_tasks::function]
146 fn version(self: Vc<Self>) -> Vc<Box<dyn Version>> {
147 Vc::upcast(self.version())
148 }
149
150 #[turbo_tasks::function]
151 async fn update(
152 self: ResolvedVc<Self>,
153 from_version: ResolvedVc<Box<dyn Version>>,
154 ) -> Result<Vc<Update>> {
155 let this = self.await?;
156 let to_version = self.version();
157 update_chunk_list(&this.chunks_contents, to_version, from_version).await
158 }
159}
160
161#[turbo_tasks::function(operation, root)]
162pub fn compute_update_from_version_operation(
163 content: ResolvedVc<EcmascriptBuildNodeChunkListContent>,
164 from: TransientInstance<ReadRef<ChunkListVersion>>,
165) -> Vc<Update> {
166 content.compute_update_from_version(from)
167}