Skip to content

Commit d09c7ee

Browse files
committed
feat(minifier): add drop_labels feature (#14634)
Implemented `drop_labels` feature, which is implemented in [esbuild](https://esbuild.github.io/api/#drop-labels) and [rolldown](https://rolldown.rs/apis/config-options#droplabels). The plan is to use this in Rolldown.
1 parent 73f2cbb commit d09c7ee

File tree

6 files changed

+80
-0
lines changed

6 files changed

+80
-0
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/oxc_minifier/src/options.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use oxc_compat::EngineTargets;
2+
use rustc_hash::FxHashSet;
23

34
pub use oxc_ecmascript::side_effects::PropertyReadSideEffects;
45

@@ -44,6 +45,13 @@ pub struct CompressOptions {
4445
/// <https://rollupjs.org/configuration-options/#treeshake>
4546
pub treeshake: TreeShakeOptions,
4647

48+
/// Set of label names to drop from the code.
49+
///
50+
/// Labeled statements matching these names will be removed during minification.
51+
///
52+
/// Default: empty (no labels dropped)
53+
pub drop_labels: FxHashSet<String>,
54+
4755
/// Limit the maximum number of iterations for debugging purpose.
4856
pub max_iterations: Option<u8>,
4957
}
@@ -65,6 +73,7 @@ impl CompressOptions {
6573
sequences: true,
6674
unused: CompressOptionsUnused::Remove,
6775
treeshake: TreeShakeOptions::default(),
76+
drop_labels: FxHashSet::default(),
6877
max_iterations: None,
6978
}
7079
}
@@ -79,6 +88,7 @@ impl CompressOptions {
7988
sequences: true,
8089
unused: CompressOptionsUnused::Keep,
8190
treeshake: TreeShakeOptions::default(),
91+
drop_labels: FxHashSet::default(),
8292
max_iterations: None,
8393
}
8494
}
@@ -93,6 +103,7 @@ impl CompressOptions {
93103
sequences: false,
94104
unused: CompressOptionsUnused::Remove,
95105
treeshake: TreeShakeOptions::default(),
106+
drop_labels: FxHashSet::default(),
96107
max_iterations: None,
97108
}
98109
}

crates/oxc_minifier/src/peephole/remove_dead_code.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,13 @@ impl<'a> PeepholeOptimizations {
197197
pub fn try_fold_labeled(stmt: &mut Statement<'a>, ctx: &mut Ctx<'a, '_>) {
198198
let Statement::LabeledStatement(s) = stmt else { return };
199199
let id = s.label.name.as_str();
200+
201+
if ctx.options().drop_labels.contains(id) {
202+
*stmt = ctx.ast.statement_empty(s.span);
203+
ctx.state.changed = true;
204+
return;
205+
}
206+
200207
// Check the first statement in the block, or just the `break [id] ` statement.
201208
// Check if we need to remove the whole block.
202209
match &mut s.body {

crates/oxc_minifier/tests/peephole/dead_code_elimination.rs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use cow_utils::CowUtils;
2+
use rustc_hash::FxHashSet;
23

34
use oxc_allocator::Allocator;
45
use oxc_codegen::Codegen;
@@ -36,6 +37,18 @@ fn test_same(source_text: &str) {
3637
test(source_text, source_text);
3738
}
3839

40+
#[track_caller]
41+
fn test_with_options(source_text: &str, expected: &str, options: CompressOptions) {
42+
let allocator = Allocator::default();
43+
let source_type = SourceType::default();
44+
let mut ret = Parser::new(&allocator, source_text, source_type).parse();
45+
let program = &mut ret.program;
46+
Compressor::new(&allocator).dead_code_elimination(program, options);
47+
let result = Codegen::new().build(program).code;
48+
let expected = run(expected, source_type, None);
49+
assert_eq!(result, expected, "\nfor source\n{source_text}\nexpect\n{expected}\ngot\n{result}");
50+
}
51+
3952
#[test]
4053
fn dce_if_statement() {
4154
test("if (true) { foo }", "foo");
@@ -346,3 +359,48 @@ console.log([
346359
",
347360
);
348361
}
362+
363+
#[test]
364+
fn drop_labels() {
365+
let mut options = CompressOptions::dce();
366+
let mut drop_labels = FxHashSet::default();
367+
drop_labels.insert("PURE".to_string());
368+
options.drop_labels = drop_labels;
369+
370+
test_with_options("PURE: { foo(); bar(); }", "", options);
371+
}
372+
373+
#[test]
374+
fn drop_multiple_labels() {
375+
let mut options = CompressOptions::dce();
376+
let mut drop_labels = FxHashSet::default();
377+
drop_labels.insert("PURE".to_string());
378+
drop_labels.insert("TEST".to_string());
379+
options.drop_labels = drop_labels;
380+
381+
test_with_options(
382+
"PURE: { foo(); } TEST: { bar(); } OTHER: { baz(); }",
383+
"OTHER: baz();",
384+
options,
385+
);
386+
}
387+
388+
#[test]
389+
fn drop_labels_nested() {
390+
let mut options = CompressOptions::dce();
391+
let mut drop_labels = FxHashSet::default();
392+
drop_labels.insert("PURE".to_string());
393+
options.drop_labels = drop_labels;
394+
395+
test_with_options("PURE: { PURE: { foo(); } }", "", options);
396+
}
397+
398+
#[test]
399+
fn drop_labels_with_vars() {
400+
let mut options = CompressOptions::dce();
401+
let mut drop_labels = FxHashSet::default();
402+
drop_labels.insert("PURE".to_string());
403+
options.drop_labels = drop_labels;
404+
405+
test_with_options("PURE: { var x = 1; foo(x); }", "", options);
406+
}

napi/minify/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ oxc_span = { workspace = true }
3434

3535
napi = { workspace = true }
3636
napi-derive = { workspace = true }
37+
rustc-hash = { workspace = true }
3738

3839
[target.'cfg(not(any(target_os = "linux", target_os = "freebsd", target_arch = "arm", target_family = "wasm")))'.dependencies]
3940
mimalloc-safe = { workspace = true, optional = true, features = ["skip_collect_on_exit"] }

napi/minify/src/options.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use napi_derive::napi;
33

44
use oxc_compat::EngineTargets;
55
use oxc_minifier::TreeShakeOptions;
6+
use rustc_hash::FxHashSet;
67

78
#[napi(object)]
89
pub struct CompressOptions {
@@ -81,6 +82,7 @@ impl TryFrom<&CompressOptions> for oxc_minifier::CompressOptions {
8182
},
8283
keep_names: o.keep_names.as_ref().map(Into::into).unwrap_or_default(),
8384
treeshake: TreeShakeOptions::default(),
85+
drop_labels: FxHashSet::default(),
8486
max_iterations: o.max_iterations,
8587
})
8688
}

0 commit comments

Comments
 (0)