mirror of
https://github.com/aphrody-labs/oxc.git
synced 2026-10-17 12:56:09 +00:00
docs(minifier): align guides with current implementation (#27584)
This commit is contained in:
1 parent
59472c5170
commit
c993555ede
8 files changed
+204
-144
No files matched your search
@@ -8,19 +8,22 @@ Build the best JavaScript minifier: smallest output, 100% correct, reasonably fa
|
||||
|
||||
### Architecture
|
||||
|
||||
- Fixed-point iteration in `PeepholeOptimizations::run_in_loop`
|
||||
- Fixed-point iteration in `Compressor::run_in_loop`
|
||||
- Arena allocation via `oxc_allocator`
|
||||
- 17+ optimizations in `src/peephole/`
|
||||
- Optimizations dispatched by `src/peephole/mod.rs`
|
||||
- Pass completion and incremental semantic updates in `src/compression_pass.rs`
|
||||
|
||||
### Key Files
|
||||
|
||||
```
|
||||
src/
|
||||
├── lib.rs # Entry point
|
||||
├── compressor.rs # Pipeline orchestration
|
||||
├── ctx.rs # Shared utilities
|
||||
├── state.rs # Optimization state
|
||||
├── peephole/
|
||||
├── lib.rs # Entry point
|
||||
├── compressor.rs # Pipeline orchestration
|
||||
├── compression_pass.rs # Pass completion and semantic updates
|
||||
├── traverse_context/ # Traversal, AST mutation, and ECMAScript utilities
|
||||
├── state.rs # Configuration and per-pass changes
|
||||
├── symbol_state.rs # Symbol values, metadata, and liveness
|
||||
└── peephole/
|
||||
│ ├── mod.rs # Optimization dispatch
|
||||
│ └── *.rs # Individual optimizations
|
||||
```
|
||||
@@ -53,7 +56,7 @@ Before selecting verification checks, read the [verification guidance](../../.ag
|
||||
#### Optimization Structure
|
||||
|
||||
```rust
|
||||
pub fn optimize_something(expr: &mut Expression, ctx: &mut Ctx) {
|
||||
pub fn optimize_something<'a>(expr: &mut Expression<'a>, ctx: &mut TraverseCtx<'a>) {
|
||||
// Check if optimization applies
|
||||
if !can_optimize(expr, ctx) {
|
||||
return;
|
||||
@@ -65,19 +68,24 @@ pub fn optimize_something(expr: &mut Expression, ctx: &mut Ctx) {
|
||||
}
|
||||
```
|
||||
|
||||
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.
|
||||
Use the typed `ctx.replace_*` helpers when replacing a slot. They record
|
||||
discarded references and direct `eval` calls as well as requesting another pass.
|
||||
When moving the old node into the replacement, use `replace_expression_with` or
|
||||
`replace_statement_with`; report discarded subtrees inside the closure with
|
||||
`ctx.drop_*`, and do not report nodes moved into the result as dropped.
|
||||
|
||||
For in-place edits that retain all subtrees (operand swaps or field flips), call
|
||||
`ctx.notice_change()`. When removing a subtree from a collection or an optional
|
||||
field, call the corresponding `ctx.drop_*` helper before discarding it.
|
||||
`notice_change()` alone does not update semantic references. If a raw slot write
|
||||
is required because no typed helper exists, record discarded subtrees, call
|
||||
`ctx.notice_change()`, and explain why.
|
||||
|
||||
#### Traversal Hook
|
||||
|
||||
```rust
|
||||
// In peephole/mod.rs
|
||||
// Within impl<'a> Traverse<'a> for PeepholeOptimizations
|
||||
fn exit_expression(&mut self, expr: &mut Expression<'a>, ctx: &mut TraverseCtx<'a>) {
|
||||
match expr {
|
||||
Expression::BinaryExpression(_) => {
|
||||
@@ -119,16 +127,16 @@ fn exit_expression(&mut self, expr: &mut Expression<'a>, ctx: &mut TraverseCtx<'
|
||||
|
||||
```bash
|
||||
# Debug conformance failures
|
||||
cargo coverage --debug
|
||||
cargo coverage minifier --debug
|
||||
|
||||
# Test single file
|
||||
cargo run -p oxc_minifier --example minifier test.js
|
||||
cargo run -p oxc_minifier --example minifier -- test.js
|
||||
|
||||
# Test idempotency
|
||||
cargo run -p oxc_minifier --example minifier test.js --twice
|
||||
cargo run -p oxc_minifier --example minifier -- test.js --twice
|
||||
```
|
||||
|
||||
### Key Utilities in `ctx.rs`
|
||||
### Key Utilities in `traverse_context/`
|
||||
|
||||
- `eval_binary()` - Evaluate binary expressions
|
||||
- `value_to_expr()` - Convert constant to AST node
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# Oxc Minifier
|
||||
|
||||
Next-generation JavaScript/TypeScript minifier achieving best-in-class compression.
|
||||
JavaScript minifier focused on small output and performance. Transform TypeScript,
|
||||
TSX, and JSX to JavaScript before minification.
|
||||
|
||||
## Inspiration
|
||||
|
||||
@@ -12,7 +13,7 @@ Next-generation JavaScript/TypeScript minifier achieving best-in-class compressi
|
||||
## Key Features
|
||||
|
||||
- Maximum compression through exhaustive optimizations
|
||||
- 100% correctness with comprehensive testing
|
||||
- Correctness testing under the [documented assumptions](./docs/ASSUMPTIONS.md)
|
||||
- Fixed-point iteration for optimal size
|
||||
- Arena allocation for performance
|
||||
|
||||
@@ -21,28 +22,43 @@ Next-generation JavaScript/TypeScript minifier achieving best-in-class compressi
|
||||
See [`tasks/minsize`](../../tasks/minsize) for compression benchmarks.
|
||||
|
||||
- Matching/beating esbuild on many libraries
|
||||
- Full test262, Babel, TypeScript conformance
|
||||
- Minifier idempotency checks on selected test262 and Babel cases
|
||||
|
||||
## Usage
|
||||
|
||||
```rust
|
||||
use oxc_allocator::Allocator;
|
||||
use oxc_codegen::{Codegen, CodegenOptions};
|
||||
use oxc_minifier::{Minifier, MinifierOptions};
|
||||
use oxc_parser::Parser;
|
||||
use oxc_span::SourceType;
|
||||
|
||||
let options = MinifierOptions::default();
|
||||
let minifier = Minifier::new(options);
|
||||
let result = minifier.minify(&mut program);
|
||||
let allocator = Allocator::default();
|
||||
let parsed = Parser::new(&allocator, "const x = 1 + 1; console.log(x);", SourceType::mjs())
|
||||
.parse();
|
||||
assert!(parsed.diagnostics.is_empty());
|
||||
let mut program = parsed.program;
|
||||
|
||||
let result = Minifier::new(MinifierOptions::default()).minify(&allocator, &mut program);
|
||||
let output = Codegen::new()
|
||||
.with_options(CodegenOptions { minify: true, ..CodegenOptions::default() })
|
||||
.with_scoping(result.scoping)
|
||||
.with_private_member_mappings(result.class_private_mappings)
|
||||
.build(&program);
|
||||
println!("{}", output.code);
|
||||
```
|
||||
|
||||
## Testing Infrastructure
|
||||
|
||||
- `just minsize` - Track compression benchmarks
|
||||
- `cargo coverage` - Conformance tests (test262, Babel, TypeScript)
|
||||
- `cargo coverage minifier` - Minifier idempotency tests (test262 and Babel)
|
||||
- `cargo coverage runtime` - Execute eligible test262 cases with Node.js
|
||||
- `tasks/e2e` - Real-world E2E testing
|
||||
|
||||
## Development
|
||||
|
||||
- `just test` - Run all tests
|
||||
- `cargo run -p oxc_minifier --example minifier` - Try the minifier
|
||||
- `cargo run -p oxc_minifier --example minifier -- test.js` - Try the minifier
|
||||
|
||||
## Key Dependencies
|
||||
|
||||
@@ -53,7 +69,7 @@ let result = minifier.minify(&mut program);
|
||||
## Documentation
|
||||
|
||||
- [Architecture](./docs/ARCHITECTURE.md) - Design and components
|
||||
- [Optimizations](./docs/OPTIMIZATIONS.md) - Complete optimization catalog
|
||||
- [Optimizations](./docs/OPTIMIZATIONS.md) - Optimization overview
|
||||
- [Assumptions](./docs/ASSUMPTIONS.md) - Code assumptions for optimization
|
||||
- [Correctness](./docs/CORRECTNESS.md) - Testing and validation
|
||||
- [Roadmap](./docs/ROADMAP.md) - Development plan
|
||||
|
||||
@@ -6,7 +6,7 @@ Achieve maximum compression through comprehensive optimizations while maintainin
|
||||
|
||||
### Size Optimization Strategy
|
||||
|
||||
- Fixed-point iteration until no more improvements
|
||||
- Fixed-point iteration until no more changes or the iteration limit is reached
|
||||
- Combine multiple optimization techniques
|
||||
- Learn from all major minifiers
|
||||
- Apply optimizations exhaustively
|
||||
@@ -63,7 +63,7 @@ Key responsibilities:
|
||||
|
||||
### Peephole Optimizations (`peephole/`)
|
||||
|
||||
17+ transformation passes including:
|
||||
Transformation modules dispatched together during a peephole traversal, including:
|
||||
|
||||
- Constant folding
|
||||
- Dead code elimination
|
||||
@@ -73,54 +73,56 @@ Key responsibilities:
|
||||
|
||||
Each optimization implements transformations in the AST traversal visitor pattern.
|
||||
|
||||
### Context (`ctx.rs`)
|
||||
### Context (`traverse_context/`)
|
||||
|
||||
Shared utilities for optimizations:
|
||||
The crate's `TraverseCtx<'a>` alias refers to `MinifierTraverseCtx<'a>`.
|
||||
It provides the AST builder, ancestry, scoping, and `MinifierState`.
|
||||
ECMAScript evaluation and mutation helpers are in `traverse_context/ecma_context.rs`.
|
||||
|
||||
- AST manipulation helpers
|
||||
- Constant evaluation
|
||||
- Side effect analysis
|
||||
- Semantic utilities
|
||||
Use typed `replace_*` helpers for replacements and `drop_*` helpers for discarded
|
||||
subtrees. They record removed references and dropped direct `eval` calls as well
|
||||
as requesting another pass. Use `replace_*_with` when moving an old node into its
|
||||
replacement; the closure must report discarded subtrees. `notice_change()` is
|
||||
for in-place edits that retain their subtrees.
|
||||
|
||||
```rust
|
||||
pub struct Ctx<'a, 'b> {
|
||||
// Provides access to:
|
||||
// - AST builder
|
||||
// - Scoping information
|
||||
// - Symbol values
|
||||
// - Optimization options
|
||||
}
|
||||
```
|
||||
### State Management (`state.rs`, `symbol_state.rs`)
|
||||
|
||||
### State Management (`state.rs`)
|
||||
`MinifierState` stores configuration, per-body state, private-member usage, and
|
||||
per-pass changes. `SymbolState` groups symbol values, metadata, and liveness.
|
||||
|
||||
Tracks optimization state:
|
||||
### Pass Completion (`compression_pass.rs`)
|
||||
|
||||
- Symbol values
|
||||
- Changed flags
|
||||
- Pure functions
|
||||
- Source type
|
||||
After normalization and each peephole traversal, pass completion prunes removed
|
||||
semantic references, refreshes direct-eval scope flags when needed, and updates
|
||||
function reachability. Its outcome drives `Compressor::run_in_loop`; debug
|
||||
guards check for references that were incorrectly removed or left behind.
|
||||
|
||||
## Optimization Pipeline
|
||||
|
||||
```text
|
||||
1. Parse JavaScript (caller)
|
||||
2. Optional property-name mangling
|
||||
└─> Collect, assign, and rewrite before compression
|
||||
3. Compression (if enabled)
|
||||
├─> Build semantic scoping
|
||||
├─> Normalize and complete the normalization pass
|
||||
└─> Repeat peephole traversal and pass completion
|
||||
until no revisit is needed or the iteration limit is reached
|
||||
4. Optional identifier/private-member mangling
|
||||
└─> Rebuild semantics for the compressed AST
|
||||
5. Code generation (caller)
|
||||
└─> Pass scoping and class_private_mappings from MinifierReturn to Codegen
|
||||
```
|
||||
1. Parse and Build Semantic Model
|
||||
└─> SemanticBuilder creates scoping and symbols
|
||||
|
||||
2. Normalization Pass
|
||||
└─> Convert to canonical form for optimizations
|
||||
`Minifier::minify` selects full compression. `Minifier::dce` selects tree-shaking
|
||||
compression, which keeps folds needed to expose dead branches but skips transforms
|
||||
whose only purpose is shorter syntax. Mangling remains controlled by the supplied
|
||||
`MinifierOptions`.
|
||||
|
||||
3. Peephole Optimization Loop
|
||||
└─> Apply all optimizations
|
||||
└─> Check if any changes made
|
||||
└─> Repeat until fixed-point (no changes)
|
||||
|
||||
4. Optional Mangling
|
||||
└─> Rename variables for size
|
||||
|
||||
5. Code Generation
|
||||
└─> Output optimized JavaScript
|
||||
```
|
||||
Callers of `Compressor::build_with_scoping` or
|
||||
`dead_code_elimination_with_scoping` must supply scoping whose resolved-reference
|
||||
lists match the current AST. Added references missing from those lists can cause
|
||||
incorrect output; stale extra references can prevent optimizations.
|
||||
|
||||
## Memory Management
|
||||
|
||||
@@ -130,7 +132,7 @@ Tracks optimization state:
|
||||
|
||||
## Traversal Strategy
|
||||
|
||||
Using `oxc_traverse` for AST walking:
|
||||
Using the crate's generated traversal through `minifier_traverse.rs`:
|
||||
|
||||
- Enter/exit hooks for each node type
|
||||
- Bottom-up transformations (exit handlers)
|
||||
|
||||
@@ -216,9 +216,26 @@ Property rewriting runs before compression. Computed keys that compression later
|
||||
such as `['f' + 'oo_']`, are not revisited and can diverge from an eligible `obj.foo_` occurrence.
|
||||
Exclude or reserve property names that are constructed this way.
|
||||
|
||||
### No Reliance on Function.prototype.name
|
||||
### No Reliance on Function or Class Names
|
||||
|
||||
Code doesn't depend on function names being preserved. This assumption is held by default. This can be changed by settings `keepNames` option.
|
||||
Code does not depend on function or class names being preserved by default.
|
||||
In the Rust API, set `CompressOptions::keep_names` and, when identifier mangling
|
||||
is enabled, `MangleOptions::keep_names` for the names you need to preserve.
|
||||
When both stages are enabled in the Node.js API, configure both options:
|
||||
|
||||
- `compress.keepNames` takes an object with Boolean `function` and `class` fields.
|
||||
- `mangle.keepNames` takes a Boolean (for both kinds of names) or an object with
|
||||
Boolean `function` and `class` fields.
|
||||
|
||||
For example, to preserve both function and class names during compression and
|
||||
identifier mangling:
|
||||
|
||||
```javascript
|
||||
const options = {
|
||||
compress: { keepNames: { function: true, class: true } },
|
||||
mangle: { keepNames: true },
|
||||
};
|
||||
```
|
||||
|
||||
```javascript
|
||||
// The minifier assumes this never happens:
|
||||
@@ -231,6 +248,7 @@ if (myFunc.name !== "myFunc") throw Error();
|
||||
Optional assumptions can be configured in the minifier options if your code requires different behavior.
|
||||
|
||||
```rust
|
||||
// Selected fields; see src/options.rs for the complete definitions.
|
||||
pub struct CompressOptions {
|
||||
// Control optimization behavior
|
||||
pub drop_console: bool,
|
||||
@@ -261,15 +279,11 @@ pub struct TreeShakeOptions {
|
||||
To ensure your code works with these assumptions:
|
||||
|
||||
1. **Test thoroughly**: Run your test suite on minified code
|
||||
2. **Use conformance tests**: `cargo coverage` runs test262, Babel, TypeScript tests
|
||||
3. **Node.js compatibility**: The minifier is validated against Node.js compatibility tables
|
||||
2. **Check idempotency**: `cargo coverage minifier` checks selected test262 and Babel cases
|
||||
3. **Check runtime behavior**: `cargo coverage runtime` executes eligible test262 cases with Node.js
|
||||
4. **Try real-world code**: Test with your actual application
|
||||
5. **Report issues**: If valid code breaks, file an issue
|
||||
|
||||
### Node.js Compatibility Testing
|
||||
|
||||
The minifier includes comprehensive validation against Node.js compatibility tables to ensure optimizations work correctly across different Node.js versions and environments.
|
||||
|
||||
## When Assumptions Don't Hold
|
||||
|
||||
If your code violates these assumptions, you may:
|
||||
|
||||
@@ -2,16 +2,19 @@
|
||||
|
||||
## Our Commitment
|
||||
|
||||
The Oxc minifier maintains correctness through comprehensive testing and validation.
|
||||
The Oxc minifier aims to preserve JavaScript behavior under the
|
||||
[documented assumptions](./ASSUMPTIONS.md). Tests provide regression coverage;
|
||||
they do not prove correctness for every program.
|
||||
|
||||
## Validation Infrastructure
|
||||
|
||||
### Conformance Testing
|
||||
|
||||
- **test262**: Full ECMAScript specification compliance
|
||||
- **Babel**: Modern JavaScript patterns and transforms
|
||||
- **TypeScript**: Type-aware transformations
|
||||
- **Real-world**: Top npm packages and frameworks
|
||||
`cargo coverage minifier` runs compression/code-generation idempotency checks on
|
||||
selected test262 and Babel cases. The test262 runner skips parse-negative and
|
||||
`noStrict` cases; the Babel runner skips expected failures and TypeScript sources.
|
||||
The minifier has no TypeScript conformance suite or type-aware transformations.
|
||||
Transform TypeScript, TSX, and JSX to JavaScript before minification.
|
||||
|
||||
Run conformance tests:
|
||||
|
||||
@@ -41,15 +44,16 @@ just minsize
|
||||
# See tasks/minsize/minsize.snap for results
|
||||
```
|
||||
|
||||
### Differential Testing
|
||||
### Runtime Testing
|
||||
|
||||
- Input vs output behavioral equivalence
|
||||
- Cross-validation with other minifiers
|
||||
- Fuzzing with randomly generated valid JavaScript
|
||||
`cargo coverage runtime` runs eligible test262 cases through codegen, transformer,
|
||||
and minifier pipelines and executes the outputs with Node.js (>= 22).
|
||||
`tasks/e2e` also contains Node.js runtime tests for the transformer and minifier.
|
||||
Idempotency alone does not establish behavioral equivalence.
|
||||
|
||||
### Semantic Preservation
|
||||
|
||||
Every optimization preserves:
|
||||
Within the documented assumptions, optimizations are intended to preserve:
|
||||
|
||||
- Variable scoping and bindings
|
||||
- Execution order and side effects
|
||||
@@ -61,8 +65,11 @@ Every optimization preserves:
|
||||
|
||||
### Temporal Dead Zones (TDZ)
|
||||
|
||||
Code must not violate a TDZ. Preserving the resulting `ReferenceError` is not
|
||||
guaranteed; see [No TDZ Violation](./ASSUMPTIONS.md#no-tdz-violation).
|
||||
|
||||
```javascript
|
||||
// Correctly preserves TDZ semantics
|
||||
// Outside the minifier's assumptions: this code violates the TDZ.
|
||||
{
|
||||
console.log(x); // ReferenceError
|
||||
let x = 1;
|
||||
@@ -108,7 +115,8 @@ function* gen() {
|
||||
|
||||
### Type Coercion
|
||||
|
||||
All JavaScript coercion rules are preserved using `oxc_ecmascript` conversions:
|
||||
Constant evaluation and side-effect analysis use `oxc_ecmascript` conversions,
|
||||
subject to the documented assumptions about coercion purity and exceptions:
|
||||
|
||||
- String coercion (`ToJsString`)
|
||||
- Number coercion (`ToNumber`)
|
||||
@@ -131,35 +139,25 @@ cargo test -p oxc_minifier
|
||||
Real-world code testing:
|
||||
|
||||
```bash
|
||||
cd tasks/e2e
|
||||
pnpm test
|
||||
# From the repository root, build the bindings first
|
||||
pnpm --filter "./napi/minify" --filter "./napi/transform" run build-test
|
||||
pnpm --dir tasks/e2e test
|
||||
```
|
||||
|
||||
### Idempotency Testing
|
||||
|
||||
Minifying twice produces same result:
|
||||
The conformance runner checks whether a second compression produces the same
|
||||
output. The example can also report whether a particular input is idempotent:
|
||||
|
||||
```bash
|
||||
cargo run -p oxc_minifier --example minifier test.js --twice
|
||||
cargo run -p oxc_minifier --example minifier -- test.js --twice
|
||||
```
|
||||
|
||||
## Correctness Tools
|
||||
## Semantic Bookkeeping Checks
|
||||
|
||||
### Semantic Validator
|
||||
|
||||
Validates that transformations preserve semantics.
|
||||
|
||||
### AST Differ
|
||||
|
||||
Shows exact changes made to the AST.
|
||||
|
||||
### Behavior Comparison
|
||||
|
||||
Compares runtime behavior of original vs minified code.
|
||||
|
||||
### Side Effect Tracker
|
||||
|
||||
Ensures side effects occur in correct order.
|
||||
Debug builds run over-prune and under-prune guards in `src/compression_pass.rs`
|
||||
to catch inconsistencies between live AST references and semantic scoping.
|
||||
These guards check bookkeeping, not arbitrary runtime equivalence.
|
||||
|
||||
## Known Limitations
|
||||
|
||||
@@ -180,11 +178,6 @@ If you find correctness issues:
|
||||
|
||||
## Continuous Validation
|
||||
|
||||
Our CI runs:
|
||||
|
||||
- Full conformance test suite
|
||||
- Size benchmarks
|
||||
- Real-world package tests
|
||||
- Fuzzing tests
|
||||
|
||||
Every PR must pass all correctness tests.
|
||||
Check the current [CI workflow](../../../.github/workflows/ci.yml) for
|
||||
configured checks. Choose local verification using the repository's
|
||||
[verification guidance](../../../.agents/verification.md).
|
||||
@@ -1,10 +1,11 @@
|
||||
# Optimization Catalog
|
||||
|
||||
Complete list of optimizations for maximum size reduction.
|
||||
Overview of implemented optimization families. Examples illustrate individual
|
||||
transforms; other passes may further simplify or remove the shown output.
|
||||
|
||||
Many optimizations rely on [`oxc_ecmascript`](../../oxc_ecmascript) for ECMAScript operations like constant evaluation, type conversion, and side effect analysis.
|
||||
|
||||
## Current Optimizations (18)
|
||||
## Current Optimizations
|
||||
|
||||
### Constant Folding
|
||||
|
||||
@@ -72,7 +73,7 @@ a && b();
|
||||
!(!x || !y);
|
||||
|
||||
// After
|
||||
x && y;
|
||||
!!(x && y);
|
||||
|
||||
// Before
|
||||
!!true;
|
||||
@@ -115,7 +116,7 @@ obj.property;
|
||||
|
||||
### Template Literal Optimization
|
||||
|
||||
**Module**: `inline.rs`
|
||||
**Module**: `fold_constants.rs`, `substitute_alternate_syntax.rs`
|
||||
**Size Impact**: Medium
|
||||
**Description**: Simplifies template literals
|
||||
|
||||
@@ -137,11 +138,9 @@ obj.property;
|
||||
|
||||
```javascript
|
||||
// Before
|
||||
"test".indexOf("e");
|
||||
Math.pow(2, 3);
|
||||
|
||||
// After
|
||||
"test".indexOf("e"); // or optimized form
|
||||
2 ** 3;
|
||||
```
|
||||
|
||||
@@ -234,19 +233,21 @@ x ? true : false;
|
||||
|
||||
```javascript
|
||||
// Before
|
||||
if (x === true) {
|
||||
if (!!x) {
|
||||
run();
|
||||
}
|
||||
|
||||
// After
|
||||
if (x) {
|
||||
run();
|
||||
}
|
||||
```
|
||||
|
||||
### Variable Inlining
|
||||
|
||||
**Module**: `inline.rs`
|
||||
**Module**: `inline.rs`, `minimize_statements.rs`
|
||||
**Size Impact**: Medium
|
||||
**Description**: Inlines single-use variables
|
||||
**Description**: Propagates known constants and inlines eligible single-use variables
|
||||
|
||||
```javascript
|
||||
// Before
|
||||
@@ -257,7 +258,27 @@ console.log(x);
|
||||
console.log(5);
|
||||
```
|
||||
|
||||
## Planned Optimizations
|
||||
### Switch Statement Optimization
|
||||
|
||||
**Module**: `minimize_switch_statements.rs`
|
||||
**Description**: Removes unreachable cases for known discriminants; related switch
|
||||
folding is dispatched from `peephole/mod.rs`.
|
||||
|
||||
### Unused Private Member Removal
|
||||
|
||||
**Module**: `remove_unused_private_members.rs`
|
||||
**Description**: Removes eligible unused private class members.
|
||||
|
||||
### IIFE Simplification
|
||||
|
||||
**Module**: `substitute_alternate_syntax.rs`
|
||||
**Description**: Simplifies eligible immediately invoked function expressions,
|
||||
including empty bodies and parameterless single-expression arrow functions.
|
||||
|
||||
## Ideas for Further Optimization
|
||||
|
||||
These are possible future directions, not implemented features or commitments.
|
||||
The minifier accepts JavaScript; TypeScript enum lowering belongs in the transformer.
|
||||
|
||||
### From Closure Compiler
|
||||
|
||||
@@ -269,7 +290,6 @@ console.log(5);
|
||||
|
||||
### From Terser
|
||||
|
||||
- **Switch statement optimization**: Simplify switch statements
|
||||
- **Advanced array/object patterns**: Recognize and optimize patterns
|
||||
- **String optimizations**: Join strings, optimize concatenation
|
||||
- **RegExp optimizations**: Simplify regular expressions
|
||||
@@ -278,11 +298,11 @@ console.log(5);
|
||||
|
||||
- **CSS-in-JS optimization**: Optimize styled components
|
||||
- **Import optimization**: Remove unused imports
|
||||
- **Enum inlining**: Replace enum access with values
|
||||
- **Enum-like object inlining**: Replace JavaScript object property access with values
|
||||
|
||||
## Size Optimization Techniques
|
||||
|
||||
1. **Multiple passes**: Run optimizations until fixed-point
|
||||
1. **Multiple passes**: Run optimizations until fixed-point or the iteration limit
|
||||
2. **Optimization ordering**: Some optimizations enable others
|
||||
3. **Pattern matching**: Recognize common code patterns
|
||||
4. **Syntactic substitution**: Always prefer shorter forms
|
||||
@@ -297,4 +317,5 @@ Some optimizations enable others:
|
||||
- **Inlining** → enables further constant folding
|
||||
- **Dead code removal** → enables more inlining
|
||||
|
||||
The fixed-point iteration ensures all optimization opportunities are found.
|
||||
Repeated passes let implemented optimizations expose further opportunities, subject
|
||||
to safety checks, options, and the iteration limit.
|
||||
@@ -1,5 +1,9 @@
|
||||
# Development Roadmap
|
||||
|
||||
This document distinguishes implemented foundations from possible future work.
|
||||
Unchecked items are ideas, not committed features or delivery dates. The
|
||||
[optimization catalog](./OPTIMIZATIONS.md) describes current transforms.
|
||||
|
||||
## Phase 1: Foundation ✓
|
||||
|
||||
- [x] Basic peephole optimizations
|
||||
@@ -8,7 +12,7 @@
|
||||
- [x] Test infrastructure (minsize, coverage, e2e)
|
||||
- [x] Fixed-point iteration
|
||||
|
||||
## Phase 2: Complete Optimization Suite ✓
|
||||
## Phase 2: Optimization Suite
|
||||
|
||||
- [x] Port safe optimizations from Closure Compiler
|
||||
- [x] Port core optimizations from Terser/UglifyJS
|
||||
@@ -17,24 +21,24 @@
|
||||
- [x] Template literal optimization
|
||||
- [x] Array/object patterns
|
||||
|
||||
## Phase 3: Advanced Optimizations (Current)
|
||||
## Phase 3: Further Optimization Ideas
|
||||
|
||||
- [ ] Function inlining (when provably safe)
|
||||
- [ ] Switch statement optimization
|
||||
- [ ] Broader function inlining (limited IIFE simplification is already implemented)
|
||||
- [x] Switch statement optimization (known-discriminant case removal and switch folding)
|
||||
- [ ] Advanced string concatenation (extending `oxc_ecmascript` string operations)
|
||||
- [ ] Enum unboxing
|
||||
- [ ] Property collapsing
|
||||
- [ ] Better RegExp optimization
|
||||
- [ ] Loop optimizations
|
||||
- [ ] Broader loop optimizations (while/for normalization and for-statement transforms exist)
|
||||
- [ ] Cross-module optimization
|
||||
- [ ] Perfect side effect analysis (extending `oxc_ecmascript` capabilities)
|
||||
- [ ] More precise side effect analysis (extending `oxc_ecmascript` capabilities)
|
||||
- [ ] Advanced DCE with escape analysis
|
||||
- [ ] Type-aware optimizations (from TS types)
|
||||
- [ ] Additional JavaScript value analysis (the minifier does not consume TypeScript types)
|
||||
- [ ] Framework-specific optimizations (React, Vue, Angular)
|
||||
|
||||
## Phase 4: Production Ready
|
||||
## Further Infrastructure Ideas
|
||||
|
||||
- [ ] Differential testing framework
|
||||
- [ ] Broader differential testing (test262 runtime checks and Node.js E2E tests already exist)
|
||||
- [ ] Fuzzing infrastructure
|
||||
- [ ] Performance optimization
|
||||
- [ ] Source map improvements
|
||||
@@ -43,7 +47,7 @@
|
||||
## Goals
|
||||
|
||||
**Size**: Beat Closure Compiler, smallest output for top npm packages
|
||||
**Correctness**: 100% test262/Babel/TypeScript conformance
|
||||
**Correctness**: Preserve JavaScript behavior under documented assumptions, with test262/Babel idempotency and runtime regression coverage
|
||||
**Performance**: < 2x slower than esbuild, < 10x faster than Terser
|
||||
**Adoption**: Integration in major build tools
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
//! # Oxc Minifier
|
||||
//!
|
||||
//! High-performance JavaScript/TypeScript minifier focused on maximum compression.
|
||||
//! High-performance JavaScript minifier focused on maximum compression.
|
||||
//! Transform TypeScript, TSX, and JSX to JavaScript before minification.
|
||||
//!
|
||||
//! ## Overview
|
||||
//!
|
||||
@@ -11,9 +12,10 @@
|
||||
//!
|
||||
//! ## Features
|
||||
//!
|
||||
//! - **Maximum Compression**: Fixed-point iteration ensures all optimization opportunities are found
|
||||
//! - **Comprehensive Optimizations**: 17+ transformation passes and growing
|
||||
//! - **100% Correct**: Extensive testing with test262, Babel, and TypeScript test suites
|
||||
//! - **Compression**: Repeated passes expose further optimization opportunities
|
||||
//! - **Comprehensive Optimizations**: Constant folding, dead code removal, and syntax simplification
|
||||
//! - **Correctness Testing**: Selected test262/Babel idempotency checks and Node.js runtime tests
|
||||
//! under the [documented assumptions](https://github.com/oxc-project/oxc/blob/main/crates/oxc_minifier/docs/ASSUMPTIONS.md)
|
||||
//! - **Fast**: Efficient algorithms and arena allocation for performance
|
||||
//!
|
||||
//! ## Example
|
||||
|
||||
Reference in new issue
Block a user