diff --git a/crates/swc/Cargo.toml b/crates/swc/Cargo.toml index 0c4f5f15fc4..f5cd43cdf04 100644 --- a/crates/swc/Cargo.toml +++ b/crates/swc/Cargo.toml @@ -116,6 +116,10 @@ name = "transform" harness = false name = "bugs" +[[bench]] +harness = false +name = "minify" + [[bench]] harness = false name = "typescript" diff --git a/crates/swc/benches/minify.rs b/crates/swc/benches/minify.rs new file mode 100644 index 00000000000..524602ef361 --- /dev/null +++ b/crates/swc/benches/minify.rs @@ -0,0 +1,84 @@ +/// Explicit extern crate to use allocator. +extern crate swc_node_base; + +use std::{path::PathBuf, sync::Arc}; + +use criterion::{black_box, criterion_group, criterion_main, Bencher, Criterion}; +use swc::{config::JsMinifyOptions, try_with_handler}; +use swc_common::{FilePathMapping, SourceMap}; + +fn mk() -> swc::Compiler { + let cm = Arc::new(SourceMap::new(FilePathMapping::empty())); + + swc::Compiler::new(cm) +} + +fn bench_minify(b: &mut Bencher, filename: &str) { + let c = mk(); + + c.run(|| { + b.iter(|| { + let fm = black_box( + c.cm.load_file( + &PathBuf::from("..") + .join("swc_ecma_minifier") + .join("benches") + .join("full") + .join(filename), + ) + .unwrap(), + ); + + let res = try_with_handler(c.cm.clone(), Default::default(), |handler| { + c.minify( + fm, + handler, + &JsMinifyOptions { + compress: true.into(), + mangle: true.into(), + format: Default::default(), + ecma: Default::default(), + keep_classnames: Default::default(), + keep_fnames: Default::default(), + module: Default::default(), + safari10: Default::default(), + toplevel: Default::default(), + source_map: Default::default(), + output_path: Default::default(), + inline_sources_content: Default::default(), + }, + ) + }) + .unwrap(); + + black_box(res); + }) + }); +} + +fn files_group(c: &mut Criterion) { + let mut group = c.benchmark_group("libraries"); + group.sample_size(10); + + let mut bench_file = |name: &str| { + group.bench_function(name, |b| { + bench_minify(b, &format!("{}.js", name)); + }); + }; + + bench_file("antd"); + bench_file("d3"); + bench_file("echarts"); + bench_file("jquery"); + bench_file("lodash"); + bench_file("moment"); + bench_file("react"); + bench_file("terser"); + bench_file("three"); + bench_file("typescript"); + bench_file("victory"); + bench_file("vue"); +} + +criterion_group!(benches, files_group); +criterion_main!(benches); diff --git a/crates/swc_ecma_minifier/src/compress/optimize/mod.rs b/crates/swc_ecma_minifier/src/compress/optimize/mod.rs index 94fb7cd67e3..10416f97169 100644 --- a/crates/swc_ecma_minifier/src/compress/optimize/mod.rs +++ b/crates/swc_ecma_minifier/src/compress/optimize/mod.rs @@ -245,18 +245,23 @@ impl Vars { N: for<'aa> VisitMutWith>, { let mut changed = false; - n.visit_mut_with(&mut MultiReplacer::new( - &mut self.simple_functions, - true, - MultiReplacerMode::OnlyCallee, - &mut changed, - )); - n.visit_mut_with(&mut MultiReplacer::new( - &mut self.vars_for_inlining, - false, - MultiReplacerMode::Normal, - &mut changed, - )); + if !self.simple_functions.is_empty() { + n.visit_mut_with(&mut MultiReplacer::new( + &mut self.simple_functions, + true, + MultiReplacerMode::OnlyCallee, + &mut changed, + )); + } + + if !self.vars_for_inlining.is_empty() { + n.visit_mut_with(&mut MultiReplacer::new( + &mut self.vars_for_inlining, + false, + MultiReplacerMode::Normal, + &mut changed, + )); + } changed } diff --git a/node-swc/benches/load.mjs b/node-swc/benches/load.mjs new file mode 100644 index 00000000000..394d777c0ad --- /dev/null +++ b/node-swc/benches/load.mjs @@ -0,0 +1 @@ +import '../../index.js'; diff --git a/node-swc/benches/minify.mjs b/node-swc/benches/minify.mjs new file mode 100644 index 00000000000..4261375f336 --- /dev/null +++ b/node-swc/benches/minify.mjs @@ -0,0 +1,11 @@ +import { minify } from '../../index.js'; +import { promises as fs } from 'fs'; + +const files = process.argv.slice(2); +const inputCode = await fs.readFile(files[0], 'utf8'); + +await minify(inputCode, { + compress: true, + mangle: true, + sourceMap: false, +}) \ No newline at end of file diff --git a/node-swc/src/binding.d.ts b/node-swc/src/binding.d.ts index cb7a0e7c482..c2f8263cd3c 100644 --- a/node-swc/src/binding.d.ts +++ b/node-swc/src/binding.d.ts @@ -3,6 +3,10 @@ /* auto-generated by NAPI-RS */ +export interface TransformOutput { + code: string + map?: string | undefined | null +} export function bundle(confItems: Buffer, signal?: AbortSignal | undefined | null): Promise<{ [index: string]: { code: string, map?: string } }> export function minify(code: Buffer, opts: Buffer, signal?: AbortSignal | undefined | null): Promise export function minifySync(code: Buffer, opts: Buffer): TransformOutput diff --git a/scripts/bench-node.sh b/scripts/bench-node.sh new file mode 100755 index 00000000000..5b5e1ed6a70 --- /dev/null +++ b/scripts/bench-node.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash + +set -eu + + +echo "Binary load time" +hyperfine --warmup 10 --runs 5 'node ./node-swc/benches/load.mjs' + +echo "Load + minify antd, all core" +hyperfine --warmup 5 --runs 5 "node ./node-swc/benches/minify.mjs $PWD/crates/swc_ecma_minifier/benches/full/antd.js" + +echo "Load + minify antd, 2 core" +hyperfine --warmup 5 --runs 5 "RAYON_NUM_THREADS=2 node ./node-swc/benches/minify.mjs $PWD/crates/swc_ecma_minifier/benches/full/antd.js" +