-
-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
9f985a2
commit 9645d90
Showing
11 changed files
with
787 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,3 +5,4 @@ yarn-error.log | |
coverage | ||
.idea | ||
bundle | ||
.DS_Store |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,6 +12,7 @@ | |
"**/bundle", | ||
"**/stub", | ||
"rollup.config.js", | ||
"benchmark", | ||
"**/*.config.*" | ||
], | ||
"branches": 100, | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,5 +4,5 @@ | |
"eslint/convert-rc-to-flat": "on" | ||
} | ||
}, | ||
"ignore": ["bundle"] | ||
"ignore": ["bundle", "benchmark"] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
source/* | ||
!source/example* | ||
result |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
# Benchmark | ||
|
||
This is a performance benchmark of the following bundlers: | ||
|
||
- Bun | ||
- esbuild | ||
- Terser | ||
- @putoutjs/minify | ||
|
||
To run the benchmark: | ||
|
||
- Need to install bun globally (https://bun.sh/docs/installation) | ||
|
||
```sh | ||
$ npm install | ||
$ node index.js | ||
``` | ||
|
||
## Results | ||
|
||
The `real` results, as run on a 13-inch M1 Macbook air: | ||
|
||
Time in ms | ||
``` | ||
┌──────────┬─────┬─────────┬────────┬─────────────────┐ | ||
│ (index) │ bun │ esbuild │ terser │ putoutjs_minify │ | ||
├──────────┼─────┼─────────┼────────┼─────────────────┤ | ||
│ react │ 58 │ 50 │ 230 │ 2509 │ | ||
│ solidjs │ 21 │ 16 │ 270 │ 12735 │ | ||
│ treejs │ 74 │ 100 │ 1787 │ │ | ||
│ lodash │ 21 │ 27 │ 603 │ 108901 │ | ||
│ vue │ 60 │ 62 │ 1455 │ │ | ||
│ angular │ 32 │ 41 │ 1320 │ │ | ||
│ jquery │ 18 │ 23 │ 548 │ 80481 │ | ||
│ example1 │ 42 │ 35 │ 108 │ 330 │ | ||
└──────────┴─────┴─────────┴────────┴─────────────────┘ | ||
``` | ||
|
||
Size in bytes | ||
``` | ||
┌──────────┬───────────────────┬───────────────────┬───────────────────┬──────────────────┬──────────────────┐ | ||
│ (index) │ original │ bun │ esbuild │ terser │ putoutjs_minify │ | ||
├──────────┼───────────────────┼───────────────────┼───────────────────┼──────────────────┼──────────────────┤ | ||
│ react │ '10751 (100.0%)' │ '10553 (98.2%)' │ '10644 (99.0%)' │ '10391 (96.7%)' │ '10052 (93.5%)' │ | ||
│ solidjs │ '28537 (100.0%)' │ '21888 (76.7%)' │ '20553 (72.0%)' │ '28202 (98.8%)' │ '21886 (76.7%)' │ | ||
│ treejs │ '677935 (100.0%)' │ '680368 (100.4%)' │ '657528 (97.0%)' │ '677573 (99.9%)' │ │ | ||
│ lodash │ '73015 (100.0%)' │ '72551 (99.4%)' │ '72189 (98.9%)' │ '70751 (96.9%)' │ '73688 (100.9%)' │ | ||
│ vue │ '196075 (100.0%)' │ '196443 (100.2%)' │ '193091 (98.5%)' │ '195200 (99.6%)' │ │ | ||
│ angular │ '177368 (100.0%)' │ '178187 (100.5%)' │ '177834 (100.3%)' │ '176388 (99.4%)' │ │ | ||
│ jquery │ '87533 (100.0%)' │ '87451 (99.9%)' │ '87119 (99.5%)' │ '86958 (99.3%)' │ '85889 (98.1%)' │ | ||
│ example1 │ '853 (100.0%)' │ '494 (57.9%)' │ '490 (57.4%)' │ '481 (56.4%)' │ '482 (56.5%)' │ | ||
└──────────┴───────────────────┴───────────────────┴───────────────────┴──────────────────┴──────────────────┘ | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import {minify} from '@putout/minify'; | ||
import { readFileSync, writeFileSync } from 'node:fs' | ||
|
||
const body = readFileSync(process.argv[2], 'utf8'); | ||
writeFileSync(process.argv[3], minify(body)); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,155 @@ | ||
import { get } from "node:https"; | ||
import { statSync, writeFileSync, createWriteStream, rmSync } from "node:fs"; | ||
import { execSync } from 'node:child_process' | ||
|
||
const listFiles = { | ||
react: { | ||
url: "https://cdn.jsdelivr.net/npm/[email protected]/umd/react.production.min.js", | ||
}, | ||
solidjs: { | ||
url: "https://cdn.jsdelivr.net/npm/[email protected]/dist/solid.min.js", | ||
}, | ||
treejs: { | ||
url: "https://cdn.jsdelivr.net/npm/[email protected]/build/three.module.min.js", | ||
}, | ||
lodash: { | ||
url: "https://cdn.jsdelivr.net/npm/[email protected]/lodash.min.js", | ||
}, | ||
vue: { | ||
url: "https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.global.min.js", | ||
}, | ||
angular: { | ||
url: "https://cdn.jsdelivr.net/npm/[email protected]/angular.min.js", | ||
}, | ||
jquery: { | ||
url: 'https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.min.js', | ||
}, | ||
example1: { | ||
file: "./source/example1.js", | ||
} | ||
}; | ||
|
||
const compressors = { | ||
bun: 'bun build --minify {dist} --outfile {out}', | ||
esbuild: './node_modules/.bin/esbuild {dist} --bundle --minify --outfile={out}', | ||
terser: './node_modules/.bin/terser {dist} --compress --mangle --comments false -o {out}', | ||
'putoutjs_minify': 'node ./cli/minify.js {dist} {out}' | ||
}; | ||
|
||
let debug = () => {}; | ||
// debug = console.log; | ||
|
||
function fileExists(path) { | ||
try { | ||
const s = statSync(path); | ||
debug(`File ${path} exists ${s.size} bytes`) | ||
return s.size > 0; | ||
} catch (e) { | ||
debug(`File ${path} does not exist`) | ||
return false; | ||
} | ||
} | ||
|
||
async function downloadFile(url, dest) { | ||
if (fileExists(dest)) { | ||
debug(`File ${dest} already exists`) | ||
return; | ||
} | ||
return new Promise((resolve, reject) => { | ||
debug(`Downloading ${url} to ${dest}`); | ||
get(url, (res) => { | ||
const file = createWriteStream(dest, ""); | ||
res.pipe(file); | ||
res.on("end", () => { | ||
debug(`Downloaded ${url} to ${dest}`); | ||
resolve(); | ||
}); | ||
}); | ||
}); | ||
} | ||
|
||
function fileFromUrl(url) { | ||
return `./source/${url}.js` | ||
} | ||
|
||
async function download() { | ||
for (const [key, value] of Object.entries(listFiles)) { | ||
if (!value.url) continue; | ||
const { url } = value; | ||
const dest = fileFromUrl(key); | ||
await downloadFile(url, dest); | ||
} | ||
} | ||
|
||
function getPathFromFile(file) { | ||
return listFiles[file].file || fileFromUrl(file); | ||
} | ||
|
||
function removeFile(filePath) { | ||
rmSync(filePath, { force: true }); | ||
} | ||
|
||
async function compareTask(file) { | ||
const dist = getPathFromFile(file); | ||
const result = {}; | ||
for (const [key, value] of Object.entries(compressors)) { | ||
const out = `./result/${file}-${key}.js`; | ||
removeFile(out); | ||
const cmd = value.replace('{dist}', dist).replace('{out}', out); | ||
debug(`Running: ${cmd}`); | ||
let endTime = 0; | ||
try { | ||
const startTime = Date.now(); | ||
execSync(cmd, { stdio: 'pipe', encoding: 'utf8' }); | ||
endTime = Date.now() - startTime; | ||
} catch (e) { | ||
console.error(`Error running ${key}: ${e.message} ${e.stderr}`); | ||
continue; | ||
} | ||
const fileSize = statSync(out).size; | ||
result[key] = { | ||
time: endTime, | ||
size: fileSize, | ||
} | ||
console.log(`File: ${file} Compressor: ${key} Time: ${endTime}ms Size: ${fileSize} bytes`) | ||
} | ||
return result; | ||
} | ||
|
||
function convertMap(fn, obj) { | ||
return Object.fromEntries(Object.entries(obj).map(([k, v]) => [k, fn(v, k, obj)]).filter(([k, v]) => v !== undefined)); | ||
} | ||
|
||
function convertTable(obj, key) { | ||
return convertMap(convertMap.bind(null, (v) => v[key]), obj); | ||
} | ||
|
||
async function compare() { | ||
const result = {}; | ||
for (const key of Object.keys(listFiles)) { | ||
result[key] = await compareTask(key); | ||
const originalSize = statSync(getPathFromFile(key)).size; | ||
result[key] = { | ||
original: { size: originalSize }, | ||
...result[key] | ||
} | ||
} | ||
return result; | ||
} | ||
|
||
async function main() { | ||
await download(); | ||
const result = await compare(); | ||
debug(result) | ||
const resultTime = convertTable(result, 'time'); | ||
debug(resultTime) | ||
console.log('Time in ms') | ||
console.table(resultTime); | ||
const resultSize = convertMap(convertMap.bind(null, (v, k, obj) => `${v} (${(100 * v / obj.original).toFixed(1)}%)`),convertTable(result, 'size')); | ||
|
||
debug(resultSize) | ||
console.log('Size in bytes') | ||
console.table(resultSize); | ||
} | ||
|
||
main(); |
Oops, something went wrong.