Skip to content

Commit c75578b

Browse files
authoredFeb 20, 2025··
refactor(es/minifier): Remove CompileUnit to simplify (#10055)
**Description:** This type disturbs the transition to the core visitor.
1 parent f0f842d commit c75578b

File tree

7 files changed

+58
-352
lines changed

7 files changed

+58
-352
lines changed
 

‎.changeset/silver-spoons-joke.md

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
swc_ecma_minifier: minor
3+
swc_core: minor
4+
---
5+
6+
refactor(es/minifier): Remove `CompileUnit` to simplify

‎crates/swc_ecma_minifier/src/compress/mod.rs

+20-62
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ use swc_ecma_ast::*;
1111
use swc_ecma_transforms_optimization::simplify::{
1212
dead_branch_remover, expr_simplifier, ExprSimplifierConfig,
1313
};
14-
use swc_ecma_usage_analyzer::{analyzer::UsageAnalyzer, marks::Marks};
15-
use swc_ecma_visit::{noop_visit_mut_type, visit_mut_pass, VisitMut, VisitMutWith, VisitWith};
14+
use swc_ecma_usage_analyzer::marks::Marks;
15+
use swc_ecma_visit::{visit_mut_pass, VisitMutWith, VisitWith};
1616
use swc_timer::timer;
1717
use tracing::{debug, error};
1818

@@ -23,8 +23,8 @@ use crate::{
2323
debug::{dump, AssertValid},
2424
mode::Mode,
2525
option::{CompressOptions, MangleOptions},
26-
program_data::{analyze, ProgramData},
27-
util::{now, unit::CompileUnit},
26+
program_data::analyze,
27+
util::{force_dump_program, now},
2828
};
2929

3030
mod hoist_decls;
@@ -37,7 +37,7 @@ pub(crate) fn compressor<'a, M>(
3737
options: &'a CompressOptions,
3838
mangle_options: Option<&'a MangleOptions>,
3939
mode: &'a M,
40-
) -> impl 'a + VisitMut
40+
) -> impl 'a + Pass
4141
where
4242
M: Mode,
4343
{
@@ -52,7 +52,7 @@ where
5252
};
5353

5454
(
55-
visit_mut_pass(compressor),
55+
compressor,
5656
Optional {
5757
enabled: options.evaluate || options.side_effects,
5858
visitor: visit_mut_pass(expr_simplifier(
@@ -81,14 +81,14 @@ impl CompilerPass for Compressor<'_> {
8181
}
8282
}
8383

84+
impl Pass for Compressor<'_> {
85+
fn process(&mut self, program: &mut Program) {
86+
self.optimize_unit_repeatedly(program);
87+
}
88+
}
89+
8490
impl Compressor<'_> {
85-
fn optimize_unit_repeatedly<N>(&mut self, n: &mut N)
86-
where
87-
N: CompileUnit
88-
+ VisitWith<UsageAnalyzer<ProgramData>>
89-
+ for<'aa> VisitMutWith<Compressor<'aa>>
90-
+ VisitWith<AssertValid>,
91-
{
91+
fn optimize_unit_repeatedly(&mut self, n: &mut Program) {
9292
trace_op!(
9393
"Optimizing a compile unit within `{:?}`",
9494
thread::current().name()
@@ -105,7 +105,7 @@ impl Compressor<'_> {
105105
},
106106
&data,
107107
);
108-
n.apply(&mut v);
108+
n.visit_mut_with(&mut v);
109109
self.changed |= v.changed();
110110
}
111111

@@ -129,13 +129,7 @@ impl Compressor<'_> {
129129
}
130130

