Package Exports
- htmlnano
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (htmlnano) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
htmlnano
Modular HTML minifier, built on top of the PostHTML. Inspired by cssnano.
The author of htmlnano is available for hire as a full stack web developer: https://kirillmaltsev.net/services
Benchmark
Website | Source (KB) | html-minifier@3.5.20 | htmlnano@0.2.0 |
---|---|---|---|
stackoverflow.com | 258 | 205 | 218 |
github.com | 63 | 51 | 56 |
en.wikipedia.org | 77 | 69 | 74 |
npmjs.com | 32 | 29 | 30 |
Avg. minify rate | 0% | 15% | 9% |
Usage
Gulp
npm install --save-dev gulp-htmlnano
const gulp = require('gulp');
const htmlnano = require('gulp-htmlnano');
const options = {
removeComments: false
};
gulp.task('default', function() {
return gulp
.src('./index.html')
.pipe(htmlnano(options))
.pipe(gulp.dest('./build'));
});
Javascript
const htmlnano = require('htmlnano');
const options = {
removeEmptyAttributes: false, // Disable the module "removeEmptyAttributes"
collapseWhitespace: 'conservative' // Pass options to the module "collapseWhitespace"
};
htmlnano
// "preset" arg might be skipped (see "Presets" section below for more info)
.process(html, options, preset)
.then(function (result) {
// result.html is minified
})
.catch(function (err) {
console.error(err);
});
PostHTML
Just add htmlnano
as a final plugin:
const posthtml = require('posthtml');
const options = {
removeComments: false, // Disable the module "removeComments"
collapseWhitespace: 'conservative' // Pass options to the module "collapseWhitespace"
};
const posthtmlPlugins = [
/* other PostHTML plugins */
require('htmlnano')(options)
];
// "preset" arg might be skipped (see "Presets" section below for more info)
posthtml(posthtmlPlugins, preset)
.process(html)
.then(function (result) {
// result.html is minified
})
.catch(function (err) {
console.error(err);
});
Presets
A preset is just an object with modules config.
Currently the following presets are available:
- safe — a default preset for minifying a regular HTML in a safe way (without breaking anything)
- ampSafe - same as
safe
preset but for AMP pages - max - maximal minification (might break some pages)
You can use them the following way:
const htmlnano = require('htmlnano');
const ampSafePreset = require('htmlnano').presets.ampSafe;
const options = {
// Your options
};
htmlnano
.process(html, options, ampSafePreset)
.then(function (result) {
// result.html is minified
})
.catch(function (err) {
console.error(err);
});
If you skip preset
argument safe
preset would be 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 also your own presets:
const htmlnano = require('htmlnano');
// Preset for minifying email templates
const emailPreset = {
mergeStyles: true,
minifyCss: {
safe: true
},
};
const options = {
// Some specific options
};
htmlnano
.process(html, options, emailPreset)
.then(function (result) {
// result.html is minified
})
.catch(function (err) {
console.error(err);
});
Feel free to submit a PR with your preset if it might be useful for other developers as well.
Modules
By default the modules should only perform safe transforms, see the module documentation below for details.
You can disable modules by passing false
as option, and enable them by passing true
.
collapseAttributeWhitespace
Collapse redundant white spaces in list-like attributes (class
, rel
, ping
).
Example
Source:
<div class=" content page "></div>
Minified:
<div class="content page"></div>
collapseWhitespace
Collapses redundant white spaces (including new lines). It doesn’t affect white spaces in the elements <style>
, <textarea>
, <script>
and <pre>
.
Options
conservative
— collapses all redundant white spaces to 1 space (default)all
— collapses all redundant white spaces
Side effects
<i>hello</i> <i>world</i>
after minification will be rendered as helloworld
.
To prevent that use conservative
option (this is the default option).
Example
Source:
<div>
hello world!
<style>div { color: red; } </style>
</div>
Minified (with all
):
<div>hello world!<style>div { color: red; } </style></div>
Minified (with conservative
):
<div> hello world! <style>div { color: red; } </style> </div>
deduplicateAttributeValues
Remove duplicate values from list-like attributes (class
, rel
, ping
).
Example
Source:
<div class="sidebar left sidebar"></div>
Minified:
<div class="sidebar left"></div>
removeComments
Options
safe
– removes all HTML comments except the conditional comments and<!--noindex--><!--/noindex-->
(default)all
— removes all HTML comments
Example
Source:
<div><!-- test --></div>
Minified:
<div></div>
removeEmptyAttributes
Removes empty safe-to-remove attributes.
Side effects
This module could break your styles or JS if you use selectors with attributes:
img[style=""] {
margin: 10px;
}
Example
Source:
<img src="foo.jpg" alt="" style="">
Minified:
<img src="foo.jpg" alt="">
removeUnusedCss
Removes unused CSS with uncss inside <style>
tags.
Options
See the documentation of uncss for all supported options.
uncss options can be passed directly to the removeUnusedCss
module:
htmlnano.process(html, {
removeUnusedCss: {
ignore: ['.do-not-remove']
}
});
The following uncss options are ignored if passed to the module:
stylesheets
ignoreSheets
raw
Example
Source:
<div class="b">
<style>
.a {
margin: 10px 10px 10px 10px;
}
.b {
color: #ff0000;
}
</style>
</div>
Optimized:
<div class="b">
<style>
.b {
color: #ff0000;
}
</style>
</div>
minifyCss
Minifies CSS with cssnano inside <style>
tags and style
attributes.
Options
See the documentation of cssnano for all supported optimizations.
By default CSS is minified with preset default
, which shouldn't have any side-effects.
To use another preset or disabled some optimizations pass options to minifyCss
module:
htmlnano.process(html, {
minifyCss: {
preset: ['default', {
discardComments: {
removeAll: true,
},
}]
}
});
Example
Source:
<div>
<style>
h1 {
margin: 10px 10px 10px 10px;
color: #ff0000;
}
</style>
</div>
Minified:
<div>
<style>h1{margin:10px;color:red}</style>
</div>
minifyJs
Minifies JS using Terser inside <script>
tags.
Options
See the documentation of Terser for all supported options.
Terser options can be passed directly to the minifyJs
module:
htmlnano.process(html, {
minifyJs: {
output: { quote_style: 1 },
},
});
Example
Source:
<div>
<script>
/* comment */
const foo = function () {
};
</script>
</div>
Minified:
<div>
<script>const foo=function(){};</script>
</div>
minifyJson
Minifies JSON inside <script type="application/json"></script>
.
Example
Source:
<script type="application/json">
{
"user": "me"
}
</script>
Minified:
<script type="application/json">{"user":"me"}</script>
minifySvg
Minifies SVG inside <svg>
tags using SVGO.
Options
See the documentation of SVGO for all supported options.
SVGO options can be passed directly to the minifySvg
module:
htmlnano.process(html, {
minifySvg: {
plugins: [
{ collapseGroups: false },
],
},
});
Example
Source:
<svg version="1.1" baseProfile="full" width="300" height="200" xmlns="http://www.w3.org/2000/svg">
<rect width="100%" height="100%" fill="red" />
<circle cx="150" cy="100" r="80" fill="green" />
<text x="150" y="125" font-size="60" text-anchor="middle" fill="white">SVG</text>
</svg>`
Minified:
<svg baseProfile="full" width="300" height="200" xmlns="http://www.w3.org/2000/svg"><rect width="100%" height="100%" fill="red"/><circle cx="150" cy="100" r="80" fill="green"/><text x="150" y="125" font-size="60" text-anchor="middle" fill="#fff">SVG</text></svg>
removeRedundantAttributes
Removes redundant attributes from tags if they contain default values:
method="get"
from<form>
type="text"
from<input>
type="submit"
from<button>
language="javascript"
andtype="text/javascript"
from<script>
charset
from<script>
if it's an external scriptmedia="all"
from<style>
and<link>
Options
This module is disabled by default, change option to true to enable this module.
Side effects
This module could break your styles or JS if you use selectors with attributes:
form[method="get"] {
color: red;
}
Example
Source:
<form method="get">
<input type="text">
</form>
Minified:
<form>
<input>
</form>
collapseBooleanAttributes
Collapses boolean attributes (like disabled
) to the minimized form.
Options
If your document uses AMP, set the amphtml
flag
to collapse additonal, AMP-specific boolean attributes:
"collapseBooleanAttributes": {
"amphtml": true
}
Side effects
This module could break your styles or JS if you use selectors with attributes:
button[disabled="disabled"] {
color: red;
}
Example
Source:
<button disabled="disabled">click</button>
<script defer=""></script>
Minified:
<button disabled>click</button>
<script defer></script>
mergeStyles
Merges multiple <style>
with the same media
and type
into one tag.
<style scoped>...</style>
are skipped.
Example
Source:
<style>h1 { color: red }</style>
<style media="print">div { color: blue }</style>
<style type="text/css" media="print">a {}</style>
<style>div { font-size: 20px }</style>
Minified:
<style>h1 { color: red } div { font-size: 20px }</style>
<style media="print">div { color: blue } a {}</style>
mergeScripts
Merge multiple <script>
with the same attributes (id, class, type, async, defer
) into one (last) tag.
Side effects
It could break your code if the tags with different attributes share the same variable scope. See the example below.
Example
Source:
<script>const foo = 'A:1';</script>
<script class="test">foo = 'B:1';</script>
<script type="text/javascript">foo = 'A:2';</script>
<script defer>foo = 'C:1';</script>
<script>foo = 'A:3';</script>
<script defer="defer">foo = 'C:2';</script>
<script class="test" type="text/javascript">foo = 'B:2';</script>
Minified:
<script>const foo = 'A:1'; foo = 'A:2'; foo = 'A:3';</script>
<script defer="defer">foo = 'C:1'; foo = 'C:2';</script>
<script class="test" type="text/javascript">foo = 'B:1'; foo = 'B:2';</script>
custom
It's also possible to pass custom modules in the minifier. As a function:
const options = {
custom: function (tree, options) {
// Some minification
return tree;
}
};
Or as a list of functions:
const options = {
custom: [
function (tree, options) {
// Some minification
return tree;
},
function (tree, options) {
// Some other minification
return tree;
}
]
};
options
is an object with all options that were passed to the plugin.
Contribute
Since the minifier is modular, it's very easy to add new modules:
Create a ES6-file inside
lib/modules/
with a function that does some minification. For example you can checklib/modules/example.es6
.Add the module in the modules array. The modules are applied from top to bottom. So you can choose the order for your module.
Create a JS-file inside
test/modules/
with some unit-tests.Describe your module in the section "Modules".
Send me a pull request.
Other types of contribution (bug fixes, documentation improves, etc) are also welcome! Would like to contribute, but don't have any ideas what to do? Check out our issues.