10000 feat(dbg-swc): Add auto-reducer for the minifier (#4654) · swc-project/swc@c8818b0 · GitHub
[go: up one dir, main page]

Skip to content

Commit c8818b0

Browse files
authored
feat(dbg-swc): Add auto-reducer for the minifier (#4654)
1 parent f63be2f commit c8818b0

File tree

11 files changed

+233
-73
lines changed

11 files changed

+233
-73
lines changed

Cargo.lock

Lines changed: 13 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/dbg-swc/.gitignore

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,7 @@
1-
*.output.js
1+
*.output.js
2+
input.js
3+
*.orig
4+
5+
*.txt
6+
7+
.data/

crates/dbg-swc/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ name = "dbg-swc"
1515
anyhow = "1.0.57"
1616
clap = { version = "3", features = ["derive"] }
1717
rayon = "1.5.2"
18+
sha1 = "0.10.1"
1819
swc_atoms = { version = "0.2.11", path = "../swc_atoms" }
1920
swc_common = { version = "0.18.0", features = [
2021
"concurrent",

crates/dbg-swc/scripts/check-size.sh

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#!/usr/bin/env bash
2+
set -eu
3+
4+
cargo run -- minify ensure-size --no-terser > list.txt
5+
cat list.txt | xargs -L 1 cargo run -- minify reduce

crates/dbg-swc/src/main.rs

Lines changed: 76 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,24 @@
22

33
use std::{env, str::FromStr, sync::Arc};
44

5-
use anyhow::Result;
5+
use anyhow::{bail, Result};
66
use clap::{StructOpt, Subcommand};
77
use swc_common::{
88
errors::{ColorConfig, HANDLER},
99
Globals, SourceMap, GLOBALS,
1010
};
11+
use swc_ecma_minifier::option::MinifyOptions;
12+
use swc_ecma_transforms_base::fixer::fixer;
13+
use swc_ecma_visit::VisitMutWith;
1114
use swc_error_reporters::handler::{try_with_handler, HandlerOpts};
1215
use tracing_subscriber::EnvFilter;
1316

14-
use self::{bundle::BundleCommand, minify::MinifyCommand, test::TestCommand};
17+
use self::{
18+
bundle::BundleCommand,
19+
minify::MinifyCommand,
20+
test::TestCommand,
21+
util::{parse_js, print_js},
22+
};
1523

1624
mod bundle;
1725
mod minify;
@@ -34,7 +42,7 @@ enum Cmd {
3442
Test(TestCommand),
3543
}
3644

37-
fn main() -> Result<()> {
45+
fn init() -> Result<()> {
3846
let log_env =
3947
env::var("RUST_LOG").unwrap_or_else(|_| "info,swc_ecma_minifier=warn,swc_timer=off".into());
4048

@@ -49,10 +57,74 @@ fn main() -> Result<()> {
4957

5058
tracing::subscriber::set_global_default(logger)?;
5159

52-
let args = AppArgs::parse();
60+
Ok(())
61+
}
62+
63+
fn main() -> Result<()> {
64+
init()?;
5365

5466
let cm = Arc::new(SourceMap::default());
5567

68+
if env::var("CREDUCE_COMPARE").unwrap_or_default() == "1" {
69+
return try_with_handler(
70+
cm.clone(),
71+
HandlerOpts {
72+
color: ColorConfig::Always,
73+
skip_filename: false,
74+
},
75+
|handler| {
76+
GLOBALS.set(&Globals::default(), || {
77+
HANDLER.set(handler, || {
78+
//
79+
80+
let fm = cm.load_file("input.js".as_ref())?;
81+
82+
let m = parse_js(fm)?;
83+
84+
let mut m = {
85+
swc_ecma_minifier::optimize(
86+
m.module,
87+
cm.clone(),
88+
None,
89+
None,
90+
&MinifyOptions {
91+
compress: Some(Default::default()),
92+
mangle: Some(Default::default()),
93+
..Default::default()
94+
},
95+
&swc_ecma_minifier::option::ExtraOptions {
96+
unresolved_mark: m.unresolved_mark,
97+
top_level_mark: m.top_level_mark,
98+
},
99+
)
100+
};
101+
102+
m.visit_mut_with(&mut fixer(None));
103+
104+
let swc_output = print_js(cm.clone(), &m, true)?;
105+
106+
let esbuild_output =
107+
self::util::minifier::get_esbuild_output("input.js".as_ref(), true)?;
108+
109+
if swc_output.len() > esbuild_output.len() {
110+
return Ok(());
111+
}
112+
113+
println!(
114+
"swc size = {}, esbuild size = {}",
115+
swc_output.len(),
116+
esbuild_output.len()
117+
);
118+
119+
bail!("We don't care about this file")
120+
})
121+
})
122+
},
123+
);
124+
}
125+
126+
let args = AppArgs::parse();
127+
56128
try_with_handler(
57129
cm.clone(),
58130
HandlerOpts {

crates/dbg-swc/src/minify/compare.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,7 @@ use swc_ecma_minifier::option::MinifyOptions;
1111
use swc_ecma_transforms_base::fixer::fixer;
1212
use swc_ecma_visit::VisitMutWith;
1313

14-
use super::get_esbuild_output;
15-
use crate::util::{parse_js, print_js};
14+
use crate::util::{minifier::get_esbuild_output, parse_js, print_js};
1615

1716
/// Opens vscode for diffing output of swc minifier and terser/esbuild
1817
#[derive(Debug, Args)]

crates/dbg-swc/src/minify/ensure_size.rs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,10 @@ use swc_ecma_transforms_base::fixer::fixer;
1212
use swc_ecma_visit::VisitMutWith;
1313
use tracing::info;
1414

15-
use crate::{
16-
minify::{get_esbuild_output, get_terser_output},
17-
util::{all_js_files, parse_js, print_js, wrap_task},
15+
use crate::util::{
16+
all_js_files,
17+
minifier::{get_esbuild_output, get_terser_output},
18+
parse_js, print_js, wrap_task,
1819
};
1920

2021
/// Ensure that we are performing better than other minification tools.
@@ -36,7 +37,7 @@ impl EnsureSize {
3637
pub fn run(self, cm: Arc<SourceMap>) -> Result<()> {
3738
let all_files = all_js_files(&self.path)?;
3839

39-
dbg!(&all_files);
40+
info!("Using {} files", all_files.len());
4041

4142
let results = GLOBALS.with(|globals| {
4243
all_files
@@ -50,7 +51,7 @@ impl EnsureSize {
5051
return Ok(());
5152
}
5253
for report in &results {
53-
dbg!(&report);
54+
println!("{}", report.fm.name);
5455
}
5556

5657
bail!("found some issues")
@@ -90,7 +91,7 @@ impl EnsureSize {
9091
};
9192

9293
let swc_no_mangle = {
93-
let mut minified_mangled = {
94+
let mut minified_no_mangled = {
9495
let m = i.module.clone();
9596

9697
swc_ecma_minifier::optimize(
@@ -110,9 +111,9 @@ impl EnsureSize {
110111
)
111112
};
112113

113-
minified_mangled.visit_mut_with(&mut fixer(None));
114+
minified_no_mangled.visit_mut_with(&mut fixer(None));
114115

115-
print_js(cm, &minified_mangled, true).context("failed to convert ast to code")?
116+
print_js(cm, &minified_no_mangled, true).context("failed to convert ast to code")?
116117
};
117118

118119
// eprintln!("The output size of swc minifier: {}", code_mangled.len());

crates/dbg-swc/src/minify/mod.rs

Lines changed: 6 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,80 +1,29 @@
1-
use std::{
2-
path::Path,
3-
process::{Command, Stdio},
4-
sync::Arc,
5-
};
1+
use std::sync::Arc;
62

7-
use anyhow::{bail, Context, Result};
3+
use anyhow::Result;
84
use clap::Subcommand;
95
use swc_common::SourceMap;
106

11-
use self::{compare::CompareCommand, ensure_size::EnsureSize};
12-
use crate::util::wrap_task;
7+
use self::{compare::CompareCommand, ensure_size::EnsureSize, reduce::ReduceCommand};
138

149
mod compare;
1510
mod ensure_size;
11+
mod reduce;
1612

1713
/// Minify a javascript file.
1814
#[derive(Debug, Subcommand)]
1915
pub enum MinifyCommand {
16+
Reduce(ReduceCommand),
2017
Compare(CompareCommand),
2118
EnsureSize(EnsureSize),
2219
}
2320

2421
impl MinifyCommand {
2522
pub fn run(self, cm: Arc<SourceMap>) -> Result<()> {
2623
match self {
24+
MinifyCommand::Reduce(cmd) => cmd.run(cm),
2725
MinifyCommand::EnsureSize(cmd) => cmd.run(cm),
2826
MinifyCommand::Compare(cmd) => cmd.run(cm),
2927
}
3028
}
3129
}
32-
33-
fn get_terser_output(file: &Path, compress: bool, mangle: bool) -> Result<String> {
34-
wrap_task(|| {
35-
let mut cmd = Command::new("terser");
36-
cmd.stderr(Stdio::inherit());
37-
38-
if compress {
39-
cmd.arg("--compress");
40-
}
41-
if mangle {
42-
cmd.arg("--mangle");
43-
}
44-
cmd.arg("--");
45-
cmd.arg(file);
46-
47-
let output = cmd.output().context("failed to get output")?;
48-
49-
if !output.status.success() {
50-
bail!("failed to run terser");
51-
}
52-
53-
String::from_utf8(output.stdout).context("terser emitted non-utf8 string")
54-
})
55-
.with_context(|| format!("failed to get output of {} from terser", file.display()))
56-
}
57-
58-
fn get_esbuild_output(file: &Path, mangle: bool) -> Result<String> {
59-
wrap_task(|| {
60-
let mut cmd = Command::new("esbuild");
61-
cmd.stderr(Stdio::inherit());
62-
63-
cmd.arg(file);
64-
65-
if mangle {
66-
cmd.arg("--minify");
67-
} else {
68-
cmd.arg("--minify-syntax").arg("--minify-whitespace");
69-
}
70-
71-
let output = cmd.output().context("failed to get output")?;
72-
73-
if !output.status.success() {
74-
bail!("failed to run esbuild");
75-
}
76-
77-
String::from_utf8(output.stdout).context("esbuild emitted non-utf8 string")
78-
})
79-
.with_context(|| format!("failed to get output of {} from esbuild", file.display()))
80-
}

crates/dbg-swc/src/minify/reduce.rs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
use std::{
2+
env::current_exe,
3+
fs::{self, create_dir_all, read_to_string},
4+
path::{Path, PathBuf},
5+
process::Command,
6+
sync::Arc,
7+
};
8+
9+
use anyhow::{Context, Result};
10+
use clap::Args;
11+
use sha1::{Digest, Sha1};
12+
use swc_common::SourceMap;
13+
14+
#[derive(Debug, Args)]
15+
pub struct ReduceCommand {
16+
pub path: PathBuf,
17+
}
18+
19+
impl ReduceCommand {
20+
pub fn run(self, _cm: Arc<SourceMap>) -> Result<()> {
21+
fs::copy(&self.path, "input.js").context("failed to copy")?;
22+
23+
let mut c = Command::new("creduce");
24+
c.env("CREDUCE_COMPARE", "1");
25+
let exe = current_exe()?;
26+
c.arg(&exe);
27+
c.arg("input.js");
28+
c.status().context("failed to run creduce")?;
29+
30+
move_to_data_dir("input.js".as_ref())?;
31+
32+
Ok(())
33+
}
34+
}
35+
36+
fn move_to_data_dir(input_path: &Path) -> Result<PathBuf> {
37+
let src = read_to_string(input_path).context("failed to read input file")?;
38+
39+
// create a Sha1 object
40+
let mut hasher = Sha1::new();
41+
42+
// process input message
43+
hasher.update(src.as_bytes());
44+
45+
// acquire hash digest in the form of GenericArray,
46+
// which in this case is equivalent to [u8; 20]
47+
let result = hasher.finalize();
48+
let hash_str = format!("{:x}", result);
49+
50+
create_dir_all(".data").context("failed to create `.data`")?;
51+
52+
let to = PathBuf::from(format!(".data/{}.js", hash_str));
53+
fs::copy(input_path, &to).context("failed to copy")?;
54+
55+
Ok(to)
56+
}

0 commit comments

Comments
 (0)
0