html-minifier-next 1.3.2 → 1.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +49 -23
  2. package/cli.js +14 -11
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -40,14 +40,16 @@ html-minifier-next --collapse-whitespace --input-dir=src --output-dir=dist --fil
40
40
  # Process multiple file extensions (CLI method)
41
41
  html-minifier-next --collapse-whitespace --input-dir=src --output-dir=dist --file-ext=html,htm,php
42
42
 
43
- # Using configuration file with fileExt setting
43
+ # Using configuration file that sets `fileExt` (e.g., `"fileExt": "html,htm"`)
44
44
  html-minifier-next --config-file=html-minifier.json --input-dir=src --output-dir=dist
45
45
 
46
46
  # Process all files (default behavior)
47
47
  html-minifier-next --collapse-whitespace --input-dir=src --output-dir=dist
48
+ # Note: When processing all files, non-HTML files will also be read as UTF‑8 and passed to the minifier.
49
+ # Consider restricting with “--file-ext” to avoid touching binaries (e.g., images, archives).
48
50
  ```
49
51
 
50
- ### CLI Options
52
+ ### CLI options
51
53
 
52
54
  Use `html-minifier-next --help` to check all available options:
53
55
 
@@ -59,9 +61,9 @@ Use `html-minifier-next --help` to check all available options:
59
61
  | `-o --output <file>` | Specify output file (single file mode) | `-o minified.html` |
60
62
  | `-c --config-file <file>` | Use a configuration file | `--config-file=html-minifier.json` |
61
63
 
62
- ### Configuration Files
64
+ ### Configuration file
63
65
 
64
- You can also use a configuration file to specify options:
66
+ You can also use a configuration file to specify options. The file can be either JSON format or a JavaScript module that exports the configuration object:
65
67
 
66
68
  **JSON configuration example:**
67
69
 
@@ -73,6 +75,16 @@ You can also use a configuration file to specify options:
73
75
  }
74
76
  ```
75
77
 
78
+ **JavaScript module configuration example:**
79
+
80
+ ```js
81
+ module.exports = {
82
+ collapseWhitespace: true,
83
+ removeComments: true,
84
+ fileExt: "html,htm"
85
+ };
86
+ ```
87
+
76
88
  **Using a configuration file:**
77
89
 
78
90
  ```bash
@@ -85,13 +97,28 @@ html-minifier-next --config-file=html-minifier.json --file-ext=xml --input-dir=s
85
97
 
86
98
  ### Node.js
87
99
 
100
+ ESM with Node.js ≥16.14:
101
+
88
102
  ```js
89
- const { minify } = require('html-minifier-next');
103
+ import { minify } from 'html-minifier-next';
90
104
 
91
105
  const result = await minify('<p title="blah" id="moo">foo</p>', {
92
106
  removeAttributeQuotes: true,
93
107
  });
