htmlnano 2.1.4 → 3.0.0

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 (69) hide show
  1. package/README.md +6 -0
  2. package/dist/_modules/collapseAttributeWhitespace.d.mts +1 -0
  3. package/dist/_modules/collapseAttributeWhitespace.d.ts +1 -0
  4. package/dist/_modules/collapseBooleanAttributes.d.mts +1 -0
  5. package/dist/_modules/collapseBooleanAttributes.d.ts +1 -0
  6. package/dist/_modules/collapseWhitespace.d.mts +1 -0
  7. package/dist/_modules/collapseWhitespace.d.ts +1 -0
  8. package/dist/_modules/custom.d.mts +1 -0
  9. package/dist/_modules/custom.d.ts +1 -0
  10. package/dist/_modules/deduplicateAttributeValues.d.mts +1 -0
  11. package/dist/_modules/deduplicateAttributeValues.d.ts +1 -0
  12. package/dist/_modules/example.d.mts +1 -0
  13. package/dist/_modules/example.d.ts +1 -0
  14. package/dist/_modules/mergeScripts.d.mts +1 -0
  15. package/dist/_modules/mergeScripts.d.ts +1 -0
  16. package/dist/_modules/mergeStyles.d.mts +1 -0
  17. package/dist/_modules/mergeStyles.d.ts +1 -0
  18. package/dist/_modules/mergeStyles.js +1 -2
  19. package/dist/_modules/mergeStyles.mjs +1 -2
  20. package/dist/_modules/minifyConditionalComments.d.mts +1 -0
  21. package/dist/_modules/minifyConditionalComments.d.ts +1 -0
  22. package/dist/_modules/minifyCss.d.mts +1 -0
  23. package/dist/_modules/minifyCss.d.ts +1 -0
  24. package/dist/_modules/minifyCss.js +9 -2
  25. package/dist/_modules/minifyCss.mjs +9 -2
  26. package/dist/_modules/minifyJs.d.mts +1 -0
  27. package/dist/_modules/minifyJs.d.ts +1 -0
  28. package/dist/_modules/minifyJs.js +5 -1
  29. package/dist/_modules/minifyJs.mjs +5 -1
  30. package/dist/_modules/minifyJson.d.mts +1 -0
  31. package/dist/_modules/minifyJson.d.ts +1 -0
  32. package/dist/_modules/minifyJson.js +1 -1
  33. package/dist/_modules/minifyJson.mjs +1 -1
  34. package/dist/_modules/minifySvg.d.mts +1 -0
  35. package/dist/_modules/minifySvg.d.ts +1 -0
  36. package/dist/_modules/minifySvg.js +3 -3
  37. package/dist/_modules/minifySvg.mjs +3 -3
  38. package/dist/_modules/minifyUrls.d.mts +1 -0
  39. package/dist/_modules/minifyUrls.d.ts +1 -0
  40. package/dist/_modules/minifyUrls.js +1 -1
  41. package/dist/_modules/minifyUrls.mjs +1 -1
  42. package/dist/_modules/normalizeAttributeValues.d.mts +1 -0
  43. package/dist/_modules/normalizeAttributeValues.d.ts +1 -0
  44. package/dist/_modules/removeAttributeQuotes.d.mts +1 -0
  45. package/dist/_modules/removeAttributeQuotes.d.ts +1 -0
  46. package/dist/_modules/removeAttributeQuotes.js +1 -2
  47. package/dist/_modules/removeAttributeQuotes.mjs +1 -2
  48. package/dist/_modules/removeComments.d.mts +1 -0
  49. package/dist/_modules/removeComments.d.ts +1 -0
  50. package/dist/_modules/removeEmptyAttributes.d.mts +1 -0
  51. package/dist/_modules/removeEmptyAttributes.d.ts +1 -0
  52. package/dist/_modules/removeOptionalTags.d.mts +1 -0
  53. package/dist/_modules/removeOptionalTags.d.ts +1 -0
  54. package/dist/_modules/removeRedundantAttributes.d.mts +1 -0
  55. package/dist/_modules/removeRedundantAttributes.d.ts +1 -0
  56. package/dist/_modules/removeUnusedCss.d.mts +1 -0
  57. package/dist/_modules/removeUnusedCss.d.ts +1 -0
  58. package/dist/_modules/sortAttributes.d.mts +1 -0
  59. package/dist/_modules/sortAttributes.d.ts +1 -0
  60. package/dist/_modules/sortAttributesWithLists.d.mts +1 -0
  61. package/dist/_modules/sortAttributesWithLists.d.ts +1 -0
  62. package/dist/bin.js +34 -0
  63. package/dist/index.d.ts +13 -12
  64. package/dist/index.js +70 -15
  65. package/dist/index.mjs +70 -15
  66. package/dist/presets/ampSafe.d.ts +2 -1
  67. package/dist/presets/max.d.ts +2 -1
  68. package/dist/presets/safe.d.ts +2 -1
  69. package/package.json +12 -8
package/README.md CHANGED
@@ -61,4 +61,10 @@ htmlnano
61
61
  });
