Skip to main content
Version: Next

Presets

A preset is just an object with modules config.

Currently the following presets are available:

  • safe — default preset for safe minification.
  • ampSafe — same as safe but tailored for AMP pages.
  • max — maximal minification (might break some pages).

safe compatibility contract​

safe preserves browser-parsed HTML behavior, not the original source. It may simplify syntax and remove empty or redundant whitespace when the result parses as an equivalent HTML document or fragment.

It does not guarantee preservation of outerHTML, attribute presence or order, comments removed by removeComments: 'safe', or XHTML/XML serialization. ampSafe follows the same contract while keeping the output valid AMP HTML.

For optional tags, safe uses removeOptionalTags: { removeStartTags: false }: it retains every explicit start tag while omitting eligible end tags. ampSafe inherits this conservative setting. max uses removeOptionalTags: true, so it may omit eligible start tags as well as end tags.

The completed preset changes differ as follows:

BehaviorsafeampSafemax
Attribute quotesRemoves optional quotesSame as safeRemoves optional quotes
Optional tagsEnd tags onlyEnd tags onlyStart and end tags
Doctype normalizationShort HTML5 doctypes onlyShort HTML5 doctypes onlyBroad, including legacy doctypes
IE conditional commentsUnchangedUnchangedMinifies their contents
Attribute sortingDisabledDisabledAlphabetical

ampSafe otherwise differs from safe by enabling AMP-specific boolean attribute collapsing and disabling JavaScript minification. Attribute sorting remains out of both safe presets because measurements on the cached benchmark corpus showed that it increased gzip and Brotli sizes despite leaving raw size unchanged.

max enables lossy modules on purpose. The most visible one is removeEmptyElements with removeWithAttributes: 'presentational': empty elements whose attributes are all presentational (class, style, aria-hidden) are dropped, which removes purely decorative markup such as carousel dots, skeleton loaders and spacers. Elements with an id, a role, data-*, event handlers and the like are kept, as are <canvas>, <slot>, <iframe>, custom elements and interactive elements such as <button> and <a>. Removal keeps the meaning and accessibility of the page intact, but class is also a scripting hook, so a decorative element that some script looks up by class will no longer be found. If you want those decorations back, override the module:

htmlnano.process(html, { removeEmptyElements: true }, htmlnano.presets.max);

max also configures minifyJs with format: { comments: false }, which drops the @license/@preserve//*! comments Terser keeps by default. That is a legal trade-off — most JS licenses require the notice to be distributed with the code — so only use it when the notices are shipped elsewhere. To keep them:

htmlnano.process(html, { minifyJs: { format: { comments: 'some' } } }, htmlnano.presets.max);

You can use them the following way:

const htmlnano = require('htmlnano');
const ampSafePreset = require('htmlnano').presets.ampSafe;

htmlnano.process(html, { collapseWhitespace: 'conservative' }, ampSafePreset)
.then((result) => {
// result.html is minified
})
.catch((err) => {
console.error(err);
});

You can also import presets directly:

import htmlnano from 'htmlnano';
import ampSafe from 'htmlnano/presets/ampSafe';

const result = await htmlnano.process(html, {}, ampSafe);

If you skip preset argument, safe is used by default.

If you'd like to define your very own config without any presets pass an empty object as a preset:

const htmlnano = require('htmlnano');
const options = {
// Your options
};

htmlnano
.process(html, options, {})
.then(function (result) {
// result.html is minified
})
.catch(function (err) {
console.error(err);
});

You might create your own presets by starting from a built-in one:

const htmlnano = require('htmlnano');
const emailPreset = {
...htmlnano.presets.safe,
mergeStyles: true,
minifyCss: {
safe: true
}
};

htmlnano.process(html, { removeComments: false }, emailPreset)
.then((result) => {
// result.html is minified
})
.catch((err) => {
console.error(err);
});

Feel free to submit a PR with your preset if it might be useful for other developers as well.