mirror of
https://github.com/oxc-project/oxc.git
synced 2026-09-14 19:36:11 +08:00
a8ed2a7837
Updates the minifier documentation to use supported validation commands and fixes broken relative links. Also refreshes the coverage task README so it no longer advertises removed suite selectors.
4.8 KiB
4.8 KiB
Oxc Minifier - AI Assistant Guide
Mission
Build the best JavaScript minifier: smallest output, 100% correct, reasonably fast.
Quick Reference
Architecture
- Fixed-point iteration in
PeepholeOptimizations::run_in_loop - Arena allocation via
oxc_allocator - 17+ optimizations in
src/peephole/
Key Files
src/
├── lib.rs # Entry point
├── compressor.rs # Pipeline orchestration
├── ctx.rs # Shared utilities
├── state.rs # Optimization state
├── peephole/
│ ├── mod.rs # Optimization dispatch
│ └── *.rs # Individual optimizations
Adding New Optimizations
- Research: Study implementation in other minifiers (Terser, Closure, esbuild)
- Design: Determine transformation rules and edge cases
- Implement: Add to
src/peephole/following existing patterns - Hook up: Add to traversal in
peephole/mod.rs - Test: Add comprehensive tests
- Measure: Check size impact with
just minsize - Validate: Run conformance with
cargo coverage
Testing Commands
just test # Unit tests
just minsize # Size benchmarks (PRIMARY METRIC)
cargo coverage # Conformance tests
pnpm --filter "./napi/minify" --filter "./napi/transform" run build-test
pnpm --dir tasks/e2e test # End-to-end tests
just ready # Run before committing
Common Patterns
Optimization Structure
pub fn optimize_something(expr: &mut Expression, ctx: &mut Ctx) {
// Check if optimization applies
if !can_optimize(expr, ctx) {
return;
}
// Apply transformation
let new_expr = create_optimized_form(ctx);
ctx.replace_expression(expr, new_expr);
}
Always route slot replacements through the typed ctx.replace_* helpers —
they are the only way to signal a mutation: the mutation flag is private to
MinifierState (compiler-enforced), so a bare *slot = … write cannot mark
the pass as changed and will stall the fixed-point loop. For in-place edits
that don't replace a slot (operand swaps, field flips, element removals), call
ctx.notice_change(); if a raw slot write is genuinely required (e.g. an enum
slot with no typed helper), pair it with ctx.notice_change() and a comment
explaining why.
Traversal Hook
// In peephole/mod.rs
fn exit_expression(&mut self, expr: &mut Expression<'a>, ctx: &mut TraverseCtx<'a>) {
let ctx = &mut Ctx::new(ctx);
match expr {
Expression::BinaryExpression(_) => {
Self::optimize_binary(expr, ctx);
}
// ... other cases
}
}
Size Optimization Tips
- Always prefer shorter syntax (
!0overtrue) - Combine related operations
- Remove all redundancy
- Fold constants aggressively
- Eliminate dead code completely
- Use comma operators for sequences
- Prefer operators over keywords
Performance Tips
- Minimize AST traversals
- Use arena allocation (
ctx.ast) - Batch related transformations
- Early exit when possible
- Check side effects early
Common Pitfalls to Avoid
- Side Effects: Always check
may_have_side_effects() - Scope Issues: Use
scoping()for variable lookups - TDZ: Be careful with
let/consttransformations - Evaluation Order: Preserve execution order
- Edge Cases: Test with
NaN,Infinity,-0, etc.
Debugging
# Debug conformance failures
cargo coverage --debug
# Test single file
cargo run -p oxc_minifier --example minifier test.js
# Test idempotency
cargo run -p oxc_minifier --example minifier test.js --twice
Key Utilities in ctx.rs
eval_binary()- Evaluate binary expressionsvalue_to_expr()- Convert constant to AST nodeis_expression_undefined()- Check for undefinedexpr_eq()- Compare expressionsscoping()- Access scope informationast- AST builder
Development Flow
-
Find optimization opportunity
- Check minsize benchmarks
- Study other minifiers
- Look for patterns in real code
-
Implement safely
- Follow existing patterns
- Handle all edge cases
- Preserve semantics
-
Test thoroughly
cargo test -p oxc_minifier cargo coverage just minsize -
Document clearly
- Add comments explaining the optimization
- Document any assumptions
- Add examples in tests
AST Manipulation
// Use TakeIn for moving nodes
use oxc_allocator::TakeIn;
let moved = node.take_in(ctx.ast);
// Use arena for allocations
ctx.ast.expression_boolean_literal(span, true)
// Check node types
if let Expression::BinaryExpression(e) = expr {
// work with binary expression
}
Remember
- Size is the primary goal
- Correctness is non-negotiable
- Document assumptions clearly
- Test with real-world code
- Learn from other minifiers