A Metalsmith plugin for optimizing and minifying HTML files
A modern, modular HTML optimizer for Metalsmith that reduces file sizes by removing unnecessary whitespace, comments, and redundant markup while preserving functionality. This plugin supports both ESM and CommonJS environments.
- Modular Architecture: Enable only the optimizations you need
- Dual Module Support: Works with both ESM and CommonJS imports
- Safe Optimizations: Preserves functionality while reducing file size
- Comprehensive Options: Fine-grained control over optimizations
- Tag Exclusion: Exclude specific tags from optimization
- Validation: Robust input validation with helpful error messages
- Reliable Compatibility: Fixed in v0.5.3 to work correctly in CommonJS environments
Metalsmith HTML Minifier was historically the standard plugin for HTML optimization, but it became abandoned with security issues. This plugin is built from scratch with modern JavaScript practices, a functional approach, and minimal dependencies. It offers more granular control over optimizations while maintaining better security and compatibility with current projects.
npm install metalsmith-optimize-html
Both ESM and CommonJS imports are supported:
// ESM
import optimizeHTML from 'metalsmith-optimize-html';
// CommonJS
const optimizeHTML = require('metalsmith-optimize-html');
Metalsmith(__dirname).use(
optimizeHTML({
// options
removeComments: true,
removeTagSpaces: true
})
);
In your metalsmith.json
:
{
"plugins": {
"metalsmith-optimize-html": {
"removeComments": true,
"removeTagSpaces": true,
"simplifyDoctype": true
}
}
}
The plugin validates all options for correct types and will throw detailed error messages if invalid options are provided. This helps catch configuration mistakes early.
- Collapses multiple whitespace to single space
- Removes whitespace between HTML tags
- Preserves whitespace in
<pre>
,<code>
,<textarea>
,<script>
,<style>
tags
removeComments: boolean (default: false)
- Removes all HTML comments
<!-- This comment will be removed -->
removeTagSpaces: boolean (default: false)
- Removes extra spaces inside HTML tags
- Normalizes spaces between attributes
<div class="example" id="test">
<!-- becomes -->
<div class="example" id="test"></div>
</div>
removeDefaultAttributes: boolean (default: false)
- Removes common default attributes that browsers assume anyway
<script type="text/javascript" src="main.js">
<link type="text/css" rel="stylesheet">
<form method="get">
<input type="text">
<!-- becomes -->
<script src="main.js">
<link rel="stylesheet">
<form>
<input>
normalizeBooleanAttributes: boolean (default: false)
- Normalizes boolean attributes to their shorter form
<input type="checkbox" checked="checked" disabled="disabled" />
<select multiple="multiple">
<!-- becomes -->
<input type="checkbox" checked disabled />
<select multiple></select>
</select>
cleanUrlAttributes: boolean (default: false)
- Cleans and normalizes URLs in href, src, action, srcset, and data attributes
- Removes unnecessary whitespace in URLs
<a href=" https://example.com/page ">
<!-- becomes -->
<a href="https://example.com/page"></a
></a>
cleanDataAttributes: boolean (default: false)
- Normalizes whitespace in data-* attribute values
- Maintains valid JSON in data attributes
<div data-config='{ "key" : "value" }'>
<!-- becomes -->
<div data-config='{"key":"value"}'></div>
</div>
removeEmptyAttributes: boolean (default: false)
- Removes attributes with empty values
<div id="" class=" " data-value="">
<!-- becomes -->
<div></div>
</div>
removeProtocols: boolean (default: false)
- Converts URLs to protocol-relative URLs
- Preserves protocols in links with
rel="external"
<a href="https://example.com">
<a href="http://example.com" rel="external">
<!-- becomes -->
<a href="//example.com"> <a href="http://example.com" rel="external"></a></a></a
></a>
simplifyDoctype: boolean (default: false)
- Replaces any DOCTYPE declaration with
HTML5 DOCTYPE
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<!-- becomes -->
<!DOCTYPE html>
safeRemoveAttributeQuotes: boolean (default: false)
- Only removes quotes if value contains no special characters
- Preserves quotes for values with spaces, brackets, etc.
<div class="example" id="test" data-value='{"key":"value"}'>
<!-- becomes -->
<div class="example" id="test" data-value='{"key":"value"}'></div>
</div>
aggressive: boolean (default: false)
- Enables all optimizations with a single option:
- removeComments
- removeTagSpaces
- removeDefaultAttributes
- normalizeBooleanAttributes
- cleanUrlAttributes
- cleanDataAttributes
- removeEmptyAttributes
- removeProtocols
- simplifyDoctype
- safeRemoveAttributeQuotes
Metalsmith(__dirname).use(optimizeHTML({ aggressive: true }));
All individual option settings are ignored when aggressive is true, except when explicitly overridden:
Metalsmith(__dirname).use(
optimizeHTML({
aggressive: true,
removeComments: false // This override will be respected
})
);
To log debug output, set the DEBUG environment variable to metalsmith-optimize-html
Linux/Mac:
DEBUG=metalsmith-optimize-html metalsmith
Windows:
set DEBUG=metalsmith-optimize-html
metalsmith
- The plugin cannot safely handle nested or malformed HTML comments
- If a comment is not properly closed, it might affect subsequent content
- Content within
<pre>
,<code>
,<textarea>
,<script>
, and<style>
tags is preserved - Whitespace and formatting within these tags remains untouched
- Protocol removal only affects
http://
andhttps://
protocols - Other protocols (
ftp://
,ws://
, etc.) remain unchanged - Handles URLs in meta tags (
og:url
,twitter:url
,canonical
) - Processes SVG attributes (
xmlns
,xlink:href
,href
,src
)
- JSON values in data attributes must be valid JSON
- Invalid JSON structures are left unchanged
This project maintains high statement and line coverage for the source code. Coverage is verified during the release process using the c8 coverage tool.