94
- result; // “<p title=blah id=moo>foo</p>”
108
+ console.log(result); // “<p title=blah id=moo>foo</p>”
109
+ ```
110
+
111
+ CommonJS:
112
+
113
+ ```js
114
+ const { minify } = require('html-minifier-next');
115
+
116
+ (async () => {
117
+ const result = await minify('<p title="blah" id="moo">foo</p>', {
118
+ removeAttributeQuotes: true,
119
+ });
120
+ console.log(result);
121
+ })();
95
122
  ```
96
123
 
97
124
  See [the original blog post](http://perfectionkills.com/experimenting-with-html-minifier) for details of [how it works](http://perfectionkills.com/experimenting-with-html-minifier#how_it_works), [description of each option](http://perfectionkills.com/experimenting-with-html-minifier#options), [testing results](http://perfectionkills.com/experimenting-with-html-minifier#field_testing), and [conclusions](http://perfectionkills.com/experimenting-with-html-minifier#cost_and_benefits).
@@ -102,24 +129,24 @@ For lint-like capabilities take a look at [HTMLLint](https://github.com/kangax/h
102
129
 
103
130
  How does HTML Minifier compare to other solutions, like [minimize](https://github.com/Swaagie/minimize) or [htmlcompressor.com](http://htmlcompressor.com/)?
104
131
 
105
- | Site | Original size (KB) | HTML Minifier | minimize | htmlcompressor.com |
106
- | --- | --- |---------------| --- | --- |
132
+ | Site | Original size (KB) | HTMLMinifier | minimize | htmlcompressor.com |
133
+ | --- | --- | --- | --- | --- |
107
134
  | [A List Apart](https://alistapart.com/) | 64 | **54** | 59 | 57 |
108
- | [Amazon](https://www.amazon.com/) | 206 | **195** | 203 | 200 |
109
- | [BBC](https://www.bbc.co.uk/) | 767 | **703** | 761 | n/a |
110
- | [CSS-Tricks](https://css-tricks.com/) | 166 | **124** | 152 | 148 |
111
- | [ECMAScript](https://tc39.es/ecma262/) | 7204 | **6361** | 6581 | n/a |
112
- | [EFF](https://www.eff.org/) | 57 | **48** | 52 | 52 |
113
- | [FAZ](https://www.faz.net/aktuell/) | 1767 | **1641** | 1679 | n/a |
114
- | [Frontend Dogma](https://frontenddogma.com/) | 119 | **114** | 128 | 118 |
115
- | [Google](https://www.google.com/) | 51 | **46** | 50 | 50 |
116
- | [HTML Minifier](https://github.com/kangax/html-minifier) | 373 | **250** | 349 | n/a |
117
- | [Mastodon](https://mastodon.social/explore) | 37 | **28** | 36 | 36 |
118
- | [NBC](https://www.nbc.com/) | 601 | **549** | 593 | n/a |
119
- | [New York Times](https://www.nytimes.com/) | 822 | **701** | 811 | n/a |
135
+ | [Amazon](https://www.amazon.com/) | 707 | **635** | 693 | n/a |
136
+ | [BBC](https://www.bbc.co.uk/) | 700 | **642** | 694 | n/a |
137
+ | [CSS-Tricks](https://css-tricks.com/) | 167 | **124** | 153 | 149 |
138
+ | [ECMAScript](https://tc39.es/ecma262/) | 7205 | **6365** | 6585 | n/a |
139
+ | [EFF](https://www.eff.org/) | 58 | **49** | 52 | 52 |
140
+ | [Eloquent JavaScript](https://eloquentjavascript.net/) | 6 | **5** | 6 | 5 |
141
+ | [FAZ](https://www.faz.net/aktuell/) | 1848 | **1727** | 1763 | n/a |
142
+ | [Frontend Dogma](https://frontenddogma.com/) | 118 | **113** | 127 | 117 |
143
+ | [Google](https://www.google.com/) | 50 | **46** | 50 | 50 |
144
+ | [HTMLMinifier](https://github.com/kangax/html-minifier) | 371 | **249** | 347 | n/a |
145
+ | [Mastodon](https://mastodon.social/explore) | 35 | **26** | 34 | 34 |
146
+ | [NBC](https://www.nbc.com/) | 579 | **528** | 572 | n/a |
147
+ | [New York Times](https://www.nytimes.com/) | 733 | **625** | 722 | n/a |
120
148
  | [United Nations](https://www.un.org/) | 9 | **7** | 8 | 8 |
121
- | [W3C](https://www.w3.org/) | 50 | **36** | 41 | 39 |
122
- | [Wikipedia](https://en.wikipedia.org/wiki/Main_Page) | 225 | **204** | 215 | 215 |
149
+ | [W3C](https://www.w3.org/) | 51 | **36** | 42 | 40 |
123
150
 
124
151
  ## Options quick reference
125
152
 
@@ -139,7 +166,6 @@ Most of the options are disabled by default.
139
166
  | `customAttrSurround` | Arrays of regexes that allow to support custom attribute surround expressions (e.g. `<input {{#if value}}checked="checked"{{/if}}>`) | `[]` |
140
167
  | `customEventAttributes` | Arrays of regexes that allow to support custom event attributes for `minifyJS` (e.g. `ng-click`) | `[ /^on[a-z]{3,}$/ ]` |
141
168
  | `decodeEntities` | Use direct Unicode characters whenever possible | `false` |
142
- | `fileExt` | File extensions to process | `[]` (process all files) |
143
169
  | `html5` | Parse input according to HTML5 specifications | `true` |
144
170
  | `ignoreCustomComments` | Array of regexes that allow to ignore certain comments, when matched | `[ /^!/, /^\s*#/ ]` |
145
171
  | `ignoreCustomFragments` | Array of regexes that allow to ignore certain fragments, when matched (e.g. `<?php ... ?>`, `{{ ... }}`, etc.) | `[ /<%[\s\S]*?%>/, /<\?[\s\S]*?\?>/ ]` |
package/cli.js CHANGED
@@ -197,7 +197,7 @@ program.option('-c --config-file <file>', 'Use config file', function (configPat
197
197
  });
198
198
  program.option('--input-dir <dir>', 'Specify an input directory');
199
199
  program.option('--output-dir <dir>', 'Specify an output directory');
200
- program.option('--file-ext <text>', 'Specify file extension(s) to be read, e.g. “html” or “html,htm”');
200
+ program.option('--file-ext <extensions>', 'Specify file extension(s) to process (comma-separated), e.g., “html” or “html,htm,php”');
201
201
 
202
202
  let content;
203
203
  program.arguments('[files...]').action(function (files) {
@@ -250,17 +250,16 @@ function processFile(inputFile, outputFile) {
250
250
  }
251
251
 
252
252
  function parseFileExtensions(fileExt) {
253
- if (!fileExt) {
254
- return [];
255
- }
256
- return fileExt
253
+ if (!fileExt) return [];
254
+ const list = fileExt
257
255
  .split(',')
258
256
  .map(ext => ext.trim().replace(/^\.+/, '').toLowerCase())
259
257
  .filter(ext => ext.length > 0);
258
+ return [...new Set(list)];
260
259
  }
261
260
 
262
261
  function shouldProcessFile(filename, fileExtensions) {
263
- if (fileExtensions.length === 0) {
262
+ if (!fileExtensions || fileExtensions.length === 0) {
264
263
  return true; // No extensions specified, process all files
265
264
  }
266
265
 
@@ -268,8 +267,11 @@ function shouldProcessFile(filename, fileExtensions) {
268
267
  return fileExtensions.includes(fileExt);
269
268
  }
270
269
 
271
- function processDirectory(inputDir, outputDir, fileExt) {
272
- const extensions = parseFileExtensions(fileExt);
270
+ function processDirectory(inputDir, outputDir, extensions) {
271
+ // If first call provided a string, normalize once; otherwise assume pre-parsed array
272
+ if (typeof extensions === 'string') {
273
+ extensions = parseFileExtensions(extensions);
274
+ }
273
275
 
274
276
  fs.readdir(inputDir, function (err, files) {
275
277
  if (err) {
@@ -284,7 +286,7 @@ function processDirectory(inputDir, outputDir, fileExt) {
284
286
  if (err) {
285
287
  fatal('Cannot read ' + inputFile + '\n' + err.message);
286
288
  } else if (stat.isDirectory()) {
287
- processDirectory(inputFile, outputFile, fileExt);
289
+ processDirectory(inputFile, outputFile, extensions);
288
290
  } else if (shouldProcessFile(file, extensions)) {
289
291
  mkdir(outputDir, function () {
290
292
  processFile(inputFile, outputFile);
@@ -319,8 +321,9 @@ const writeMinify = async () => {
319
321
 
320
322
  const { inputDir, outputDir, fileExt } = programOptions;
321
323
 
322
- // Resolve file extensions: CLI argument takes priority over config file
323
- const resolvedFileExt = fileExt || config.fileExt;
324
+ // Resolve file extensions: CLI argument takes priority over config file, even if empty string
325
+ const hasCliFileExt = program.getOptionValueSource('fileExt') === 'cli';
326
+ const resolvedFileExt = hasCliFileExt ? fileExt : config.fileExt;
324
327
 
325
328
  if (inputDir || outputDir) {
326
329
  if (!inputDir) {
package/package.json CHANGED
@@ -88,5 +88,5 @@
88
88
  "test:watch": "NODE_OPTIONS='--experimental-vm-modules --no-warnings' jest --watch"
89
89
  },
90
90
  "type": "module",
91
- "version": "1.3.2"
91
+ "version": "1.3.3"
92
92
  }