diff --git a/bench/README.md b/bench/README.md index c70c367..6f05feb 100644 --- a/bench/README.md +++ b/bench/README.md @@ -49,7 +49,7 @@ The settings used for each minifier can be found in [minifiers.js](./minifiers.j Make sure to install the dependencies listed in [package.json](./package.json) by running `npm i` or `yarn`. Node.js 10 is required, and system dependencies for building [canvas](https://www.npmjs.com/package/canvas), used for rendering graphs, may need to be installed. See the [npm package](https://www.npmjs.com/package/canvas) for more details. -Run [build.sh](./build.sh) to build minify-html-nodejs with the local minify-html. +Run [build.sh](./build.sh) to build @minify-html/js with the local minify-html. Run [sizes.js](sizes.js) to run each HTML minifier against each test and record the minified size results. This will also output the minified files in `min` if inspection of minified outputs is necessary. [compare.sh](./compare.sh) is a useful script for viewing a character-by-character diff between the minified outputs of minify-html and html-minifier for a specific test. Pass the test's file name as the first argument. diff --git a/bench/compare.sh b/bench/compare.sh index 2d104d0..fd963c0 100755 --- a/bench/compare.sh +++ b/bench/compare.sh @@ -1,3 +1,3 @@ #!/usr/bin/env bash -git --no-pager diff --no-index --word-diff=color --word-diff-regex=. "min/html-minifier/$1.html" "min/minify-html-nodejs/$1.html" | less +git --no-pager diff --no-index --word-diff=color --word-diff-regex=. "min/html-minifier/$1.html" "min/@minify-html/js/$1.html" | less diff --git a/bench/graph.js b/bench/graph.js index a810439..f7d3eb0 100644 --- a/bench/graph.js +++ b/bench/graph.js @@ -3,7 +3,7 @@ const results = require('./results'); const colours = { 'minify-html': '#041f60', - 'minify-html-nodejs': '#1f77b4', + '@minify-html/js': '#1f77b4', 'minimize': '#ff7f0e', 'html-minifier': '#2ca02c', }; @@ -56,7 +56,7 @@ const renderChart = async (cfg) => { }; (async () => { - const averageSpeeds = results.getSpeedResults().getAverageRelativeSpeedPerMinifier('minify-html-nodejs'); + const averageSpeeds = results.getSpeedResults().getAverageRelativeSpeedPerMinifier('@minify-html/js'); results.writeAverageSpeedsGraph(await renderChart({ type: 'bar', data: { @@ -70,7 +70,7 @@ const renderChart = async (cfg) => { ...chartOptions('Average operations per second (higher is better)', false, percentageTick), })); - const speeds = results.getSpeedResults().getRelativeFileSpeedsPerMinifier('minify-html-nodejs'); + const speeds = results.getSpeedResults().getRelativeFileSpeedsPerMinifier('@minify-html/js'); results.writeSpeedsGraph(await renderChart({ type: 'bar', data: { diff --git a/bench/minifiers.js b/bench/minifiers.js index 7bde60a..292a84a 100644 --- a/bench/minifiers.js +++ b/bench/minifiers.js @@ -3,7 +3,7 @@ const htmlMinifier = require('html-minifier'); const minifyHtml = require('@minify-html/js'); const minimize = require('minimize'); -const minifyHtmlCfg = minifyHtml.createConfiguration({minifyJs: true}); +const testJsMinification = process.env.HTML_ONLY !== '1'; const jsMime = new Set([ undefined, @@ -46,49 +46,62 @@ class EsbuildAsync { } } -module.exports = { - 'minify-html-nodejs': (_, buffer) => minifyHtml.minifyInPlace(Buffer.from(buffer), minifyHtmlCfg), - 'html-minifier': async (content) => { - const js = new EsbuildAsync(); - const res = htmlMinifier.minify(content, { - collapseBooleanAttributes: true, - collapseInlineTagWhitespace: true, - collapseWhitespace: true, - // minify-html can do context-aware whitespace removal, which is safe when configured correctly to match how whitespace is used in the document. - // html-minifier cannot, so whitespace must be collapsed conservatively. - // Alternatively, minify-html can also be made to remove whitespace regardless of context. - conservativeCollapse: true, - customEventAttributes: [], - decodeEntities: true, - ignoreCustomComments: [], - ignoreCustomFragments: [/<\?[\s\S]*?\?>/], - minifyJS: code => js.queue(code), - processConditionalComments: true, - removeAttributeQuotes: true, - removeComments: true, - removeEmptyAttributes: true, - removeOptionalTags: true, - removeRedundantAttributes: true, - removeScriptTypeAttributes: true, - removeStyleLinkTypeAttributes: true, - removeTagWhitespace: true, - useShortDoctype: true, - }); - return js.finalise(res); - }, - 'minimize': async (content) => { - const js = new EsbuildAsync(); - const res = new minimize({ - plugins: [{ - id: 'esbuild', - element: (node, next) => { - if (node.type === 'text' && node.parent && node.parent.type === 'script' && jsMime.has(node.parent.attribs.type)) { - node.data = js.queue(node.data); - } - next(); - }, - }], - }).parse(content); - return js.finalise(res); - }, +const minifyHtmlCfg = minifyHtml.createConfiguration({minifyJs: testJsMinification}); +const htmlMinifierCfg = { + collapseBooleanAttributes: true, + collapseInlineTagWhitespace: true, + collapseWhitespace: true, + // minify-html can do context-aware whitespace removal, which is safe when configured correctly to match how whitespace is used in the document. + // html-minifier cannot, so whitespace must be collapsed conservatively. + // Alternatively, minify-html can also be made to remove whitespace regardless of context. + conservativeCollapse: true, + customEventAttributes: [], + decodeEntities: true, + ignoreCustomComments: [], + ignoreCustomFragments: [/<\?[\s\S]*?\?>/], + // This will be set to a function if `testJsMinification` is true. + minifyJS: false, + processConditionalComments: true, + removeAttributeQuotes: true, + removeComments: true, + removeEmptyAttributes: true, + removeOptionalTags: true, + removeRedundantAttributes: true, + removeScriptTypeAttributes: true, + removeStyleLinkTypeAttributes: true, + removeTagWhitespace: true, + useShortDoctype: true, +}; + +module.exports = { + '@minify-html/js': (_, buffer) => minifyHtml.minifyInPlace(Buffer.from(buffer), minifyHtmlCfg), + 'html-minifier': testJsMinification + ? async (content) => { + const js = new EsbuildAsync(); + const res = htmlMinifier.minify(content, { + ...htmlMinifierCfg, + minifyJS: code => js.queue(code), + }); + return js.finalise(res); + } + : content => htmlMinifier.minify(content, htmlMinifierCfg), + 'minimize': testJsMinification + ? async (content) => { + const js = new EsbuildAsync(); + const plugins = []; + if (testJsMinification) { + plugins.push({ + id: 'esbuild', + element: (node, next) => { + if (node.type === 'text' && node.parent && node.parent.type === 'script' && jsMime.has(node.parent.attribs.type)) { + node.data = js.queue(node.data); + } + next(); + }, + }); + } + const res = new minimize({plugins}).parse(content); + return js.finalise(res); + } + : content => new minimize().parse(content), };