131131
/// Optimize a module. `N` can be [Module] or [FnExpr].
132-
fn optimize_unit<N>(&mut self, n: &mut N)
133-
where
134-
N: CompileUnit
135-
+ VisitWith<UsageAnalyzer<ProgramData>>
136-
+ for<'aa> VisitMutWith<Compressor<'aa>>
137-
+ VisitWith<AssertValid>,
138-
{
132+
fn optimize_unit(&mut self, n: &mut Program) {
139133
let _timer = timer!("optimize", pass = self.pass);
140134

141135
if self.options.passes != 0 && self.options.passes < self.pass {
@@ -150,7 +144,7 @@ impl Compressor<'_> {
150144
error!("Seems like there's an infinite loop");
151145
}
152146

153-
let code = n.force_dump();
147+
let code = force_dump_program(n);
154148

155149
if self.dump_for_infinite_loop.contains(&code) {
156150
let mut msg = String::new();
@@ -189,7 +183,7 @@ impl Compressor<'_> {
189183
let start = n.dump();
190184

191185
let mut visitor = expr_simplifier(self.marks.unresolved_mark, ExprSimplifierConfig {});
192-
n.apply(&mut visitor);
186+
n.visit_mut_with(&mut visitor);
193187

194188
self.changed |= visitor.changed();
195189
if visitor.changed() {
@@ -240,7 +234,7 @@ impl Compressor<'_> {
240234
debug_infinite_loop: self.pass >= 20,
241235
},
242236
);
243-
n.apply(&mut visitor);
237+
n.visit_mut_with(&mut visitor);
244238

245239
self.changed |= visitor.changed();
246240

@@ -276,7 +270,7 @@ impl Compressor<'_> {
276270
self.mode,
277271
!self.dump_for_infinite_loop.is_empty(),
278272
);
279-
n.apply(&mut visitor);
273+
n.visit_mut_with(&mut visitor);
280274

281275
self.changed |= visitor.changed();
282276

@@ -291,7 +285,7 @@ impl Compressor<'_> {
291285
let start_time = now();
292286

293287
let mut v = dead_branch_remover(self.marks.unresolved_mark);
294-
n.apply(&mut v);
288+
n.visit_mut_with(&mut v);
295289

296290
if let Some(start_time) = start_time {
297291
let end_time = Instant::now();
@@ -320,42 +314,6 @@ impl Compressor<'_> {
320314
}
321315
}
322316

323-
impl VisitMut for Compressor<'_> {
324-
noop_visit_mut_type!();
325-
326-
fn visit_mut_script(&mut self, n: &mut Script) {
327-
self.optimize_unit_repeatedly(n);
328-
}
329-
330-
fn visit_mut_module(&mut self, n: &mut Module) {
331-
self.optimize_unit_repeatedly(n);
332-
}
333-
334-
fn visit_mut_module_items(&mut self, stmts: &mut Vec<ModuleItem>) {
335-
stmts.retain(|stmt| match stmt {
336-
ModuleItem::Stmt(Stmt::Empty(..)) => false,
337-
ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(ExportDecl {
338-
decl: Decl::Var(v),
339-
..
340-
}))
341-
| ModuleItem::Stmt(Stmt::Decl(Decl::Var(v)))
342-
if v.decls.is_empty() =>
343-
{
344-
false
345-
}
346-
_ => true,
347-
});
348-
}
349-
350-
fn visit_mut_stmts(&mut self, stmts: &mut Vec<Stmt>) {
351-
stmts.retain(|stmt| match stmt {
352-
Stmt::Empty(..) => false,
353-
Stmt::Decl(Decl::Var(v)) if v.decls.is_empty() => false,
354-
_ => true,
355-
});
356-
}
357-
}
358-
359317
#[cfg(feature = "debug")]
360318
#[derive(PartialEq, Eq)]
361319
struct DebugUsingDisplay<'a>(pub &'a str);

‎crates/swc_ecma_minifier/src/debug.rs

+1-189
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,9 @@
1-
use std::{
2-
io::Write,
3-
process::{Command, Stdio},
4-
};
5-
61
use swc_common::{sync::Lrc, SourceMap, SyntaxContext};
72
use swc_ecma_ast::*;
83
use swc_ecma_codegen::{text_writer::JsWriter, Emitter};
9-
use swc_ecma_transforms_base::{fixer::fixer, hygiene::hygiene};
10-
pub use swc_ecma_transforms_optimization::{debug_assert_valid, AssertValid};
4+
pub use swc_ecma_transforms_optimization::AssertValid;
115
use swc_ecma_utils::{drop_span, DropSpan};
126
use swc_ecma_visit::{noop_visit_mut_type, VisitMut, VisitMutWith};
13-
use tracing::debug;
147

158
pub(crate) struct Debugger {}
169

@@ -61,184 +54,3 @@ where
6154

