turbopack_ecmascript/hmr/
version.rs1use anyhow::Result;
2use turbo_rcstr::RcStr;
3use turbo_tasks::{FxIndexMap, ReadRef, TryJoinIterExt, Vc, turbobail};
4use turbo_tasks_fs::FileSystemPath;
5use turbo_tasks_hash::{Xxh3Hash64Hasher, encode_base64};
6use turbopack_core::{
7 chunk::{MinifyType, ModuleId},
8 version::Version,
9};
10
11use crate::chunk::{EcmascriptChunkContent, EcmascriptChunkContentEntries};
12
13#[turbo_tasks::value(serialization = "skip")]
21pub struct EcmascriptChunkVersion {
22 pub chunk_path: RcStr,
23 pub minify_type: MinifyType,
24 pub entries_hashes: FxIndexMap<ModuleId, u128>,
25}
26
27#[turbo_tasks::value_impl]
28impl EcmascriptChunkVersion {
29 #[turbo_tasks::function]
30 pub async fn new(
31 output_root: FileSystemPath,
32 chunk_path: FileSystemPath,
33 content: Vc<EcmascriptChunkContent>,
34 minify_type: MinifyType,
35 ) -> Result<Vc<Self>> {
36 let Some(chunk_path) = output_root.get_path_to(&chunk_path) else {
37 turbobail!("chunk path {chunk_path} is not in output root {output_root}");
38 };
39 let entries_hashes = EcmascriptChunkContentEntries::new(content)
40 .await?
41 .iter()
42 .map(async |(id, entry)| Ok((id.clone(), *entry.hash.await?)))
43 .try_join()
44 .await?
45 .into_iter()
46 .collect();
47
48 Ok(EcmascriptChunkVersion {
49 chunk_path: chunk_path.into(),
50 minify_type,
51 entries_hashes,
52 }
53 .cell())
54 }
55}
56
57#[turbo_tasks::value_impl]
58impl Version for EcmascriptChunkVersion {
59 #[turbo_tasks::function]
60 fn id(&self) -> Vc<RcStr> {
61 let mut hasher = Xxh3Hash64Hasher::new();
62 hasher.write_ref(&self.chunk_path);
63 hasher.write_ref(&self.minify_type);
64 let sorted_hashes = {
65 let mut hashes: Vec<_> = self.entries_hashes.values().copied().collect();
66 hashes.sort();
67 hashes
68 };
69 for hash in sorted_hashes {
70 hasher.write_value(hash);
71 }
72 let hash = hasher.finish();
73 let hash = encode_base64(hash);
74 Vc::cell(hash.into())
75 }
76}
77
78#[turbo_tasks::value(serialization = "skip", shared)]
81pub struct EcmascriptMergedChunkVersion {
82 #[turbo_tasks(trace_ignore)]
83 pub versions: Vec<ReadRef<EcmascriptChunkVersion>>,
84}
85
86#[turbo_tasks::value_impl]
87impl Version for EcmascriptMergedChunkVersion {
88 #[turbo_tasks::function]
89 async fn id(&self) -> Result<Vc<RcStr>> {
90 let mut hasher = Xxh3Hash64Hasher::new();
91 hasher.write_value(self.versions.len());
92 let sorted_ids = {
93 let mut sorted_ids = self
94 .versions
95 .iter()
96 .map(|version| ReadRef::cell(version.clone()).id())
99 .try_join()
100 .await?;
101 sorted_ids.sort();
102 sorted_ids
103 };
104 for id in sorted_ids {
105 hasher.write_value(id);
106 }
107 let hash = hasher.finish();
108 let hash = encode_base64(hash);
109 Ok(Vc::cell(hash.into()))
110 }
111}