62
62
  ```
63
63
 
64
+ Also, you can use it as CLI tool:
65
+
66
+ ```bash
67
+ node_modules/.bin/htmlnano --help
68
+ ```
69
+
64
70
  More usage examples (PostHTML, Gulp, Webpack): https://htmlnano.netlify.app/next/usage
@@ -14,6 +14,7 @@ type MaybeArray<T> = T | Array<T>;
14
14
  type PostHTMLNodeLike = PostHTML.Node | string;
15
15
  interface HtmlnanoOptions {
16
16
  skipConfigLoading?: boolean;
17
+ configPath?: string;
17
18
  skipInternalWarnings?: boolean;
18
19
  collapseAttributeWhitespace?: boolean;
19
20
  collapseBooleanAttributes?: {
@@ -14,6 +14,7 @@ type MaybeArray<T> = T | Array<T>;
14
14
  type PostHTMLNodeLike = PostHTML.Node | string;
15
15
  interface HtmlnanoOptions {
16
16
  skipConfigLoading?: boolean;
17
+ configPath?: string;
17
18
  skipInternalWarnings?: boolean;
18
19
  collapseAttributeWhitespace?: boolean;
19
20
  collapseBooleanAttributes?: {
@@ -14,6 +14,7 @@ type MaybeArray<T> = T | Array<T>;
14
14
  type PostHTMLNodeLike = PostHTML.Node | string;
15
15
  interface HtmlnanoOptions {
16
16
  skipConfigLoading?: boolean;
17
+ configPath?: string;
17
18
  skipInternalWarnings?: boolean;
18
19
  collapseAttributeWhitespace?: boolean;
19
20
  collapseBooleanAttributes?: {
@@ -14,6 +14,7 @@ type MaybeArray<T> = T | Array<T>;
14
14
  type PostHTMLNodeLike = PostHTML.Node | string;
15
15
  interface HtmlnanoOptions {
16
16
  skipConfigLoading?: boolean;
17
+ configPath?: string;
17
18
  skipInternalWarnings?: boolean;
18
19
  collapseAttributeWhitespace?: boolean;
19
20
  collapseBooleanAttributes?: {
@@ -14,6 +14,7 @@ type MaybeArray<T> = T | Array<T>;
14
14
  type PostHTMLNodeLike = PostHTML.Node | string;
15
15
  interface HtmlnanoOptions {
16
16
  skipConfigLoading?: boolean;
17
+ configPath?: string;
17
18
  skipInternalWarnings?: boolean;
18
19
  collapseAttributeWhitespace?: boolean;
19
20
  collapseBooleanAttributes?: {
@@ -14,6 +14,7 @@ type MaybeArray<T> = T | Array<T>;
14
14
  type PostHTMLNodeLike = PostHTML.Node | string;
15
15
  interface HtmlnanoOptions {
16
16
  skipConfigLoading?: boolean;
17
+ configPath?: string;
17
18
  skipInternalWarnings?: boolean;
18
19
  collapseAttributeWhitespace?: boolean;
19
20
  collapseBooleanAttributes?: {
@@ -14,6 +14,7 @@ type MaybeArray<T> = T | Array<T>;
14
14
  type PostHTMLNodeLike = PostHTML.Node | string;
15
15
  interface HtmlnanoOptions {
16
16
  skipConfigLoading?: boolean;
17
+ configPath?: string;
17
18
  skipInternalWarnings?: boolean;
18
19
  collapseAttributeWhitespace?: boolean;
19
20
  collapseBooleanAttributes?: {
@@ -14,6 +14,7 @@ type MaybeArray<T> = T | Array<T>;
14
14
  type PostHTMLNodeLike = PostHTML.Node | string;
15
15
  interface HtmlnanoOptions {
16
16
  skipConfigLoading?: boolean;
17
+ configPath?: string;
17
18
  skipInternalWarnings?: boolean;
18
19
  collapseAttributeWhitespace?: boolean;
19
20
  collapseBooleanAttributes?: {
@@ -14,6 +14,7 @@ type MaybeArray<T> = T | Array<T>;
14
14
  type PostHTMLNodeLike = PostHTML.Node | string;
15
15
  interface HtmlnanoOptions {
16
16
  skipConfigLoading?: boolean;
17
+ configPath?: string;
17
18
  skipInternalWarnings?: boolean;
18
19
  collapseAttributeWhitespace?: boolean;
19
20
  collapseBooleanAttributes?: {
@@ -14,6 +14,7 @@ type MaybeArray<T> = T | Array<T>;
14
14
  type PostHTMLNodeLike = PostHTML.Node | string;
15
15
  interface HtmlnanoOptions {
16
16
  skipConfigLoading?: boolean;
17
+ configPath?: string;
17
18
  skipInternalWarnings?: boolean;
18
19
  collapseAttributeWhitespace?: boolean;
19
20
  collapseBooleanAttributes?: {
@@ -14,6 +14,7 @@ type MaybeArray<T> = T | Array<T>;
14
14
  type PostHTMLNodeLike = PostHTML.Node | string;
15
15
  interface HtmlnanoOptions {
16
16
  skipConfigLoading?: boolean;
17
+ configPath?: string;
17
18
  skipInternalWarnings?: boolean;
18
19
  collapseAttributeWhitespace?: boolean;
19
20
  collapseBooleanAttributes?: {
@@ -14,6 +14,7 @@ type MaybeArray<T> = T | Array<T>;
14
14
  type PostHTMLNodeLike = PostHTML.Node | string;
15
15
  interface HtmlnanoOptions {
16
16
  skipConfigLoading?: boolean;
17
+ configPath?: string;
17
18
  skipInternalWarnings?: boolean;
18
19
  collapseAttributeWhitespace?: boolean;
19
20
  collapseBooleanAttributes?: {
@@ -14,6 +14,7 @@ type MaybeArray<T> = T | Array<T>;
14
14
  type PostHTMLNodeLike = PostHTML.Node | string;
15
15
  interface HtmlnanoOptions {
16
16
  skipConfigLoading?: boolean;
17
+ configPath?: string;
17
18
  skipInternalWarnings?: boolean;
18
19
  collapseAttributeWhitespace?: boolean;
19
20
  collapseBooleanAttributes?: {
@@ -14,6 +14,7 @@ type MaybeArray<T> = T | Array<T>;
14
14
  type PostHTMLNodeLike = PostHTML.Node | string;
15
15
  interface HtmlnanoOptions {
16
16
  skipConfigLoading?: boolean;
17
+ configPath?: string;
17
18
  skipInternalWarnings?: boolean;
18
19
  collapseAttributeWhitespace?: boolean;
19
20
  collapseBooleanAttributes?: {
@@ -14,6 +14,7 @@ type MaybeArray<T> = T | Array<T>;
14
14
  type PostHTMLNodeLike = PostHTML.Node | string;
15
15
  interface HtmlnanoOptions {
16
16
  skipConfigLoading?: boolean;
17
+ configPath?: string;
17
18
  skipInternalWarnings?: boolean;
18
19
  collapseAttributeWhitespace?: boolean;
19
20
  collapseBooleanAttributes?: {
@@ -14,6 +14,7 @@ type MaybeArray<T> = T | Array<T>;
14
14
  type PostHTMLNodeLike = PostHTML.Node | string;
15
15
  interface HtmlnanoOptions {
16
16
  skipConfigLoading?: boolean;
17
+ configPath?: string;
17
18
  skipInternalWarnings?: boolean;
18
19
  collapseAttributeWhitespace?: boolean;
19
20
  collapseBooleanAttributes?: {
@@ -24,9 +24,8 @@ var helpers_js = require('../helpers.js');
24
24
  const styleMedia = nodeAttrs.media || 'all';
25
25
  const styleKey = styleType + '_' + styleMedia;
26
26
  if (styleKey in styleNodes) {
27
- var _styleNodes_styleKey;
27
+ var _styleNodes_styleKey, _content;
28
28
  const styleContent = helpers_js.extractTextContentFromNode(node);
29
- var _content;
30
29
  (_content = (_styleNodes_styleKey = styleNodes[styleKey]).content) != null ? _content : _styleNodes_styleKey.content = [];
31
30
  styleNodes[styleKey].content.push(' ' + styleContent);
32
31
  return ''; // Remove node
@@ -22,9 +22,8 @@ import { isAmpBoilerplate, extractTextContentFromNode } from '../helpers.mjs';
22
22
  const styleMedia = nodeAttrs.media || 'all';
23
23
  const styleKey = styleType + '_' + styleMedia;
24
24
  if (styleKey in styleNodes) {
25
- var _styleNodes_styleKey;
25
+ var _styleNodes_styleKey, _content;
26
26
  const styleContent = extractTextContentFromNode(node);
27
- var _content;
28
27
  (_content = (_styleNodes_styleKey = styleNodes[styleKey]).content) != null ? _content : _styleNodes_styleKey.content = [];
29
28
  styleNodes[styleKey].content.push(' ' + styleContent);
30
29
  return ''; // Remove node
@@ -14,6 +14,7 @@ type MaybeArray<T> = T | Array<T>;
14
14
  type PostHTMLNodeLike = PostHTML.Node | string;
15
15
  interface HtmlnanoOptions {
16
16
  skipConfigLoading?: boolean;
17
+ configPath?: string;
17
18
  skipInternalWarnings?: boolean;
18
19
  collapseAttributeWhitespace?: boolean;
19
20
  collapseBooleanAttributes?: {
@@ -14,6 +14,7 @@ type MaybeArray<T> = T | Array<T>;
14
14
  type PostHTMLNodeLike = PostHTML.Node | string;
15
15
  interface HtmlnanoOptions {
16
16
  skipConfigLoading?: boolean;
17
+ configPath?: string;
17
18
  skipInternalWarnings?: boolean;
18
19
  collapseAttributeWhitespace?: boolean;
19
20
  collapseBooleanAttributes?: {
@@ -14,6 +14,7 @@ type MaybeArray<T> = T | Array<T>;
14
14
  type PostHTMLNodeLike = PostHTML.Node | string;
15
15
  interface HtmlnanoOptions {
16
16
  skipConfigLoading?: boolean;
17
+ configPath?: string;
17
18
  skipInternalWarnings?: boolean;
18
19
  collapseAttributeWhitespace?: boolean;
19
20
  collapseBooleanAttributes?: {
@@ -14,6 +14,7 @@ type MaybeArray<T> = T | Array<T>;
14
14
  type PostHTMLNodeLike = PostHTML.Node | string;
15
15
  interface HtmlnanoOptions {
16
16
  skipConfigLoading?: boolean;
17
+ configPath?: string;
17
18
  skipInternalWarnings?: boolean;
18
19
  collapseAttributeWhitespace?: boolean;
19
20
  collapseBooleanAttributes?: {
@@ -16,15 +16,22 @@ const postcssOptions = {
16
16
  return tree;
17
17
  }
18
18
  const promises = [];
19
+ let p;
19
20
  tree.walk((node)=>{
20
21
  // Skip SRI, reasons are documented in "minifyJs" module
21
22
  if (node.attrs && 'integrity' in node.attrs) {
22
23
  return node;
23
24
  }
24
25
  if (helpers_js.isStyleNode(node)) {
25
- promises.push(processStyleNode(node, cssnanoOptions, cssnano, postcss));
26
+ p = processStyleNode(node, cssnanoOptions, cssnano, postcss);
27
+ if (p) {
28
+ promises.push(p);
29
+ }
26
30
  } else if (node.attrs && node.attrs.style) {
27
- promises.push(processStyleAttr(node, cssnanoOptions, cssnano, postcss));
31
+ p = processStyleAttr(node, cssnanoOptions, cssnano, postcss);
32
+ if (p) {
33
+ promises.push(p);
34
+ }
28
35
  }
29
36
  return node;
30
37
  });
@@ -14,15 +14,22 @@ const postcssOptions = {
14
14
  return tree;
15
15
  }
16
16
  const promises = [];
17
+ let p;
17
18
  tree.walk((node)=>{
18
19
  // Skip SRI, reasons are documented in "minifyJs" module
19
20
  if (node.attrs && 'integrity' in node.attrs) {
20
21
  return node;
21
22
  }
22
23
  if (isStyleNode(node)) {
23
- promises.push(processStyleNode(node, cssnanoOptions, cssnano, postcss));
24
+ p = processStyleNode(node, cssnanoOptions, cssnano, postcss);
25
+ if (p) {
26
+ promises.push(p);
27
+ }
24
28
  } else if (node.attrs && node.attrs.style) {
25
- promises.push(processStyleAttr(node, cssnanoOptions, cssnano, postcss));
29
+ p = processStyleAttr(node, cssnanoOptions, cssnano, postcss);
30
+ if (p) {
31
+ promises.push(p);
32
+ }
26
33
  }
27
34
  return node;
28
35
  });
@@ -14,6 +14,7 @@ type MaybeArray<T> = T | Array<T>;
14
14
  type PostHTMLNodeLike = PostHTML.Node | string;
15
15
  interface HtmlnanoOptions {
16
16
  skipConfigLoading?: boolean;
17
+ configPath?: string;
17
18
  skipInternalWarnings?: boolean;
18
19
  collapseAttributeWhitespace?: boolean;
19
20
  collapseBooleanAttributes?: {
@@ -14,6 +14,7 @@ type MaybeArray<T> = T | Array<T>;
14
14
  type PostHTMLNodeLike = PostHTML.Node | string;
15
15
  interface HtmlnanoOptions {
16
16
  skipConfigLoading?: boolean;
17
+ configPath?: string;
17
18
  skipInternalWarnings?: boolean;
18
19
  collapseAttributeWhitespace?: boolean;
19
20
  collapseBooleanAttributes?: {
@@ -8,6 +8,7 @@ var removeRedundantAttributes_js = require('./removeRedundantAttributes.js');
8
8
  const terser = await helpers_js.optionalImport('terser');
9
9
  if (!terser) return tree;
10
10
  const promises = [];
11
+ let p;
11
12
  tree.walk((node)=>{
12
13
  const nodeAttrs = node.attrs || {};
13
14
  /**
@@ -27,7 +28,10 @@ var removeRedundantAttributes_js = require('./removeRedundantAttributes.js');
27
28
  if (node.tag && node.tag === 'script') {
28
29
  const mimeType = nodeAttrs.type || 'text/javascript';
29
30
  if (removeRedundantAttributes_js.redundantScriptTypes.has(mimeType) || mimeType === 'module') {
30
- promises.push(processScriptNode(node, terserOptions, terser));
31
+ p = processScriptNode(node, terserOptions, terser);
32
+ if (p) {
33
+ promises.push(p);
34
+ }
31
35
  }
32
36
  }
33
37
  if (node.attrs) {
@@ -6,6 +6,7 @@ import { redundantScriptTypes } from './removeRedundantAttributes.mjs';
6
6
  const terser = await optionalImport('terser');
7
7
  if (!terser) return tree;
8
8
  const promises = [];
9
+ let p;
9
10
  tree.walk((node)=>{
10
11
  const nodeAttrs = node.attrs || {};
11
12
  /**
@@ -25,7 +26,10 @@ import { redundantScriptTypes } from './removeRedundantAttributes.mjs';
25
26
  if (node.tag && node.tag === 'script') {
26
27
  const mimeType = nodeAttrs.type || 'text/javascript';
27
28
  if (redundantScriptTypes.has(mimeType) || mimeType === 'module') {
28
- promises.push(processScriptNode(node, terserOptions, terser));
29
+ p = processScriptNode(node, terserOptions, terser);
30
+ if (p) {
31
+ promises.push(p);
32
+ }
29
33
  }
30
34
  }
31
35
  if (node.attrs) {
@@ -14,6 +14,7 @@ type MaybeArray<T> = T | Array<T>;
14
14
  type PostHTMLNodeLike = PostHTML.Node | string;
15
15
  interface HtmlnanoOptions {
16
16
  skipConfigLoading?: boolean;
17
+ configPath?: string;
17
18
  skipInternalWarnings?: boolean;
18
19
  collapseAttributeWhitespace?: boolean;
19
20
  collapseBooleanAttributes?: {
@@ -14,6 +14,7 @@ type MaybeArray<T> = T | Array<T>;
14
14
  type PostHTMLNodeLike = PostHTML.Node | string;
15
15
  interface HtmlnanoOptions {
16
16
  skipConfigLoading?: boolean;
17
+ configPath?: string;
17
18
  skipInternalWarnings?: boolean;
18
19
  collapseAttributeWhitespace?: boolean;
19
20
  collapseBooleanAttributes?: {
@@ -23,7 +23,7 @@ const mod = {
23
23
  return [
24
24
  JSON.stringify(JSON.parse(jsonContent))
25
25
  ];
26
- } catch (e) {
26
+ } catch (unused) {
27
27
  // Invalid JSON
28
28
  }
29
29
  }
@@ -21,7 +21,7 @@ const mod = {
21
21
  return [
22
22
  JSON.stringify(JSON.parse(jsonContent))
23
23
  ];
24
- } catch (e) {
24
+ } catch (unused) {
25
25
  // Invalid JSON
26
26
  }
27
27
  }
@@ -14,6 +14,7 @@ type MaybeArray<T> = T | Array<T>;
14
14
  type PostHTMLNodeLike = PostHTML.Node | string;
15
15
  interface HtmlnanoOptions {
16
16
  skipConfigLoading?: boolean;
17
+ configPath?: string;
17
18
  skipInternalWarnings?: boolean;
18
19
  collapseAttributeWhitespace?: boolean;
19
20
  collapseBooleanAttributes?: {
@@ -14,6 +14,7 @@ type MaybeArray<T> = T | Array<T>;
14
14
  type PostHTMLNodeLike = PostHTML.Node | string;
15
15
  interface HtmlnanoOptions {
16
16
  skipConfigLoading?: boolean;
17
+ configPath?: string;
17
18
  skipInternalWarnings?: boolean;
18
19
  collapseAttributeWhitespace?: boolean;
19
20
  collapseBooleanAttributes?: {
@@ -24,9 +24,9 @@ var helpers_js = require('../helpers.js');
24
24
  ];
25
25
  return node;
26
26
  } catch (error) {
27
- console.error('htmlnano fails to minify the svg:');
28
- console.error(error);
29
- if (error && typeof error === 'object' && 'name' in error && error.name === 'SvgoParserError') {
27
+ const isSvgoParserError = Boolean(error && typeof error === 'object' && 'name' in error && error.name === 'SvgoParserError');
28
+ if (!options.skipInternalWarnings && !isSvgoParserError) {
29
+ console.error('htmlnano fails to minify the svg:');
30
30
  console.error(error);
31
31
  }
32
32
  // We return the node as-is
@@ -22,9 +22,9 @@ import { optionalImport } from '../helpers.mjs';
22
22
  ];
23
23
  return node;
24
24
  } catch (error) {
25
- console.error('htmlnano fails to minify the svg:');
26
- console.error(error);
27
- if (error && typeof error === 'object' && 'name' in error && error.name === 'SvgoParserError') {
25
+ const isSvgoParserError = Boolean(error && typeof error === 'object' && 'name' in error && error.name === 'SvgoParserError');
26
+ if (!options.skipInternalWarnings && !isSvgoParserError) {
27
+ console.error('htmlnano fails to minify the svg:');
28
28
  console.error(error);
29
29
  }
30
30
  // We return the node as-is
@@ -14,6 +14,7 @@ type MaybeArray<T> = T | Array<T>;
14
14
  type PostHTMLNodeLike = PostHTML.Node | string;
15
15
  interface HtmlnanoOptions {
16
16
  skipConfigLoading?: boolean;
17
+ configPath?: string;
17
18
  skipInternalWarnings?: boolean;
18
19
  collapseAttributeWhitespace?: boolean;
19
20
  collapseBooleanAttributes?: {
@@ -14,6 +14,7 @@ type MaybeArray<T> = T | Array<T>;
14
14
  type PostHTMLNodeLike = PostHTML.Node | string;
15
15
  interface HtmlnanoOptions {
16
16
  skipConfigLoading?: boolean;
17
+ configPath?: string;
17
18
  skipInternalWarnings?: boolean;
18
19
  collapseAttributeWhitespace?: boolean;
19
20
  collapseBooleanAttributes?: {
@@ -144,7 +144,7 @@ let STORED_URL_BASE;
144
144
  }
145
145
  return item;
146
146
  }));
147
- } catch (e) {
147
+ } catch (unused) {
148
148
  // srcset will throw an Error for invalid srcset.
149
149
  }
150
150
  }
@@ -142,7 +142,7 @@ let STORED_URL_BASE;
142
142
  }
143
143
  return item;
144
144
  }));
145
- } catch (e) {
145
+ } catch (unused) {
146
146
  // srcset will throw an Error for invalid srcset.
147
147
  }
148
148
  }
@@ -14,6 +14,7 @@ type MaybeArray<T> = T | Array<T>;
14
14
  type PostHTMLNodeLike = PostHTML.Node | string;
15
15
  interface HtmlnanoOptions {
16
16
  skipConfigLoading?: boolean;
17
+ configPath?: string;
17
18
  skipInternalWarnings?: boolean;
18
19
  collapseAttributeWhitespace?: boolean;
19
20
  collapseBooleanAttributes?: {
@@ -14,6 +14,7 @@ type MaybeArray<T> = T | Array<T>;
14
14
  type PostHTMLNodeLike = PostHTML.Node | string;
15
15
  interface HtmlnanoOptions {
16
16
  skipConfigLoading?: boolean;
17
+ configPath?: string;
17
18
  skipInternalWarnings?: boolean;
18
19
  collapseAttributeWhitespace?: boolean;
19
20
  collapseBooleanAttributes?: {
@@ -14,6 +14,7 @@ type MaybeArray<T> = T | Array<T>;
14
14
  type PostHTMLNodeLike = PostHTML.Node | string;
15
15
  interface HtmlnanoOptions {
16
16
  skipConfigLoading?: boolean;
17
+ configPath?: string;
17
18
  skipInternalWarnings?: boolean;
18
19
  collapseAttributeWhitespace?: boolean;
19
20
  collapseBooleanAttributes?: {
@@ -14,6 +14,7 @@ type MaybeArray<T> = T | Array<T>;
14
14
  type PostHTMLNodeLike = PostHTML.Node | string;
15
15
  interface HtmlnanoOptions {
16
16
  skipConfigLoading?: boolean;
17
+ configPath?: string;
17
18
  skipInternalWarnings?: boolean;
18
19
  collapseAttributeWhitespace?: boolean;
19
20
  collapseBooleanAttributes?: {
@@ -5,8 +5,7 @@ Object.defineProperty(exports, '__esModule', { value: true });
5
5
  // See also: https://github.com/posthtml/htmlnano/issues/6#issuecomment-707105334
6
6
  /** Disable quoteAllAttributes while not overriding the configuration */ const mod = {
7
7
  default: function removeAttributeQuotes(tree) {
8
- var _tree_options;
9
- var _quoteAllAttributes;
8
+ var _tree_options, _quoteAllAttributes;
10
9
  if (tree.options) (_quoteAllAttributes = (_tree_options = tree.options).quoteAllAttributes) != null ? _quoteAllAttributes : _tree_options.quoteAllAttributes = false;
11
10
  return tree;
12
11
  }
@@ -3,8 +3,7 @@
3
3
  // See also: https://github.com/posthtml/htmlnano/issues/6#issuecomment-707105334
4
4
  /** Disable quoteAllAttributes while not overriding the configuration */ const mod = {
5
5
  default: function removeAttributeQuotes(tree) {
6
- var _tree_options;
7
- var _quoteAllAttributes;
6
+ var _tree_options, _quoteAllAttributes;
8
7
  if (tree.options) (_quoteAllAttributes = (_tree_options = tree.options).quoteAllAttributes) != null ? _quoteAllAttributes : _tree_options.quoteAllAttributes = false;
9
8
  return tree;
10
9
  }
@@ -14,6 +14,7 @@ type MaybeArray<T> = T | Array<T>;
14
14
  type PostHTMLNodeLike = PostHTML.Node | string;
15
15
  interface HtmlnanoOptions {
16
16
  skipConfigLoading?: boolean;
17
+ configPath?: string;
17
18
  skipInternalWarnings?: boolean;
18
19
  collapseAttributeWhitespace?: boolean;
19
20
  collapseBooleanAttributes?: {
@@ -14,6 +14,7 @@ type MaybeArray<T> = T | Array<T>;
14
14
  type PostHTMLNodeLike = PostHTML.Node | string;
15
15
  interface HtmlnanoOptions {
16
16
  skipConfigLoading?: boolean;
17
+ configPath?: string;
17
18
  skipInternalWarnings?: boolean;
18
19
  collapseAttributeWhitespace?: boolean;
19
20
  collapseBooleanAttributes?: {
@@ -14,6 +14,7 @@ type MaybeArray<T> = T | Array<T>;
14
14
  type PostHTMLNodeLike = PostHTML.Node | string;
15
15
  interface HtmlnanoOptions {
16
16
  skipConfigLoading?: boolean;
17
+ configPath?: string;
17
18
  skipInternalWarnings?: boolean;
18
19
  collapseAttributeWhitespace?: boolean;
19
20
  collapseBooleanAttributes?: {
@@ -14,6 +14,7 @@ type MaybeArray<T> = T | Array<T>;
14
14
  type PostHTMLNodeLike = PostHTML.Node | string;
15
15
  interface HtmlnanoOptions {
16
16
  skipConfigLoading?: boolean;
17
+ configPath?: string;
17
18
  skipInternalWarnings?: boolean;
18
19
  collapseAttributeWhitespace?: boolean;
19
20
  collapseBooleanAttributes?: {
@@ -14,6 +14,7 @@ type MaybeArray<T> = T | Array<T>;
14
14
  type PostHTMLNodeLike = PostHTML.Node | string;
15
15
  interface HtmlnanoOptions {
16
16
  skipConfigLoading?: boolean;
17
+ configPath?: string;
17
18
  skipInternalWarnings?: boolean;
18
19
  collapseAttributeWhitespace?: boolean;
19
20
  collapseBooleanAttributes?: {
@@ -14,6 +14,7 @@ type MaybeArray<T> = T | Array<T>;
14
14
  type PostHTMLNodeLike = PostHTML.Node | string;
15
15
  interface HtmlnanoOptions {
16
16
  skipConfigLoading?: boolean;
17
+ configPath?: string;
17
18
  skipInternalWarnings?: boolean;
18
19
  collapseAttributeWhitespace?: boolean;
19
20
  collapseBooleanAttributes?: {
@@ -14,6 +14,7 @@ type MaybeArray<T> = T | Array<T>;
14
14
  type PostHTMLNodeLike = PostHTML.Node | string;
15
15
  interface HtmlnanoOptions {
16
16
  skipConfigLoading?: boolean;
17
+ configPath?: string;
17
18
  skipInternalWarnings?: boolean;
18
19
  collapseAttributeWhitespace?: boolean;
19
20
  collapseBooleanAttributes?: {
@@ -14,6 +14,7 @@ type MaybeArray<T> = T | Array<T>;
14
14
  type PostHTMLNodeLike = PostHTML.Node | string;
15
15
  interface HtmlnanoOptions {
16
16
  skipConfigLoading?: boolean;
17
+ configPath?: string;
17
18
  skipInternalWarnings?: boolean;
18
19
  collapseAttributeWhitespace?: boolean;
19
20
  collapseBooleanAttributes?: {
@@ -14,6 +14,7 @@ type MaybeArray<T> = T | Array<T>;
14
14
  type PostHTMLNodeLike = PostHTML.Node | string;
15
15
  interface HtmlnanoOptions {
16
16
  skipConfigLoading?: boolean;
17
+ configPath?: string;
17
18
  skipInternalWarnings?: boolean;
18
19
  collapseAttributeWhitespace?: boolean;
19
20
  collapseBooleanAttributes?: {
@@ -14,6 +14,7 @@ type MaybeArray<T> = T | Array<T>;
14
14
  type PostHTMLNodeLike = PostHTML.Node | string;
15
15
  interface HtmlnanoOptions {
16
16
  skipConfigLoading?: boolean;
17
+ configPath?: string;
17
18
  skipInternalWarnings?: boolean;
18
19
  collapseAttributeWhitespace?: boolean;
19
20
  collapseBooleanAttributes?: {
@@ -14,6 +14,7 @@ type MaybeArray<T> = T | Array<T>;
14
14
  type PostHTMLNodeLike = PostHTML.Node | string;
15
15
  interface HtmlnanoOptions {
16
16
  skipConfigLoading?: boolean;
17
+ configPath?: string;
17
18
  skipInternalWarnings?: boolean;
18
19
  collapseAttributeWhitespace?: boolean;
19
20
  collapseBooleanAttributes?: {
@@ -14,6 +14,7 @@ type MaybeArray<T> = T | Array<T>;
14
14
  type PostHTMLNodeLike = PostHTML.Node | string;
15
15
  interface HtmlnanoOptions {
16
16
  skipConfigLoading?: boolean;
17
+ configPath?: string;
17
18
  skipInternalWarnings?: boolean;
18
19
  collapseAttributeWhitespace?: boolean;
19
20
  collapseBooleanAttributes?: {
@@ -14,6 +14,7 @@ type MaybeArray<T> = T | Array<T>;
14
14
  type PostHTMLNodeLike = PostHTML.Node | string;
15
15
  interface HtmlnanoOptions {
16
16
  skipConfigLoading?: boolean;
17
+ configPath?: string;
17
18
  skipInternalWarnings?: boolean;
18
19
  collapseAttributeWhitespace?: boolean;
19
20
  collapseBooleanAttributes?: {
@@ -14,6 +14,7 @@ type MaybeArray<T> = T | Array<T>;
14
14
  type PostHTMLNodeLike = PostHTML.Node | string;
15
15
  interface HtmlnanoOptions {
16
16
  skipConfigLoading?: boolean;
17
+ configPath?: string;
17
18
  skipInternalWarnings?: boolean;
18
19
  collapseAttributeWhitespace?: boolean;
19
20
  collapseBooleanAttributes?: {
package/dist/bin.js ADDED
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/env node
2
+ var commander = require('commander');
3
+ var fs = require('fs');
4
+ var process = require('process');
5
+ var index_js = require('./index.js');
6
+
7
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
8
+
9
+ var fs__default = /*#__PURE__*/_interopDefault(fs);
10
+ var process__default = /*#__PURE__*/_interopDefault(process);
11
+
12
+ commander.program.name('htmlnano').description('Minify HTML with htmlnano').argument('[input]', 'input file', '-').option('-o, --output <file>', 'output file', '-').option('-p, --preset <preset>', 'preset to use', 'safe').option('-c, --config <file>', 'path to config file').action(async (input, options)=>{
13
+ const { preset, output } = options;
14
+ if (!preset || !(preset in index_js.presets)) {
15
+ const available = Object.keys(index_js.presets).join(', ');
16
+ process__default.default.stderr.write(`Unknown preset: ${preset}. Available presets: ${available}\n`);
17
+ process__default.default.exitCode = 1;
18
+ return;
19
+ }
20
+ const html = fs__default.default.readFileSync(input && input !== '-' ? input : 0, 'utf8');
21
+ const key = preset;
22
+ const chosenPreset = index_js.presets[key];
23
+ const htmlnanoOptions = {};
24
+ if (options.config) {
25
+ htmlnanoOptions.configPath = options.config;
26
+ }
27
+ const result = await index_js.process(html, htmlnanoOptions, chosenPreset);
28
+ if (output && output !== '-') {
29
+ fs__default.default.writeFileSync(output, result.html);
30
+ } else {
31
+ process__default.default.stdout.write(result.html);
32
+ }
33
+ });
34
+ commander.program.parse();
package/dist/index.d.ts CHANGED
@@ -14,6 +14,7 @@ type MaybeArray<T> = T | Array<T>;
14
14
  type PostHTMLNodeLike = PostHTML.Node | string;
15
15
  interface HtmlnanoOptions {
16
16
  skipConfigLoading?: boolean;
17
+ configPath?: string;
17
18
  skipInternalWarnings?: boolean;
18
19
  collapseAttributeWhitespace?: boolean;
19
20
  collapseBooleanAttributes?: {
@@ -40,11 +41,11 @@ interface HtmlnanoOptions {
40
41
  sortAttributes?: boolean | 'alphabetical' | 'frequency';
41
42
  sortAttributesWithLists?: boolean | 'alphabetical' | 'frequency';
42
43
  }
43
- interface HtmlnanoPreset extends Omit<HtmlnanoOptions, 'skipConfigLoading'> {
44
+ interface HtmlnanoPreset extends Omit<HtmlnanoOptions, 'skipConfigLoading' | 'configPath'> {
44
45
  }
45
46
  type HtmlnanoPredefinedPreset = 'safe' | 'ampSafe' | 'max';
46
47
  type HtmlnanoPredefinedPresets = Record<HtmlnanoPredefinedPreset, HtmlnanoPreset>;
47
- type HtmlnanoOptionsConfigFile = Omit<HtmlnanoOptions, 'skipConfigLoading'> & {
48
+ type HtmlnanoOptionsConfigFile = Omit<HtmlnanoOptions, 'skipConfigLoading' | 'configPath'> & {
48
49
  preset?: HtmlnanoPredefinedPreset;
49
50
  };
50
51
  type HtmlnanoModuleAttrsHandler = (attrs: Record<string, string | boolean | void>, node: PostHTML.Node) => Record<string, string | boolean | void>;
@@ -58,15 +59,15 @@ type HtmlnanoModule<Options = any> = {
58
59
  default?: (tree: PostHTMLTreeLike, options: Partial<HtmlnanoOptions>, moduleOptions: OptionalOptions<Options>) => PostHTMLTreeLike | Promise<PostHTMLTreeLike>;
59
60
  };
60
61
 
61
- declare function loadConfig(options?: HtmlnanoOptions, preset?: HtmlnanoPreset, configPath?: string): [Partial<HtmlnanoOptions>, HtmlnanoPreset];
62
- declare function htmlnano(optionsRun?: HtmlnanoOptions, presetRun?: HtmlnanoPreset): PostHTML.Plugin<never>;
63
- declare namespace htmlnano {
64
- var presets: HtmlnanoPredefinedPresets;
65
- var getRequiredOptionalDependencies: typeof getRequiredOptionalDependencies;
66
- var process: typeof process;
67
- var htmlMinimizerWebpackPluginMinify: typeof htmlMinimizerWebpackPluginMinify;
68
- var loadConfig: typeof loadConfig;
69
- }
62
+ declare const presets: HtmlnanoPredefinedPresets;
63
+ declare function loadConfig(options?: HtmlnanoOptions, preset?: HtmlnanoPreset): [Partial<HtmlnanoOptions>, HtmlnanoPreset];
64
+ declare const htmlnano: ((optionsRun?: HtmlnanoOptions, presetRun?: HtmlnanoPreset) => PostHTML.Plugin<never>) & {
65
+ presets: HtmlnanoPredefinedPresets;
66
+ getRequiredOptionalDependencies: typeof getRequiredOptionalDependencies;
67
+ process: typeof process;
68
+ htmlMinimizerWebpackPluginMinify: typeof htmlMinimizerWebpackPluginMinify;
69
+ loadConfig: typeof loadConfig;
70
+ };
70
71
  declare function getRequiredOptionalDependencies(optionsRun: HtmlnanoOptions, presetRun: HtmlnanoPreset): string[];
71
72
  declare function process(html: string, options?: HtmlnanoOptions, preset?: HtmlnanoPreset, postHtmlOptions?: PostHTML.Options): Promise<PostHTML.Result<unknown>>;
72
73
  declare function htmlMinimizerWebpackPluginMinify(input: {
@@ -75,5 +76,5 @@ declare function htmlMinimizerWebpackPluginMinify(input: {
75
76
  code: string;
76
77
  }>;
77
78
 
78
- export { htmlnano as default, getRequiredOptionalDependencies, htmlMinimizerWebpackPluginMinify, htmlnano, loadConfig, process };
79
+ export { htmlnano as default, getRequiredOptionalDependencies, htmlMinimizerWebpackPluginMinify, loadConfig, presets, process };
79
80
  export type { HtmlnanoModule, HtmlnanoModuleAttrsHandler, HtmlnanoModuleContentHandler, HtmlnanoModuleNodeHandler, HtmlnanoOptions, HtmlnanoOptionsConfigFile, HtmlnanoPredefinedPreset, HtmlnanoPredefinedPresets, HtmlnanoPreset, PostHTMLNodeLike, PostHTMLTreeLike };
package/dist/index.js CHANGED
@@ -18,8 +18,8 @@ const presets = {
18
18
  ampSafe: ampSafePreset__default.default,
19
19
  max: maxPreset__default.default
20
20
  };
21
- function loadConfig(options, preset, configPath) {
22
- const { skipConfigLoading = false, ...rest } = options || {};
21
+ function loadConfig(options, preset) {
22
+ const { skipConfigLoading = false, configPath, ...rest } = options || {};
23
23
  let restConfig = rest;
24
24
  if (!skipConfigLoading) {
25
25
  const explorer = cosmiconfig.cosmiconfigSync('htmlnano');
@@ -32,9 +32,10 @@ function loadConfig(options, preset, configPath) {
32
32
  }
33
33
  delete rc.config.preset;
34
34
  }
35
- if (!options) {
36
- restConfig = rc.config;
37
- }
35
+ restConfig = {
36
+ ...rc.config,
37
+ ...restConfig
38
+ };
38
39
  }
39
40
  }
40
41
  return [
@@ -59,7 +60,60 @@ const optionalDependencies = {
59
60
  'svgo'
60
61
  ]
61
62
  };
62
- const interop = (imported)=>imported.then((mod)=>mod.default);
63
+ /**
64
+ * And the old mixing named export and default export again.
65
+ *
66
+ * TL; DR: our bundler has bundled our mixed default/named export module into a "exports" object,
67
+ * and when dynamically importing a CommonJS module using "import" instead of "require", Node.js wraps
68
+ * another layer of default around the "exports" object.
69
+ *
70
+ * The longer version:
71
+ *
72
+ * The bundler we are using outputs:
73
+ *
74
+ * ESM: export { [named], xxx as default }
75
+ * CJS: exports.default = xxx; exports.[named] = ...; exports.__esModule = true;
76
+ *
77
+ * With ESM, the Module object looks like this:
78
+ *
79
+ * ```js
80
+ * Module {
81
+ * default: xxx,
82
+ * [named]: ...,
83
+ * }
84
+ * ```
85
+ *
86
+ * With CJS, Node.js handles dynamic import differently. Node.js doesn't respect `__esModule`,
87
+ * and will wrongly treat a CommonJS module as ESM, i.e. assign the "exports" object on its
88
+ * own "default" on the "Module" object.
89
+ *
90
+ * Now we have:
91
+ *
92
+ * ```js
93
+ * Module {
94
+ * // this is actually the "exports" inside among "exports.__esModule", "exports.[named]", and "exports.default"
95
+ * default: {
96
+ * __esModule: true,
97
+ * // This is the actual "exports.default"
98
+ * default: xxx
99
+ * }
100
+ * }
101
+ * ```
102
+ */ const interop = (imported)=>imported.then((mod)=>{
103
+ let htmlnanoModule;
104
+ while('default' in mod){
105
+ htmlnanoModule = mod;
106
+ mod = mod.default;
107
+ // If we find any htmlnano module hook methods, we know this object is a htmlnano module, return directly
108
+ if ('onAttrs' in mod || 'onContent' in mod || 'onNode' in mod) {
109
+ return mod;
110
+ }
111
+ }
112
+ if (htmlnanoModule && typeof htmlnanoModule.default === 'function') {
113
+ return htmlnanoModule;
114
+ }
115
+ throw new TypeError('The imported module is not a valid htmlnano module');
116
+ });
63
117
  const modules = {
64
118
  collapseAttributeWhitespace: ()=>interop(import('./_modules/collapseAttributeWhitespace.js')),
65
119
  collapseBooleanAttributes: ()=>interop(import('./_modules/collapseBooleanAttributes.js')),
@@ -85,7 +139,7 @@ const modules = {
85
139
  sortAttributes: ()=>interop(import('./_modules/sortAttributes.js')),
86
140
  sortAttributesWithLists: ()=>interop(import('./_modules/sortAttributesWithLists.js'))
87
141
  };
88
- function htmlnano(optionsRun = {}, presetRun) {
142
+ const htmlnano = Object.assign(function htmlnano(optionsRun = {}, presetRun) {
89
143
  // eslint-disable-next-line prefer-const -- re-assign options
90
144
  let [options, preset] = loadConfig(optionsRun, presetRun);
91
145
  const minifier = async (_tree)=>{
@@ -180,7 +234,13 @@ function htmlnano(optionsRun = {}, presetRun) {
180
234
  });
181
235
  };
182
236
  return minifier;
183
- }
237
+ }, {
238
+ presets,
239
+ getRequiredOptionalDependencies,
240
+ process,
241
+ htmlMinimizerWebpackPluginMinify,
242
+ loadConfig
243
+ });
184
244
  function getRequiredOptionalDependencies(optionsRun, presetRun) {
185
245
  const [options] = loadConfig(optionsRun, presetRun);
186
246
  return Array.from(Object.keys(options).reduce((acc, moduleName)=>{
@@ -200,17 +260,12 @@ function process(html, options, preset, postHtmlOptions) {
200
260
  // https://github.com/webpack-contrib/html-minimizer-webpack-plugin/blob/faca00f2219514bc671c5942685721f0b5dbaa70/src/utils.js#L74
201
261
  function htmlMinimizerWebpackPluginMinify(input, minimizerOptions) {
202
262
  const [[, code]] = Object.entries(input);
203
- return htmlnano.process(code, minimizerOptions, presets.safe).then((result)=>{
263
+ return process(code, minimizerOptions, presets.safe).then((result)=>{
204
264
  return {
205
265
  code: result.html
206
266
  };
207
267
  });
208
268
  }
209
- htmlnano.presets = presets;
210
- htmlnano.getRequiredOptionalDependencies = getRequiredOptionalDependencies;
211
- htmlnano.process = process;
212
- htmlnano.htmlMinimizerWebpackPluginMinify = htmlMinimizerWebpackPluginMinify;
213
- htmlnano.loadConfig = loadConfig;
214
269
  if (typeof module !== 'undefined') {
215
270
  module.exports = htmlnano;
216
271
  }
@@ -218,6 +273,6 @@ if (typeof module !== 'undefined') {
218
273
  exports.default = htmlnano;
219
274
  exports.getRequiredOptionalDependencies = getRequiredOptionalDependencies;
220
275
  exports.htmlMinimizerWebpackPluginMinify = htmlMinimizerWebpackPluginMinify;
221
- exports.htmlnano = htmlnano;
222
276
  exports.loadConfig = loadConfig;
277
+ exports.presets = presets;
223
278
  exports.process = process;
package/dist/index.mjs CHANGED
@@ -9,8 +9,8 @@ const presets = {
9
9
  ampSafe: ampSafePreset,
10
10
  max: maxPreset
11
11
  };
12
- function loadConfig(options, preset, configPath) {
13
- const { skipConfigLoading = false, ...rest } = options || {};
12
+ function loadConfig(options, preset) {
13
+ const { skipConfigLoading = false, configPath, ...rest } = options || {};
14
14
  let restConfig = rest;
15
15
  if (!skipConfigLoading) {
16
16
  const explorer = cosmiconfigSync('htmlnano');
@@ -23,9 +23,10 @@ function loadConfig(options, preset, configPath) {
23
23
  }
24
24
  delete rc.config.preset;
25
25
  }
26
- if (!options) {
27
- restConfig = rc.config;
28
- }
26
+ restConfig = {
27
+ ...rc.config,
28
+ ...restConfig
29
+ };
29
30
  }
30
31
  }
31
32
  return [
@@ -50,7 +51,60 @@ const optionalDependencies = {
50
51
  'svgo'
51
52
  ]
52
53
  };
53
- const interop = (imported)=>imported.then((mod)=>mod.default);
54
+ /**
55
+ * And the old mixing named export and default export again.
56
+ *
57
+ * TL; DR: our bundler has bundled our mixed default/named export module into a "exports" object,
58
+ * and when dynamically importing a CommonJS module using "import" instead of "require", Node.js wraps
59
+ * another layer of default around the "exports" object.
60
+ *
61
+ * The longer version:
62
+ *
63
+ * The bundler we are using outputs:
64
+ *
65
+ * ESM: export { [named], xxx as default }
66
+ * CJS: exports.default = xxx; exports.[named] = ...; exports.__esModule = true;
67
+ *
68
+ * With ESM, the Module object looks like this:
69
+ *
70
+ * ```js
71
+ * Module {
72
+ * default: xxx,
73
+ * [named]: ...,
74
+ * }
75
+ * ```
76
+ *
77
+ * With CJS, Node.js handles dynamic import differently. Node.js doesn't respect `__esModule`,
78
+ * and will wrongly treat a CommonJS module as ESM, i.e. assign the "exports" object on its
79
+ * own "default" on the "Module" object.
80
+ *
81
+ * Now we have:
82
+ *
83
+ * ```js
84
+ * Module {
85
+ * // this is actually the "exports" inside among "exports.__esModule", "exports.[named]", and "exports.default"
86
+ * default: {
87
+ * __esModule: true,
88
+ * // This is the actual "exports.default"
89
+ * default: xxx
90
+ * }
91
+ * }
92
+ * ```
93
+ */ const interop = (imported)=>imported.then((mod)=>{
94
+ let htmlnanoModule;
95
+ while('default' in mod){
96
+ htmlnanoModule = mod;
97
+ mod = mod.default;
98
+ // If we find any htmlnano module hook methods, we know this object is a htmlnano module, return directly
99
+ if ('onAttrs' in mod || 'onContent' in mod || 'onNode' in mod) {
100
+ return mod;
101
+ }
102
+ }
103
+ if (htmlnanoModule && typeof htmlnanoModule.default === 'function') {
104
+ return htmlnanoModule;
105
+ }
106
+ throw new TypeError('The imported module is not a valid htmlnano module');
107
+ });
54
108
  const modules = {
55
109
  collapseAttributeWhitespace: ()=>interop(import('./_modules/collapseAttributeWhitespace.mjs')),
56
110
  collapseBooleanAttributes: ()=>interop(import('./_modules/collapseBooleanAttributes.mjs')),
@@ -76,7 +130,7 @@ const modules = {
76
130
  sortAttributes: ()=>interop(import('./_modules/sortAttributes.mjs')),
77
131
  sortAttributesWithLists: ()=>interop(import('./_modules/sortAttributesWithLists.mjs'))
78
132
  };
79
- function htmlnano(optionsRun = {}, presetRun) {
133
+ const htmlnano = Object.assign(function htmlnano(optionsRun = {}, presetRun) {
80
134
  // eslint-disable-next-line prefer-const -- re-assign options
81
135
  let [options, preset] = loadConfig(optionsRun, presetRun);
82
136
  const minifier = async (_tree)=>{
@@ -171,7 +225,13 @@ function htmlnano(optionsRun = {}, presetRun) {
171
225
  });
172
226
  };
173
227
  return minifier;
174
- }
228
+ }, {
229
+ presets,
230
+ getRequiredOptionalDependencies,
231
+ process,
232
+ htmlMinimizerWebpackPluginMinify,
233
+ loadConfig
234
+ });
175
235
  function getRequiredOptionalDependencies(optionsRun, presetRun) {
176
236
  const [options] = loadConfig(optionsRun, presetRun);
177
237
  return Array.from(Object.keys(options).reduce((acc, moduleName)=>{
@@ -191,19 +251,14 @@ function process(html, options, preset, postHtmlOptions) {
191
251
  // https://github.com/webpack-contrib/html-minimizer-webpack-plugin/blob/faca00f2219514bc671c5942685721f0b5dbaa70/src/utils.js#L74
192
252
  function htmlMinimizerWebpackPluginMinify(input, minimizerOptions) {
193
253
  const [[, code]] = Object.entries(input);
194
- return htmlnano.process(code, minimizerOptions, presets.safe).then((result)=>{
254
+ return process(code, minimizerOptions, presets.safe).then((result)=>{
195
255
  return {
196
256
  code: result.html
197
257
  };
198
258
  });
199
259
  }
200
- htmlnano.presets = presets;
201
- htmlnano.getRequiredOptionalDependencies = getRequiredOptionalDependencies;
202
- htmlnano.process = process;
203
- htmlnano.htmlMinimizerWebpackPluginMinify = htmlMinimizerWebpackPluginMinify;
204
- htmlnano.loadConfig = loadConfig;
205
260
  if (typeof module !== 'undefined') {
206
261
  module.exports = htmlnano;
207
262
  }
208
263
 
209
- export { htmlnano as default, getRequiredOptionalDependencies, htmlMinimizerWebpackPluginMinify, htmlnano, loadConfig, process };
264
+ export { htmlnano as default, getRequiredOptionalDependencies, htmlMinimizerWebpackPluginMinify, loadConfig, presets, process };
@@ -13,6 +13,7 @@ type PostHTMLTreeLike = [PostHTML.Node] & PostHTML.NodeAPI & {
13
13
  type MaybeArray<T> = T | Array<T>;
14
14
  interface HtmlnanoOptions {
15
15
  skipConfigLoading?: boolean;
16
+ configPath?: string;
16
17
  skipInternalWarnings?: boolean;
17
18
  collapseAttributeWhitespace?: boolean;
18
19
  collapseBooleanAttributes?: {
@@ -39,7 +40,7 @@ interface HtmlnanoOptions {
39
40
  sortAttributes?: boolean | 'alphabetical' | 'frequency';
40
41
  sortAttributesWithLists?: boolean | 'alphabetical' | 'frequency';
41
42
  }
42
- interface HtmlnanoPreset extends Omit<HtmlnanoOptions, 'skipConfigLoading'> {
43
+ interface HtmlnanoPreset extends Omit<HtmlnanoOptions, 'skipConfigLoading' | 'configPath'> {
43
44
  }
44
45
 
45
46
  declare const _default: HtmlnanoPreset;
@@ -13,6 +13,7 @@ type PostHTMLTreeLike = [PostHTML.Node] & PostHTML.NodeAPI & {
13
13
  type MaybeArray<T> = T | Array<T>;
14
14
  interface HtmlnanoOptions {
15
15
  skipConfigLoading?: boolean;
16
+ configPath?: string;
16
17
  skipInternalWarnings?: boolean;
17
18
  collapseAttributeWhitespace?: boolean;
18
19
  collapseBooleanAttributes?: {
@@ -39,7 +40,7 @@ interface HtmlnanoOptions {
39
40
  sortAttributes?: boolean | 'alphabetical' | 'frequency';
40
41
  sortAttributesWithLists?: boolean | 'alphabetical' | 'frequency';
41
42
  }
42
- interface HtmlnanoPreset extends Omit<HtmlnanoOptions, 'skipConfigLoading'> {
43
+ interface HtmlnanoPreset extends Omit<HtmlnanoOptions, 'skipConfigLoading' | 'configPath'> {
43
44
  }
44
45
 
45
46
  declare const _default: HtmlnanoPreset;
@@ -13,6 +13,7 @@ type PostHTMLTreeLike = [PostHTML.Node] & PostHTML.NodeAPI & {
13
13
  type MaybeArray<T> = T | Array<T>;
14
14
  interface HtmlnanoOptions {
15
15
  skipConfigLoading?: boolean;
16
+ configPath?: string;
16
17
  skipInternalWarnings?: boolean;
17
18
  collapseAttributeWhitespace?: boolean;
18
19
  collapseBooleanAttributes?: {
@@ -39,7 +40,7 @@ interface HtmlnanoOptions {
39
40
  sortAttributes?: boolean | 'alphabetical' | 'frequency';
40
41
  sortAttributesWithLists?: boolean | 'alphabetical' | 'frequency';
41
42
  }
42
- interface HtmlnanoPreset extends Omit<HtmlnanoOptions, 'skipConfigLoading'> {
43
+ interface HtmlnanoPreset extends Omit<HtmlnanoOptions, 'skipConfigLoading' | 'configPath'> {
43
44
  }
44
45
 
45
46
  declare const _default: HtmlnanoPreset;
package/package.json CHANGED
@@ -1,17 +1,18 @@
1
1
  {
2
2
  "name": "htmlnano",
3
- "version": "2.1.4",
3
+ "version": "3.0.0",
4
4
  "description": "Modular HTML minifier, built on top of the PostHTML",
5
5
  "author": "Kirill Maltsev <maltsevkirill@gmail.com>",
6
6
  "license": "MIT",
7
7
  "scripts": {
8
8
  "clean": "rimraf dist",
9
9
  "build": "npm run clean && bunchee",
10
+ "postbuild": "chmod +x dist/bin.js",
10
11
  "compile": "npm run build",
11
12
  "lint": "eslint --fix .",
12
13
  "pretest": "npm run lint && npm run compile",
13
14
  "test": ":",
14
- "posttest": "mocha --timeout 5000 --require @swc-node/register --recursive --check-leaks --globals addresses",
15
+ "posttest": "mocha --timeout 5000 --require @swc-node/register --recursive --check-leaks --globals addresses 'test/**/*.ts'",
15
16
  "prepare": "npm run compile"
16
17
  },
17
18
  "files": [
@@ -19,6 +20,7 @@
19
20
  ],
20
21
  "main": "./dist/index.js",
21
22
  "module": "./dist/index.mjs",
23
+ "bin": "./dist/bin.js",
22
24
  "exports": {
23
25
  "./helpers": {
24
26
  "types": "./dist/helpers.d.ts",
@@ -55,13 +57,16 @@
55
57
  ],
56
58
  "dependencies": {
57
59
  "@types/relateurl": "^0.2.33",
60
+ "commander": "^14.0.0",
58
61
  "cosmiconfig": "^9.0.0",
59
62
  "posthtml": "^0.16.5"
60
63
  },
61
64
  "devDependencies": {
65
+ "@eslint/js": "^9.35.0",
62
66
  "@stylistic/eslint-plugin": "^5.3.1",
63
67
  "@swc-node/register": "^1.10.10",
64
- "@types/node": "^24.0.0",
68
+ "@types/mocha": "^10.0.10",
69
+ "@types/node": "^25.0.0",
65
70
  "bunchee": "^6.5.1",
66
71
  "cssnano": "^7.0.0",
67
72
  "eslint": "^9.25.1",
@@ -76,11 +81,11 @@
76
81
  "purgecss": "^7.0.2",
77
82
  "relateurl": "^0.2.7",
78
83
  "rimraf": "^6.0.0",
79
- "srcset": "5.0.1",
80
- "svgo": "^3.0.2",
84
+ "srcset": "^5.0.1",
85
+ "svgo": "^4.0.0",
81
86
  "terser": "^5.21.0",
82
87
  "typescript": "^5.8.3",
83
- "typescript-eslint": "^8.31.1",
88
+ "typescript-eslint": "^8.44.0",
84
89
  "uncss": "^0.17.3"
85
90
  },
86
91
  "peerDependencies": {
@@ -126,6 +131,5 @@
126
131
  "bugs": {
127
132
  "url": "https://github.com/posthtml/htmlnano/issues"
128
133
  },
129
- "homepage": "https://github.com/posthtml/htmlnano",
130
- "packageManager": "pnpm@10.10.0+sha512.d615db246fe70f25dcfea6d8d73dee782ce23e2245e3c4f6f888249fb568149318637dca73c2c5c8ef2a4ca0d5657fb9567188bfab47f566d1ee6ce987815c39"
134
+ "homepage": "https://github.com/posthtml/htmlnano"
131
135
  }