6255
String::from_utf8(buf).unwrap()
6356
}
64-
65-
/// Invokes code using node.js.
66-
///
67-
/// If the cargo feature `debug` is disabled or the environment variable
68-
/// `SWC_RUN` is not `1`, this function is noop.
69-
pub(crate) fn invoke_module(module: &Module) {
70-
debug_assert_valid(module);
71-
72-
let _noop_sub = tracing::subscriber::set_default(tracing::subscriber::NoSubscriber::default());
73-
74-
let should_run =
75-
cfg!(debug_assertions) && cfg!(feature = "debug") && option_env!("SWC_RUN") == Some("1");
76-
let should_check = cfg!(debug_assertions) && option_env!("SWC_CHECK") == Some("1");
77-
78-
if !should_run && !should_check {
79-
return;
80-
}
81-
82-
let module = Program::Module(module.clone())
83-
.apply(hygiene())
84-
.apply(fixer(None));
85-
let module = drop_span(module);
86-
87-
let mut buf = Vec::new();
88-
let cm = Lrc::new(SourceMap::default());
89-
90-
{
91-
let mut emitter = Emitter {
92-
cfg: Default::default(),
93-
cm: cm.clone(),
94-
comments: None,
95-
wr: Box::new(JsWriter::new(cm, "\n", &mut buf, None)),
96-
};
97-
98-
emitter.emit_program(&module).unwrap();
99-
}
100-
101-
let code = String::from_utf8(buf).unwrap();
102-
103-
debug!("Validating with node.js:\n{}", code);
104-
105-
if should_check {
106-
let mut child = Command::new("node")
107-
.arg("-")
108-
.arg("--check")
109-
.stdin(Stdio::piped())
110-
.stdout(Stdio::piped())
111-
.stderr(Stdio::piped())
112-
.spawn()
113-
.expect("failed to spawn node");
114-
115-
{
116-
let child_stdin = child.stdin.as_mut().unwrap();
117-
child_stdin
118-
.write_all(code.as_bytes())
119-
.expect("failed to write");
120-
}
121-
122-
let output = child.wait_with_output().expect("failed to check syntax");
123-
124-
if !output.status.success() {
125-
panic!(
126-
"[SWC_CHECK] Failed to validate code:\n{}\n===== ===== ===== ===== =====\n{}\n{}",
127-
code,
128-
String::from_utf8_lossy(&output.stdout),
129-
String::from_utf8_lossy(&output.stderr),
130-
);
131-
}
132-
} else {
133-
let output = Command::new("node")
134-
.arg("--input-type=module")
135-
.arg("-e")
136-
.arg(&code)
137-
.output()
138-
.expect("[SWC_RUN] failed to validate code using `node`");
139-
if !output.status.success() {
140-
panic!(
141-
"[SWC_RUN] Failed to validate code:\n{}\n===== ===== ===== ===== =====\n{}\n{}",
142-
code,
143-
String::from_utf8_lossy(&output.stdout),
144-
String::from_utf8_lossy(&output.stderr),
145-
);
146-
}
147-
148-
tracing::info!(
149-
"[SWC_RUN]\n{}\n{}",
150-
code,
151-
String::from_utf8_lossy(&output.stdout)
152-
)
153-
}
154-
}
155-
156-
/// Invokes code using node.js.
157-
///
158-
/// If the cargo feature `debug` is disabled or the environment variable
159-
/// `SWC_RUN` is not `1`, this function is noop.
160-
pub(crate) fn invoke_script(script: &Script) {
161-
debug_assert_valid(script);
162-
163-
let _noop_sub = tracing::subscriber::set_default(tracing::subscriber::NoSubscriber::default());
164-
165-
let should_run =
166-
cfg!(debug_assertions) && cfg!(feature = "debug") && option_env!("SWC_RUN") == Some("1");
167-
let should_check = cfg!(debug_assertions) && option_env!("SWC_CHECK") == Some("1");
168-
169-
if !should_run && !should_check {
170-
return;
171-
}
172-
173-
let script = Program::Script(script.clone())
174-
.apply(hygiene())
175-
.apply(fixer(None));
176-
let script = drop_span(script);
177-
178-
let mut buf = Vec::new();
179-
let cm = Lrc::new(SourceMap::default());
180-
181-
{
182-
let mut emitter = Emitter {
183-
cfg: Default::default(),
184-
cm: cm.clone(),
185-
comments: None,
186-
wr: Box::new(JsWriter::new(cm, "\n", &mut buf, None)),
187-
};
188-
189-
emitter.emit_program(&script).unwrap();
190-
}
191-
192-
let code = String::from_utf8(buf).unwrap();
193-
194-
debug!("Validating with node.js:\n{}", code);
195-
196-
if should_check {
197-
let mut child = Command::new("node")
198-
.arg("-")
199-
.arg("--check")
200-
.stdin(Stdio::piped())
201-
.stdout(Stdio::piped())
202-
.stderr(Stdio::piped())
203-
.spawn()
204-
.expect("failed to spawn node");
205-
206-
{
207-
let child_stdin = child.stdin.as_mut().unwrap();
208-
child_stdin
209-
.write_all(code.as_bytes())
210-
.expect("failed to write");
211-
}
212-
213-
let output = child.wait_with_output().expect("failed to check syntax");
214-
215-
if !output.status.success() {
216-
panic!(
217-
"[SWC_CHECK] Failed to validate code:\n{}\n===== ===== ===== ===== =====\n{}\n{}",
218-
code,
219-
String::from_utf8_lossy(&output.stdout),
220-
String::from_utf8_lossy(&output.stderr),
221-
);
222-
}
223-
} else {
224-
let output = Command::new("node")
225-
.arg("-e")
226-
.arg(&code)
227-
.output()
228-
.expect("[SWC_RUN] failed to validate code using `node`");
229-
if !output.status.success() {
230-
panic!(
231-
"[SWC_RUN] Failed to validate code:\n{}\n===== ===== ===== ===== =====\n{}\n{}",
232-
code,
233-
String::from_utf8_lossy(&output.stdout),
234-
String::from_utf8_lossy(&output.stderr),
235-
);
236-
}
237-
238-
tracing::info!(
239-
"[SWC_RUN]\n{}\n{}",
240-
code,
241-
String::from_utf8_lossy(&output.stdout)
242-
)
243-
}
244-
}

