turbopack_nodejs/ecmascript/node/entry/
chunk_list_content.rs1use anyhow::{Result, bail};
2use turbo_tasks::{FxIndexMap, ResolvedVc, 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 new(
59 chunking_context: ResolvedVc<NodeJsChunkingContext>,
60 chunks: ResolvedVc<OutputAssets>,
61 references: ResolvedVc<OutputAssetsReferences>,
62 ) -> Result<Vc<Self>> {
63 let output_root = chunking_context.output_root().owned().await?;
64
65 let async_chunks = expand_output_assets(
70 references
71 .await?
72 .iter()
73 .copied()
74 .map(ExpandOutputAssetsInput::Reference),
75 false,
76 )
77 .await?;
78
79 let chunks_contents = collect_chunks_contents(
80 &output_root,
81 chunks.await?.iter().copied().chain(async_chunks),
82 )
83 .await?;
84
85 Ok(EcmascriptBuildNodeChunkListContent { chunks_contents }.cell())
86 }
87
88 #[turbo_tasks::function]
94 pub async fn new_from_chunks(
95 chunking_context: ResolvedVc<NodeJsChunkingContext>,
96 chunks: Vc<OutputAssets>,
97 ) -> Result<Vc<Self>> {
98 let output_root = chunking_context.output_root().owned().await?;
99 let chunks_contents =
100 collect_chunks_contents(&output_root, chunks.await?.iter().copied()).await?;
101
102 Ok(EcmascriptBuildNodeChunkListContent { chunks_contents }.cell())
103 }
104
105 #[turbo_tasks::function]
106 pub async fn version(&self) -> Result<Vc<ChunkListVersion>> {
107 compute_chunk_list_version(&self.chunks_contents).await
108 }
109}
110
111#[turbo_tasks::value_impl]
112impl VersionedContent for EcmascriptBuildNodeChunkListContent {
113 #[turbo_tasks::function]
114 fn content(self: Vc<Self>) -> Result<Vc<AssetContent>> {
115 bail!("EcmascriptBuildNodeChunkListContent does not have content")
116 }
117
118 #[turbo_tasks::function]
119 fn version(self: Vc<Self>) -> Vc<Box<dyn Version>> {
120 Vc::upcast(self.version())
121 }
122
123 #[turbo_tasks::function]
124 async fn update(
125 self: ResolvedVc<Self>,
126 from_version: ResolvedVc<Box<dyn Version>>,
127 ) -> Result<Vc<Update>> {
128 let this = self.await?;
129 let to_version = self.version();
130 update_chunk_list(&this.chunks_contents, to_version, from_version).await
131 }
132}