minify-html/bench/bench.js

189 lines
4.8 KiB
JavaScript
Raw Normal View History

2019-12-30 03:58:50 -05:00
"use strict";
const benchmark = require("benchmark");
2020-01-01 09:18:38 -05:00
const chartjs = require('chartjs-node');
const fs = require("fs");
2019-12-30 03:58:50 -05:00
const htmlMinifier = require("html-minifier");
const hyperbuild = require("hyperbuild");
2020-01-01 09:18:38 -05:00
const minimize = require("minimize");
const path = require("path");
2019-12-30 03:58:50 -05:00
2020-01-01 09:18:38 -05:00
const testsDir = path.join(__dirname, "tests");
const tests = fs.readdirSync(testsDir).map(name => ({
2019-12-30 03:58:50 -05:00
name,
2020-01-01 09:18:38 -05:00
content: fs.readFileSync(path.join(testsDir, name), "utf8"),
2019-12-30 03:58:50 -05:00
}));
2020-01-01 09:18:38 -05:00
const programs = {
2020-01-04 23:18:53 -05:00
'hyperbuild-nodejs': content => hyperbuild.minify_in_place(Buffer.from(content)),
2020-01-01 09:18:38 -05:00
'html-minifier': content => htmlMinifier.minify(content, {
caseSensitive: false,
collapseBooleanAttributes: true,
collapseInlineTagWhitespace: true,
collapseWhitespace: true,
conservativeWhitespace: false,
customEventAttributes: [],
decodeEntities: true,
html5: true,
ignoreCustomComments: [],
ignoreCustomFragments: [],
includeAutoGeneratedTags: true,
keepClosingSlash: false,
minifyCSS: false,
minifyJS: false,
minifyURLs: false,
preserveLineBreaks: false,
preventAttributesEscaping: false,
processConditionalComments: true,
processScripts: [],
removeAttributeQuotes: true,
removeComments: true,
removeEmptyAttributes: false,
removeEmptyElements: false,
removeOptionalTags: true,
removeRedundantAttributes: true,
removeScriptTypeAttributes: true,
removeStyleLinkTypeAttributes: true,
removeTagWhitespace: true,
2020-01-06 08:28:35 -05:00
sortAttributes: false,
sortClassName: false,
2020-01-01 09:18:38 -05:00
trimCustomFragments: false,
useShortDoctype: true,
}).length,
'minimize': content => new minimize().parse(content).length,
};
const colours = [
{
backgroundColor: '#9ad0f5',
borderColor: '#47aaec',
},
{
backgroundColor: '#ffb0c1',
borderColor: '#ff87a1',
},
{
backgroundColor: '#a4dfdf',
borderColor: '#4bc0c0',
},
];
2020-01-04 23:18:53 -05:00
const chartOptions = (title, displayLegend, yTick = t => t) => ({
options: {
title: {
display: true,
text: title,
},
scales: {
xAxes: [{
barPercentage: 0.5,
gridLines: {
color: '#ccc',
},
ticks: {
fontColor: '#222',
2020-01-01 09:18:38 -05:00
},
2020-01-04 23:18:53 -05:00
}],
yAxes: [{
gridLines: {
color: '#666',
},
ticks: {
callback: yTick,
fontColor: '#222',
},
}],
},
legend: {
display: displayLegend,
labels: {
fontFamily: 'Ubuntu, sans-serif',
fontColor: '#000',
2020-01-01 09:18:38 -05:00
},
},
2020-01-04 23:18:53 -05:00
},
});
const renderChart = async (file, cfg) => {
const chart = new chartjs(435, 320);
await chart.drawChart(cfg);
2020-01-01 09:18:38 -05:00
await chart.writeImageToFile('image/png', path.join(__dirname, `${file}.png`));
};
2019-12-30 03:58:50 -05:00
const sizes = {};
const setSize = (program, test, result) => {
if (!sizes[test]) {
sizes[test] = {
original: {
2020-01-01 09:18:38 -05:00
absolute: tests.find(t => t.name === test).content.length,
relative: 1,
2019-12-30 03:58:50 -05:00
},
};
}
2020-01-01 09:18:38 -05:00
const original = sizes[test].original.absolute;
2019-12-30 03:58:50 -05:00
sizes[test][program] = {
2020-01-01 09:18:38 -05:00
absolute: result,
relative: result / original,
2019-12-30 03:58:50 -05:00
};
};
2020-01-01 09:18:38 -05:00
// Run once to set sizes.
for (const t of tests) {
for (const p of Object.keys(programs)) {
2020-01-03 02:19:32 -05:00
try {
setSize(p, t.name, programs[p](t.content));
} catch (err) {
console.error(`Failed to run ${p} on test ${t.name}:`);
console.error(err);
process.exit(1);
}
2020-01-01 09:18:38 -05:00
}
}
2019-12-30 03:58:50 -05:00
2020-01-01 09:18:38 -05:00
const suite = new benchmark.Suite();
for (const p of Object.keys(programs)) {
suite.add(p, () => {
2019-12-30 03:58:50 -05:00
for (const t of tests) {
2020-01-01 09:18:38 -05:00
programs[p](t.content);
2019-12-30 03:58:50 -05:00
}
2020-01-01 09:18:38 -05:00
});
}
suite
2019-12-30 03:58:50 -05:00
.on('cycle', event => {
console.info(event.target.toString());
})
2020-01-01 09:18:38 -05:00
.on('complete', async function () {
const speedResults = this.map(b => ({
name: b.name,
ops: b.hz,
2020-01-06 08:28:35 -05:00
}));
fs.writeFileSync(path.join(__dirname, "speed.json"), JSON.stringify(speedResults, null, 2));
2020-01-04 23:18:53 -05:00
await renderChart('speed', {
2020-01-01 09:18:38 -05:00
type: 'bar',
data: {
labels: speedResults.map(r => r.name),
datasets: [{
...colours[0],
data: speedResults.map(r => r.ops),
}],
},
2020-01-04 23:18:53 -05:00
...chartOptions('Operations per second (higher is better)', false),
2020-01-01 09:18:38 -05:00
});
const testNames = Object.keys(sizes);
const programNames = Object.keys(programs);
2020-01-06 08:28:35 -05:00
fs.writeFileSync(path.join(__dirname, "minification.json"), JSON.stringify(sizes, null, 2));
2020-01-04 23:18:53 -05:00
await renderChart('minification', {
2020-01-01 09:18:38 -05:00
type: 'bar',
scaleFontColor: 'red',
data: {
labels: testNames,
datasets: programNames.map((program, i) => ({
label: program,
...colours[i],
2020-01-04 23:18:53 -05:00
data: testNames.map(test => sizes[test][program].relative * 100),
2020-01-01 09:18:38 -05:00
})),
},
2020-01-04 23:18:53 -05:00
...chartOptions('Relative minified HTML file size (lower is better)', true, tick => `${tick}%`),
2019-12-30 03:58:50 -05:00
});
})
.run({'async': true});