@samitouri / QOS-React / commits / 34b78a2897

[rust-compiler] Drop the regex dependency from the napi binary (#36727)

The regex crate services exactly one pattern, the dynamic-gating directive `^use memo if\(([^\)]*)\)$`, while costing ~570KB of `.text` (regex + regex_automata + regex_syntax + aho_corasick) in the shipped binary; after LTO the removal saves ~1MB through dead-code cascade. Replaced with an exact hand parse: strip the `use memo if(` prefix and `)` suffix, reject conditions containing a close paren. Equivalence with the TS `DYNAMIC_GATING_DIRECTIVE` regex verified on the full gating fixture directory: 30/30 byte-identical TS-vs-Rust on the e2e comparison harness, dynamic-gating snap fixtures green. Independent of #36726; the two compose to take the default release binary from 11.2MB to 6.1MB.

lauren committed Jun 9, 2026 at 15:38 UTC 34b78a2897cc208260a88e6b62ecaf9ca2a9dfe4
3 files changed +25 -19
compiler/Cargo.lock
-1
@@ -1189,7 +1189,6 @@ dependencies = [
1189 "react_compiler_ssa",
1190 "react_compiler_typeinference",
1191 "react_compiler_validation",
1192 - "regex",
1192 "serde",
1193 "serde_json",
1194 ]
compiler/crates/react_compiler/Cargo.toml
-1
@@ -15,6 +15,5 @@ react_compiler_ssa = { path = "../react_compiler_ssa" }
15 react_compiler_typeinference = { path = "../react_compiler_typeinference" }
16 react_compiler_validation = { path = "../react_compiler_validation" }
17 indexmap = "2"
18 -regex = "1"
18 serde = { version = "1", features = ["derive"] }
19 serde_json = { version = "1", features = ["raw_value"] }
compiler/crates/react_compiler/src/entrypoint/program.rs
+25 -17
@@ -43,7 +43,6 @@ use react_compiler_diagnostics::SourceLocation;
43 use react_compiler_hir::ReactFunctionType;
44 use react_compiler_hir::environment_config::EnvironmentConfig;
45 use react_compiler_lowering::FunctionNode;
46 -use regex::Regex;
46
47 use super::compile_result::BindingRenameInfo;
48 use super::compile_result::CodegenFunction;
@@ -175,26 +174,21 @@ fn find_directives_dynamic_gating<'a>(
174 None => return Ok(None),
175 };
176
178 - let pattern = Regex::new(r"^use memo if\(([^\)]*)\)$").expect("Invalid dynamic gating regex");
179 -
177 let mut errors: Vec<CompilerErrorDetail> = Vec::new();
178 let mut matches: Vec<(&'a Directive, String)> = Vec::new();
179
180 for directive in directives {
184 - if let Some(caps) = pattern.captures(&directive.value.value) {
185 - if let Some(m) = caps.get(1) {
186 - let ident = m.as_str();
187 - if is_valid_identifier(ident) {
188 - matches.push((directive, ident.to_string()));
189 - } else {
190 - let mut detail = CompilerErrorDetail::new(
191 - ErrorCategory::Gating,
192 - "Dynamic gating directive is not a valid JavaScript identifier",
193 - )
194 - .with_description(format!("Found '{}'", directive.value.value));
195 - detail.loc = directive.base.loc.as_ref().map(convert_loc);
196 - errors.push(detail);
197 - }
181 + if let Some(ident) = parse_dynamic_gating_directive(&directive.value.value) {
182 + if is_valid_identifier(ident) {
183 + matches.push((directive, ident.to_string()));
184 + } else {
185 + let mut detail = CompilerErrorDetail::new(
186 + ErrorCategory::Gating,
187 + "Dynamic gating directive is not a valid JavaScript identifier",
188 + )
189 + .with_description(format!("Found '{}'", directive.value.value));
190 + detail.loc = directive.base.loc.as_ref().map(convert_loc);
191 + errors.push(detail);
192 }
193 }
194 }
@@ -236,6 +230,20 @@ fn find_directives_dynamic_gating<'a>(
230 }
231 }
232
233 +/// Parse a `use memo if(<condition>)` directive, returning the condition.
234 +/// Exact equivalent of the TS DYNAMIC_GATING_DIRECTIVE regex
235 +/// `^use memo if\(([^\)]*)\)$`: the condition may not contain `)` and the
236 +/// directive must end at the closing paren.
237 +fn parse_dynamic_gating_directive(value: &str) -> Option<&str> {
238 + let condition = value
239 + .strip_prefix("use memo if(")?
240 + .strip_suffix(')')?;
241 + if condition.contains(')') {
242 + return None;
243 + }
244 + Some(condition)
245 +}
246 +
247 /// Simple check for valid JavaScript identifier (alphanumeric + underscore + $, starting with letter/$/_ )
248 /// Also rejects reserved words like `true`, `false`, `null`, etc.
249 fn is_valid_identifier(s: &str) -> bool {