A Metalsmith plugin for optimizing and minifying HTML files - UNDER DEVELOPMENT
Build with lots of inspiration from htmlcompressor. This plugin optimizes HTML files by removing unnecessary whitespace, comments, and attributes. It also normalizes URLs, boolean attributes, and data attributes.
There was a time when Metalsmith HTML Minifier was the go-to plugin for HTML optimization. However, it looks abondoned and has some serious security issues. It is build as a wrapper for HTML Minifier which has now a security fix, but sadly the wrapper has not been updated. This plugin is build from scratch with just a few up-to-date dependencies. This is still a work in progress, but it is already usable. Please test it and report any issues you find.
npm install metalsmith-optimize-html
import Metalsmith from 'metalsmith'
import optimizeHTML from '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
}
}
}
- 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">
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>
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">
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"}'>
removeEmptyAttributes: boolean (default: false)
- Removes attributes with empty values
<div id="" class=" " data-value="">
<!-- becomes -->
<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">
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"}'>
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
}))
Debug messages can be enabled by setting the DEBUG environment variable.
metalsmith.env( 'DEBUG', 'metalsmith-optimize-html' );
- 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