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 pub versions: Vec<ReadRef<EcmascriptChunkVersion>>,
83}
84
85#[turbo_tasks::value_impl]
86impl Version for EcmascriptMergedChunkVersion {
87 #[turbo_tasks::function]
88 async fn id(&self) -> Result<Vc<RcStr>> {
89 let mut hasher = Xxh3Hash64Hasher::new();
90 hasher.write_value(self.versions.len());
91 let sorted_ids = {
92 let mut sorted_ids = self
93 .versions
94 .iter()
95 .map(|version| ReadRef::cell(version.clone()).id())
98 .try_join()
99 .await?;
100 sorted_ids.sort();
101 sorted_ids
102 };
103 for id in sorted_ids {
104 hasher.write_value(id);
105 }
106 let hash = hasher.finish();
107 let hash = encode_base64(hash);
108 Ok(Vc::cell(hash.into()))
109 }
110}