Generate benchmark graphs
This commit is contained in:
parent
e7fc519f05
commit
c9b0e7a50d
|
@ -1,6 +1,6 @@
|
||||||
# hyperbuild
|
# hyperbuild
|
||||||
|
|
||||||
A fast one-pass in-place HTML minifier written in Rust with advanced whitespace handling.
|
A fast one-pass in-place HTML minifier written in Rust with context-aware whitespace handling.
|
||||||
|
|
||||||
Available as:
|
Available as:
|
||||||
- CLI for Windows, macOS, and Linux.
|
- CLI for Windows, macOS, and Linux.
|
||||||
|
@ -13,6 +13,10 @@ Available as:
|
||||||
- No extra heap memory is allocated during processing, which increases performance.
|
- No extra heap memory is allocated during processing, which increases performance.
|
||||||
- Context-aware whitespace handling allows maximum minification while retaining wanted spaces.
|
- Context-aware whitespace handling allows maximum minification while retaining wanted spaces.
|
||||||
|
|
||||||
|
## Performance
|
||||||
|
|
||||||
|
![Chart showing speed of HTML minifiers](./bench/speed.png) ![Chart showing effectiveness of HTML minifiers](./bench/minification.png)
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
### CLI
|
### CLI
|
||||||
|
|
161
bench/bench.js
161
bench/bench.js
|
@ -1,37 +1,22 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const fs = require("fs");
|
|
||||||
const path = require("path");
|
|
||||||
const benchmark = require("benchmark");
|
const benchmark = require("benchmark");
|
||||||
|
const chartjs = require('chartjs-node');
|
||||||
|
const fs = require("fs");
|
||||||
const htmlMinifier = require("html-minifier");
|
const htmlMinifier = require("html-minifier");
|
||||||
const minimize = require("minimize");
|
|
||||||
const hyperbuild = require("hyperbuild");
|
const hyperbuild = require("hyperbuild");
|
||||||
|
const minimize = require("minimize");
|
||||||
|
const path = require("path");
|
||||||
|
|
||||||
const tests_dir = path.join(__dirname, "tests");
|
const testsDir = path.join(__dirname, "tests");
|
||||||
const tests = fs.readdirSync(tests_dir).map(name => ({
|
const tests = fs.readdirSync(testsDir).map(name => ({
|
||||||
name,
|
name,
|
||||||
content: fs.readFileSync(path.join(tests_dir, name), "utf8"),
|
content: fs.readFileSync(path.join(testsDir, name), "utf8"),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const sizes = {};
|
const programs = {
|
||||||
const setSize = (program, test, result) => {
|
'hyperbuild-nodejs': content => hyperbuild.minify(Buffer.from(content)),
|
||||||
console.log(`Received result for ${program} - ${test}`);
|
'html-minifier': content => htmlMinifier.minify(content, {
|
||||||
|
|
||||||
if (!sizes[test]) {
|
|
||||||
sizes[test] = {
|
|
||||||
original: {
|
|
||||||
result: tests.find(t => t.name === test).content.length,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
const original = sizes[test].original.result;
|
|
||||||
sizes[test][program] = {
|
|
||||||
result: result,
|
|
||||||
difference: `${((result - original) / original * 100).toFixed(2)}%`,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const htmlMinifierSettings = {
|
|
||||||
caseSensitive: false,
|
caseSensitive: false,
|
||||||
collapseBooleanAttributes: true,
|
collapseBooleanAttributes: true,
|
||||||
collapseInlineTagWhitespace: true,
|
collapseInlineTagWhitespace: true,
|
||||||
|
@ -64,32 +49,126 @@ const htmlMinifierSettings = {
|
||||||
sortClassName: true,
|
sortClassName: true,
|
||||||
trimCustomFragments: false,
|
trimCustomFragments: false,
|
||||||
useShortDoctype: true,
|
useShortDoctype: true,
|
||||||
|
}).length,
|
||||||
|
'minimize': content => new minimize().parse(content).length,
|
||||||
};
|
};
|
||||||
|
|
||||||
new benchmark.Suite()
|
const colours = [
|
||||||
.add("hyperbuild", () => {
|
{
|
||||||
for (const t of tests) {
|
backgroundColor: '#9ad0f5',
|
||||||
setSize("hyperbuild", t.name, hyperbuild.minify(Buffer.from(t.content)));
|
borderColor: '#47aaec',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
backgroundColor: '#ffb0c1',
|
||||||
|
borderColor: '#ff87a1',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
backgroundColor: '#a4dfdf',
|
||||||
|
borderColor: '#4bc0c0',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
const renderChart = async (file, cfg) => {
|
||||||
|
const chart = new chartjs(450, 300);
|
||||||
|
await chart.drawChart({
|
||||||
|
...cfg,
|
||||||
|
options: {
|
||||||
|
scales: {
|
||||||
|
xAxes: [{
|
||||||
|
barPercentage: 0.5,
|
||||||
|
gridLines: {
|
||||||
|
color: '#ccc',
|
||||||
|
},
|
||||||
|
ticks: {
|
||||||
|
fontColor: '#222',
|
||||||
|
},
|
||||||
|
}],
|
||||||
|
yAxes: [{
|
||||||
|
gridLines: {
|
||||||
|
color: '#666',
|
||||||
|
},
|
||||||
|
ticks: {
|
||||||
|
fontColor: '#222',
|
||||||
|
},
|
||||||
|
}],
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
labels: {
|
||||||
|
fontFamily: 'Ubuntu, sans-serif',
|
||||||
|
fontColor: '#000',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
await chart.writeImageToFile('image/png', path.join(__dirname, `${file}.png`));
|
||||||
|
};
|
||||||
|
|
||||||
|
const sizes = {};
|
||||||
|
const setSize = (program, test, result) => {
|
||||||
|
if (!sizes[test]) {
|
||||||
|
sizes[test] = {
|
||||||
|
original: {
|
||||||
|
absolute: tests.find(t => t.name === test).content.length,
|
||||||
|
relative: 1,
|
||||||
|
},
|
||||||
|
};
|
||||||
}
|
}
|
||||||
})
|
const original = sizes[test].original.absolute;
|
||||||
.add("html-minifier", () => {
|
sizes[test][program] = {
|
||||||
|
absolute: result,
|
||||||
|
relative: result / original,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// Run once to set sizes.
|
||||||
for (const t of tests) {
|
for (const t of tests) {
|
||||||
setSize("html-minifier", t.name, htmlMinifier.minify(t.content, htmlMinifierSettings).length);
|
for (const p of Object.keys(programs)) {
|
||||||
|
setSize(p, t.name, programs[p](t.content));
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
.add("minimize", () => {
|
|
||||||
|
const suite = new benchmark.Suite();
|
||||||
|
for (const p of Object.keys(programs)) {
|
||||||
|
suite.add(p, () => {
|
||||||
for (const t of tests) {
|
for (const t of tests) {
|
||||||
setSize("minimize", t.name, new minimize().parse(t.content).length);
|
programs[p](t.content);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
}
|
||||||
|
suite
|
||||||
.on('cycle', event => {
|
.on('cycle', event => {
|
||||||
console.info(event.target.toString());
|
console.info(event.target.toString());
|
||||||
})
|
})
|
||||||
.on('complete', function () {
|
.on('complete', async function () {
|
||||||
console.info(`Fastest is ${this.filter('fastest').map('name')}`);
|
const speedResults = this.map(b => ({
|
||||||
Object.entries(sizes).forEach(([test, results]) => {
|
name: b.name,
|
||||||
console.info(test);
|
count: b.count,
|
||||||
console.table(results);
|
ops: b.hz,
|
||||||
|
})).sort((a, b) => a.hz - b.hz);
|
||||||
|
await renderChart('speed', {
|
||||||
|
type: 'bar',
|
||||||
|
data: {
|
||||||
|
labels: speedResults.map(r => r.name),
|
||||||
|
datasets: [{
|
||||||
|
label: 'Operations per second',
|
||||||
|
...colours[0],
|
||||||
|
data: speedResults.map(r => r.ops),
|
||||||
|
}],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const testNames = Object.keys(sizes);
|
||||||
|
const programNames = Object.keys(programs);
|
||||||
|
await renderChart('minification', {
|
||||||
|
type: 'bar',
|
||||||
|
scaleFontColor: 'red',
|
||||||
|
data: {
|
||||||
|
labels: testNames,
|
||||||
|
datasets: programNames.map((program, i) => ({
|
||||||
|
label: program,
|
||||||
|
...colours[i],
|
||||||
|
data: testNames.map(test => sizes[test][program].relative),
|
||||||
|
})),
|
||||||
|
},
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.run({'async': true});
|
.run({'async': true});
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 26 KiB |
|
@ -2,9 +2,11 @@
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"benchmark": "2.1.4",
|
"benchmark": "2.1.4",
|
||||||
|
"chart.js": "^2.9.3",
|
||||||
|
"chartjs-node": "^1.7.1",
|
||||||
"html-minifier": "3.5.19",
|
"html-minifier": "3.5.19",
|
||||||
"minimize": "2.2.0",
|
"hyperbuild": "file:../nodejs",
|
||||||
"hyperbuild": "file:../nodejs"
|
"minimize": "2.2.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "node bench.js"
|
"start": "node bench.js"
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 7.9 KiB |
Loading…
Reference in New Issue