‎crates/swc_ecma_minifier/src/eval.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use crate::{
1919
pub struct Evaluator {
2020
expr_ctx: ExprCtx,
2121

22-
module: Module,
22+
program: Program,
2323
marks: Marks,
2424
data: Eval,
2525
/// We run minification only once.
@@ -36,7 +36,7 @@ impl Evaluator {
3636
remaining_depth: 3,
3737
},
3838

39-
module,
39+
program: Program::Module(module),
4040
marks,
4141
data: Default::default(),
4242
done: Default::default(),
@@ -88,7 +88,7 @@ impl Evaluator {
8888
let marks = self.marks;
8989
let data = self.data.clone();
9090
//
91-
self.module.visit_mut_with(&mut compressor(
91+
self.program.mutate(&mut compressor(
9292
marks,
9393
&CompressOptions {
9494
// We should not drop unused variables.

‎crates/swc_ecma_minifier/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ pub fn optimize(
186186
{
187187
let _timer = timer!("compress ast");
188188

189-
n.visit_mut_with(&mut compressor(
189+
n.mutate(&mut compressor(
190190
marks,
191191
c,
192192
options.mangle.as_ref(),

‎crates/swc_ecma_minifier/src/util/mod.rs

+27-3
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@ use rustc_hash::FxHashSet;
66
use swc_atoms::Atom;
77
use swc_common::{util::take::Take, Span, Spanned, DUMMY_SP};
88
use swc_ecma_ast::*;
9-
use swc_ecma_utils::{stack_size::maybe_grow_default, ModuleItemLike, StmtLike, Value};
10-
use swc_ecma_visit::{noop_visit_type, visit_obj_and_computed, Visit, VisitWith};
9+
use swc_ecma_transforms_base::{fixer::fixer, hygiene::hygiene};
10+
use swc_ecma_utils::{stack_size::maybe_grow_default, DropSpan, ModuleItemLike, StmtLike, Value};
11+
use swc_ecma_visit::{noop_visit_type, visit_mut_pass, visit_obj_and_computed, Visit, VisitWith};
1112

1213
pub(crate) mod base54;
1314
pub(crate) mod size;
1415
pub(crate) mod sort;
15-
pub(crate) mod unit;
1616

1717
pub(crate) fn make_number(span: Span, value: f64) -> Expr {
1818
trace_op!("Creating a numeric literal");
@@ -520,6 +520,30 @@ impl Visit for EvalFinder {
520520
}
521521
}
522522

523+
#[allow(unused)]
524+
pub(crate) fn dump_program(p: &Program) -> String {
525+
#[cfg(feature = "debug")]
526+
{
527+
force_dump_program(p)
528+
}
529+
#[cfg(not(feature = "debug"))]
530+
{
531+
String::new()
532+
}
533+
}
534+
535+
pub(crate) fn force_dump_program(p: &Program) -> String {
536+
let _noop_sub = tracing::subscriber::set_default(tracing::subscriber::NoSubscriber::default());
537+
538+
crate::debug::dump(
539+
&p.clone()
540+
.apply(fixer(None))
541+
.apply(hygiene())
542+
.apply(visit_mut_pass(DropSpan {})),
543+
true,
544+
)
545+
}
546+
523547
#[cfg(feature = "concurrent")]
524548
#[macro_export(local_inner_macros)]
525549
#[allow(clippy::crate_in_macro_def)]

‎crates/swc_ecma_minifier/src/util/unit.rs

-94
This file was deleted.

0 commit comments

Comments
 (0)
Please sign in to comment.