@samitouri / QOS-React / commits / 560db51408

[rust-compiler] Switch to hmac-sha256 and bump napi/similar (#36809)

## Summary Dependency maintenance for the Rust compiler crates. ### Fast Refresh hash: sha2 + hmac → hmac-sha256 The Fast Refresh source hash (`enableResetCacheOnSourceFileChanges`) only needs an HMAC-SHA256 of the source text, matching the TS compiler's `createHmac('sha256', code).digest('hex')`. RustCrypto's `sha2` + `hmac` pulled in **11 crates** (`sha2`, `hmac`, `digest`, `block-buffer`, `typenum`, `crypto-common`, `hybrid-array`, `const-oid`, `cpufeatures`, `cmov`, `ctutils`) — generic-hashing / constant-time machinery that is irrelevant for a non-security content fingerprint. This replaces them with the single **zero-dependency** `hmac-sha256` crate: a net reduction of **10 crates**. HMAC-SHA256 is a standardized deterministic algorithm, so the emitted hash is unchanged. A new unit test `source_file_hash_matches_node_create_hmac` pins the result against Node's `createHmac('sha256', code).digest('hex')` for several inputs. ### Other bumps - `napi` / `napi-derive` 2 → 3 - `similar` 2 → 3 (dev-dependency) - Drop the unused `react_compiler_lowering` dependency from `react_compiler_ssa` `cargo check --workspace --all-targets` passes, including the napi 3 native crate.

Boshen committed Jun 18, 2026 at 07:07 UTC 560db51408f4c186016ccdd8062af75a77c22104
6 files changed +164 -146
compiler/Cargo.lock
+124 -130
@@ -2,15 +2,6 @@
2 # It is not intended for manual editing.
3 version = 4
4
5 -[[package]]
6 -name = "aho-corasick"
7 -version = "1.1.4"
8 -source = "registry+https://github.com/rust-lang/crates.io-index"
9 -checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301"
10 -dependencies = [
11 - "memchr",
12 -]
13 -
5 [[package]]
6 name = "bitflags"
7 version = "2.11.0"
@@ -18,12 +9,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
9 checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af"
10
11 [[package]]
21 -name = "block-buffer"
22 -version = "0.10.4"
12 +name = "bstr"
13 +version = "1.12.1"
14 source = "registry+https://github.com/rust-lang/crates.io-index"
24 -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
15 +checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab"
16 dependencies = [
26 - "generic-array",
17 + "memchr",
18 + "serde",
19 ]
20
21 [[package]]
@@ -34,67 +26,117 @@ checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
26
27 [[package]]
28 name = "convert_case"
37 -version = "0.6.0"
29 +version = "0.11.0"
30 source = "registry+https://github.com/rust-lang/crates.io-index"
39 -checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca"
31 +checksum = "affbf0190ed2caf063e3def54ff444b449371d55c58e513a95ab98eca50adb49"
32 dependencies = [
33 "unicode-segmentation",
34 ]
35
36 [[package]]
45 -name = "cpufeatures"
46 -version = "0.2.17"
37 +name = "ctor"
38 +version = "0.11.1"
39 +source = "registry+https://github.com/rust-lang/crates.io-index"
40 +checksum = "400a21f1014a968ec518c7ccdf9b4a4ed0cac8c56ccb6d604f8b91f00110501e"
41 +
42 +[[package]]
43 +name = "ctor"
44 +version = "1.0.7"
45 +source = "registry+https://github.com/rust-lang/crates.io-index"
46 +checksum = "01334b89b69ff726750c5ce5073fc8bd860e99aa9a8fc5ca11b04730e3aee97a"
47 +
48 +[[package]]
49 +name = "equivalent"
50 +version = "1.0.2"
51 +source = "registry+https://github.com/rust-lang/crates.io-index"
52 +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
53 +
54 +[[package]]
55 +name = "futures"
56 +version = "0.3.32"
57 source = "registry+https://github.com/rust-lang/crates.io-index"
48 -checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
58 +checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d"
59 dependencies = [
50 - "libc",
60 + "futures-channel",
61 + "futures-core",
62 + "futures-executor",
63 + "futures-io",
64 + "futures-sink",
65 + "futures-task",
66 + "futures-util",
67 ]
68
69 [[package]]
54 -name = "crypto-common"
55 -version = "0.1.7"
70 +name = "futures-channel"
71 +version = "0.3.32"
72 source = "registry+https://github.com/rust-lang/crates.io-index"
57 -checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a"
73 +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d"
74 dependencies = [
59 - "generic-array",
60 - "typenum",
75 + "futures-core",
76 + "futures-sink",
77 ]
78
79 [[package]]
64 -name = "ctor"
65 -version = "0.2.9"
80 +name = "futures-core"
81 +version = "0.3.32"
82 +source = "registry+https://github.com/rust-lang/crates.io-index"
83 +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d"
84 +
85 +[[package]]
86 +name = "futures-executor"
87 +version = "0.3.32"
88 source = "registry+https://github.com/rust-lang/crates.io-index"
67 -checksum = "32a2785755761f3ddc1492979ce1e48d2c00d09311c39e4466429188f3dd6501"
89 +checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d"
90 dependencies = [
69 - "quote",
70 - "syn",
91 + "futures-core",
92 + "futures-task",
93 + "futures-util",
94 ]
95
96 [[package]]
74 -name = "digest"
75 -version = "0.10.7"
97 +name = "futures-io"
98 +version = "0.3.32"
99 +source = "registry+https://github.com/rust-lang/crates.io-index"
100 +checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718"
101 +
102 +[[package]]
103 +name = "futures-macro"
104 +version = "0.3.32"
105 source = "registry+https://github.com/rust-lang/crates.io-index"
77 -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
106 +checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b"
107 dependencies = [
79 - "block-buffer",
80 - "crypto-common",
81 - "subtle",
108 + "proc-macro2",
109 + "quote",
110 + "syn",
111 ]
112
113 [[package]]
85 -name = "equivalent"
86 -version = "1.0.2"
114 +name = "futures-sink"
115 +version = "0.3.32"
116 source = "registry+https://github.com/rust-lang/crates.io-index"
88 -checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
117 +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893"
118
119 [[package]]
91 -name = "generic-array"
92 -version = "0.14.7"
120 +name = "futures-task"
121 +version = "0.3.32"
122 source = "registry+https://github.com/rust-lang/crates.io-index"
94 -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
123 +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393"
124 +
125 +[[package]]
126 +name = "futures-util"
127 +version = "0.3.32"
128 +source = "registry+https://github.com/rust-lang/crates.io-index"
129 +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6"
130 dependencies = [
96 - "typenum",
97 - "version_check",
131 + "futures-channel",
132 + "futures-core",
133 + "futures-io",
134 + "futures-macro",
135 + "futures-sink",
136 + "futures-task",
137 + "memchr",
138 + "pin-project-lite",
139 + "slab",
140 ]
141
142 [[package]]
@@ -104,13 +146,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
146 checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
147
148 [[package]]
107 -name = "hmac"
108 -version = "0.12.1"
149 +name = "hmac-sha256"
150 +version = "1.1.14"
151 source = "registry+https://github.com/rust-lang/crates.io-index"
110 -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
111 -dependencies = [
112 - "digest",
113 -]
152 +checksum = "ec9d92d097f4749b64e8cc33d924d9f40a2d4eb91402b458014b781f5733d60f"
153
154 [[package]]
155 name = "indexmap"
@@ -130,17 +169,11 @@ version = "1.0.17"
169 source = "registry+https://github.com/rust-lang/crates.io-index"
170 checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2"
171
133 -[[package]]
134 -name = "libc"
135 -version = "0.2.183"
136 -source = "registry+https://github.com/rust-lang/crates.io-index"
137 -checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d"
138 -
172 [[package]]
173 name = "libloading"
141 -version = "0.8.9"
174 +version = "0.9.0"
175 source = "registry+https://github.com/rust-lang/crates.io-index"
143 -checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55"
176 +checksum = "754ca22de805bb5744484a5b151a9e1a8e837d5dc232c2d7d8c2e3492edc8b60"
177 dependencies = [
178 "cfg-if",
179 "windows-link",
@@ -154,15 +187,17 @@ checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
187
188 [[package]]
189 name = "napi"
157 -version = "2.16.17"
190 +version = "3.8.6"
191 source = "registry+https://github.com/rust-lang/crates.io-index"
159 -checksum = "55740c4ae1d8696773c78fdafd5d0e5fe9bc9f1b071c7ba493ba5c413a9184f3"
192 +checksum = "8e55037284865448ecf329baa86a4d05401f647ebde99f5747b640d32c2c5226"
193 dependencies = [
194 "bitflags",
162 - "ctor",
163 - "napi-derive",
195 + "ctor 0.11.1",
196 + "futures",
197 + "napi-build",
198 "napi-sys",
165 - "once_cell",
199 + "nohash-hasher",
200 + "rustc-hash",
201 ]
202
203 [[package]]
@@ -173,12 +208,12 @@ checksum = "d376940fd5b723c6893cd1ee3f33abbfd86acb1cd1ec079f3ab04a2a3bc4d3b1"
208
209 [[package]]
210 name = "napi-derive"
176 -version = "2.16.13"
211 +version = "3.5.6"
212 source = "registry+https://github.com/rust-lang/crates.io-index"
178 -checksum = "7cbe2585d8ac223f7d34f13701434b9d5f4eb9c332cccce8dee57ea18ab8ab0c"
213 +checksum = "89b3f766e04667e6da0e181e2da4f85475d5a6513b7cf6a80bea184e224a5b42"
214 dependencies = [
180 - "cfg-if",
215 "convert_case",
216 + "ctor 1.0.7",
217 "napi-derive-backend",
218 "proc-macro2",
219 "quote",
@@ -187,33 +222,37 @@ dependencies = [
222
223 [[package]]
224 name = "napi-derive-backend"
190 -version = "1.0.75"
225 +version = "5.0.4"
226 source = "registry+https://github.com/rust-lang/crates.io-index"
192 -checksum = "1639aaa9eeb76e91c6ae66da8ce3e89e921cd3885e99ec85f4abacae72fc91bf"
227 +checksum = "0d5af30503edf933ce7377cf6d4c877a62b0f1107ea05585f1b5e430e88d5baf"
228 dependencies = [
229 "convert_case",
195 - "once_cell",
230 "proc-macro2",
231 "quote",
198 - "regex",
232 "semver",
233 "syn",
234 ]
235
236 [[package]]
237 name = "napi-sys"
205 -version = "2.4.0"
238 +version = "3.2.2"
239 source = "registry+https://github.com/rust-lang/crates.io-index"
207 -checksum = "427802e8ec3a734331fec1035594a210ce1ff4dc5bc1950530920ab717964ea3"
240 +checksum = "1f5bcdf71abd3a50d00b49c1c2c75251cb3c913777d6139cd37dabc093a5e400"
241 dependencies = [
242 "libloading",
243 ]
244
245 [[package]]
213 -name = "once_cell"
214 -version = "1.21.4"
246 +name = "nohash-hasher"
247 +version = "0.2.0"
248 source = "registry+https://github.com/rust-lang/crates.io-index"
216 -checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
249 +checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451"
250 +
251 +[[package]]
252 +name = "pin-project-lite"
253 +version = "0.2.17"
254 +source = "registry+https://github.com/rust-lang/crates.io-index"
255 +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
256
257 [[package]]
258 name = "proc-macro2"
@@ -334,13 +373,12 @@ dependencies = [
373 name = "react_compiler_reactive_scopes"
374 version = "0.1.0"
375 dependencies = [
337 - "hmac",
376 + "hmac-sha256",
377 "indexmap",
378 "react_compiler_ast",
379 "react_compiler_diagnostics",
380 "react_compiler_hir",
381 "serde_json",
343 - "sha2",
382 ]
383
384 [[package]]
@@ -350,7 +388,6 @@ dependencies = [
388 "indexmap",
389 "react_compiler_diagnostics",
390 "react_compiler_hir",
353 - "react_compiler_lowering",
391 ]
392
393 [[package]]
@@ -379,33 +416,10 @@ dependencies = [
416 ]
417
418 [[package]]
382 -name = "regex"
383 -version = "1.12.3"
419 +name = "rustc-hash"
420 +version = "2.1.2"
421 source = "registry+https://github.com/rust-lang/crates.io-index"
385 -checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276"
386 -dependencies = [
387 - "aho-corasick",
388 - "memchr",
389 - "regex-automata",
390 - "regex-syntax",
391 -]
392 -
393 -[[package]]
394 -name = "regex-automata"
395 -version = "0.4.14"
396 -source = "registry+https://github.com/rust-lang/crates.io-index"
397 -checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f"
398 -dependencies = [
399 - "aho-corasick",
400 - "memchr",
401 - "regex-syntax",
402 -]
403 -
404 -[[package]]
405 -name = "regex-syntax"
406 -version = "0.8.10"
407 -source = "registry+https://github.com/rust-lang/crates.io-index"
408 -checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a"
422 +checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe"
423
424 [[package]]
425 name = "same-file"
@@ -475,27 +489,19 @@ dependencies = [
489 ]
490
491 [[package]]
478 -name = "sha2"
479 -version = "0.10.9"
492 +name = "similar"
493 +version = "3.1.1"
494 source = "registry+https://github.com/rust-lang/crates.io-index"
481 -checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
495 +checksum = "e6505efef05804732ed8a3f2d4f279429eb485bd69d5b0cc6b19cc02005cda16"
496 dependencies = [
483 - "cfg-if",
484 - "cpufeatures",
485 - "digest",
497 + "bstr",
498 ]
499
500 [[package]]
489 -name = "similar"
490 -version = "2.7.0"
501 +name = "slab"
502 +version = "0.4.12"
503 source = "registry+https://github.com/rust-lang/crates.io-index"
492 -checksum = "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa"
493 -
494 -[[package]]
495 -name = "subtle"
496 -version = "2.6.1"
497 -source = "registry+https://github.com/rust-lang/crates.io-index"
498 -checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
504 +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5"
505
506 [[package]]
507 name = "syn"
@@ -508,12 +514,6 @@ dependencies = [
514 "unicode-ident",
515 ]
516
511 -[[package]]
512 -name = "typenum"
513 -version = "1.19.0"
514 -source = "registry+https://github.com/rust-lang/crates.io-index"
515 -checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb"
516 -
517 [[package]]
518 name = "unicode-ident"
519 version = "1.0.24"
@@ -526,12 +526,6 @@ version = "1.12.0"
526 source = "registry+https://github.com/rust-lang/crates.io-index"
527 checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
528
529 -[[package]]
530 -name = "version_check"
531 -version = "0.9.5"
532 -source = "registry+https://github.com/rust-lang/crates.io-index"
533 -checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
534 -
529 [[package]]
530 name = "walkdir"
531 version = "2.5.0"
compiler/crates/react_compiler_ast/Cargo.toml
+1 -1
@@ -12,4 +12,4 @@ indexmap = { version = "2", features = ["serde"] }
12
13 [dev-dependencies]
14 walkdir = "2"
15 -similar = "2"
15 +similar = "3"
compiler/crates/react_compiler_reactive_scopes/Cargo.toml
+1 -2
@@ -9,5 +9,4 @@ react_compiler_diagnostics = { path = "../react_compiler_diagnostics" }
9 react_compiler_hir = { path = "../react_compiler_hir" }
10 indexmap = "2"
11 serde_json = "1"
12 -sha2 = "0.10"
13 -hmac = "0.12"
12 +hmac-sha256 = "1"
compiler/crates/react_compiler_reactive_scopes/src/codegen_reactive_function.rs
+36 -10
@@ -181,6 +181,17 @@ pub struct OutlinedFunction {
181 }
182
183 /// Top-level entry point: generates code for a reactive function.
184 +/// Computes the Fast Refresh source hash used to bust the memo cache when the
185 +/// source file changes. Matches the TS compiler's
186 +/// `createHmac('sha256', code).digest('hex')`: an HMAC-SHA256 keyed by the
187 +/// source code, hashing empty data.
188 +fn source_file_hash(code: &str) -> String {
189 + hmac_sha256::HMAC::mac(b"", code.as_bytes())
190 + .iter()
191 + .map(|b| format!("{b:02x}"))
192 + .collect()
193 +}
194 +
195 pub fn codegen_function(
196 func: &ReactiveFunction,
197 env: &mut Environment,
@@ -194,15 +205,7 @@ pub fn codegen_function(
205 let fast_refresh_state: Option<(u32, String)> =
206 if cx.env.config.enable_reset_cache_on_source_file_changes == Some(true) {
207 if let Some(ref code) = cx.env.code {
197 - use hmac::Hmac;
198 - use hmac::Mac;
199 - use sha2::Sha256;
200 - type HmacSha256 = Hmac<Sha256>;
201 - // Match TS: createHmac('sha256', code).digest('hex')
202 - // Node's createHmac uses the code as the HMAC key and hashes empty data.
203 - let mac = HmacSha256::new_from_slice(code.as_bytes())
204 - .expect("HMAC can take key of any size");
205 - let hash = format!("{:x}", mac.finalize().into_bytes());
208 + let hash = source_file_hash(code);
209 let cache_index = cx.alloc_cache_index(); // Reserve slot 0 for the hash check
210 Some((cache_index, hash))
211 } else {
@@ -382,7 +385,9 @@ pub fn codegen_function(
385 arguments: vec![Expression::StringLiteral(
386 StringLiteral {
387 base: BaseNode::typed("StringLiteral"),
385 - value: MEMO_CACHE_SENTINEL.to_string().into(),
388 + value: MEMO_CACHE_SENTINEL
389 + .to_string()
390 + .into(),
391 },
392 )],
393 type_parameters: None,
@@ -4239,6 +4244,27 @@ mod tests {
4244
4245 use super::{UnsupportedOriginalNode, codegen_unsupported_original_node};
4246
4247 + /// The Fast Refresh source hash must match Node's
4248 + /// `createHmac('sha256', code).digest('hex')` byte-for-byte, or hot-reload
4249 + /// cache invalidation would diverge from the TS compiler. Reference values
4250 + /// were computed with Node's `crypto` module.
4251 + #[test]
4252 + fn source_file_hash_matches_node_create_hmac() {
4253 + use super::source_file_hash;
4254 + assert_eq!(
4255 + source_file_hash("hello world"),
4256 + "0de8bee5d7f9c5d209f8c6fabed0ea84cb3fca1244e8ed38079a61b599a84c47"
4257 + );
4258 + assert_eq!(
4259 + source_file_hash(""),
4260 + "b613679a0814d9ec772f95d778c35fc5ff1697c493715653c6c712144292c5ad"
4261 + );
4262 + assert_eq!(
4263 + source_file_hash("function App(){}"),
4264 + "d637acb4985c789d6622c70197db2b62dda282f16f3276aa810b598d6e6cab7b"
4265 + );
4266 + }
4267 +
4268 /// A modeled statement tag parses typed and is emitted directly.
4269 #[test]
4270 fn unsupported_original_node_modeled_statement_tag_emits_statement() {
compiler/crates/react_compiler_ssa/Cargo.toml
-1
@@ -6,5 +6,4 @@ edition = "2024"
6 [dependencies]
7 react_compiler_diagnostics = { path = "../react_compiler_diagnostics" }
8 react_compiler_hir = { path = "../react_compiler_hir" }
9 -react_compiler_lowering = { path = "../react_compiler_lowering" }
9 indexmap = "2"
compiler/packages/babel-plugin-react-compiler-rust/native/Cargo.toml
+2 -2
@@ -7,8 +7,8 @@ edition = "2024"
7 crate-type = ["cdylib"]
8
9 [dependencies]
10 -napi = { version = "2", features = ["napi4"] }
11 -napi-derive = "2"
10 +napi = { version = "3", features = ["napi4"] }
11 +napi-derive = "3"
12 react_compiler = { path = "../../../crates/react_compiler" }
13 react_compiler_ast = { path = "../../../crates/react_compiler_ast" }
14 serde = "1"