htmlnano 2.1.4 → 2.1.5

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.
@@ -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
  });
@@ -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) {
package/dist/index.d.ts CHANGED
@@ -59,14 +59,13 @@ type HtmlnanoModule<Options = any> = {
59
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 htmlnano: ((optionsRun?: HtmlnanoOptions, presetRun?: HtmlnanoPreset) => PostHTML.Plugin<never>) & {
63
+ presets: HtmlnanoPredefinedPresets;
64
+ getRequiredOptionalDependencies: typeof getRequiredOptionalDependencies;
65
+ process: typeof process;
66
+ htmlMinimizerWebpackPluginMinify: typeof htmlMinimizerWebpackPluginMinify;
67
+ loadConfig: typeof loadConfig;
68
+ };
70
69
  declare function getRequiredOptionalDependencies(optionsRun: HtmlnanoOptions, presetRun: HtmlnanoPreset): string[];
71
70
  declare function process(html: string, options?: HtmlnanoOptions, preset?: HtmlnanoPreset, postHtmlOptions?: PostHTML.Options): Promise<PostHTML.Result<unknown>>;
72
71
  declare function htmlMinimizerWebpackPluginMinify(input: {
@@ -75,5 +74,5 @@ declare function htmlMinimizerWebpackPluginMinify(input: {
75
74
  code: string;
76
75
  }>;
77
76
 
78
- export { htmlnano as default, getRequiredOptionalDependencies, htmlMinimizerWebpackPluginMinify, htmlnano, loadConfig, process };
77
+ export { htmlnano as default, getRequiredOptionalDependencies, htmlMinimizerWebpackPluginMinify, loadConfig, process };
79
78
  export type { HtmlnanoModule, HtmlnanoModuleAttrsHandler, HtmlnanoModuleContentHandler, HtmlnanoModuleNodeHandler, HtmlnanoOptions, HtmlnanoOptionsConfigFile, HtmlnanoPredefinedPreset, HtmlnanoPredefinedPresets, HtmlnanoPreset, PostHTMLNodeLike, PostHTMLTreeLike };
package/dist/index.js CHANGED
@@ -59,7 +59,60 @@ const optionalDependencies = {
59
59
  'svgo'
60
60
  ]
61
61
  };
62
- const interop = (imported)=>imported.then((mod)=>mod.default);
62
+ /**
63
+ * And the old mixing named export and default export again.
64
+ *
65
+ * TL; DR: our bundler has bundled our mixed default/named export module into a "exports" object,
66
+ * and when dynamically importing a CommonJS module using "import" instead of "require", Node.js wraps
67
+ * another layer of default around the "exports" object.
68
+ *
69
+ * The longer version:
70
+ *
71
+ * The bundler we are using outputs:
72
+ *
73
+ * ESM: export { [named], xxx as default }
74
+ * CJS: exports.default = xxx; exports.[named] = ...; exports.__esModule = true;
75
+ *
76
+ * With ESM, the Module object looks like this:
77
+ *
78
+ * ```js
79
+ * Module {
80
+ * default: xxx,
81
+ * [named]: ...,
82
+ * }
83
+ * ```
84
+ *
85
+ * With CJS, Node.js handles dynamic import differently. Node.js doesn't respect `__esModule`,
86
+ * and will wrongly treat a CommonJS module as ESM, i.e. assign the "exports" object on its
87
+ * own "default" on the "Module" object.
88
+ *
89
+ * Now we have:
90
+ *
91
+ * ```js
92
+ * Module {
93
+ * // this is actually the "exports" inside among "exports.__esModule", "exports.[named]", and "exports.default"
94
+ * default: {
95
+ * __esModule: true,
96
+ * // This is the actual "exports.default"
97
+ * default: xxx
98
+ * }
99
+ * }
100
+ * ```
101
+ */ const interop = (imported)=>imported.then((mod)=>{
102
+ let htmlnanoModule;
103
+ while('default' in mod){
104
+ htmlnanoModule = mod;
105
+ mod = mod.default;
106
+ // If we find any htmlnano module hook methods, we know this object is a htmlnano module, return directly
107
+ if ('onAttrs' in mod || 'onContent' in mod || 'onNode' in mod) {
108
+ return mod;
109
+ }
110
+ }
111
+ if (htmlnanoModule && typeof htmlnanoModule.default === 'function') {
112
+ return htmlnanoModule;
113
+ }
114
+ throw new TypeError('The imported module is not a valid htmlnano module');
115
+ });
63
116
  const modules = {
64
117
  collapseAttributeWhitespace: ()=>interop(import('./_modules/collapseAttributeWhitespace.js')),
65
118
  collapseBooleanAttributes: ()=>interop(import('./_modules/collapseBooleanAttributes.js')),
@@ -85,7 +138,7 @@ const modules = {
85
138
  sortAttributes: ()=>interop(import('./_modules/sortAttributes.js')),
86
139
  sortAttributesWithLists: ()=>interop(import('./_modules/sortAttributesWithLists.js'))
87
140
  };
88
- function htmlnano(optionsRun = {}, presetRun) {
141
+ const htmlnano = Object.assign(function htmlnano(optionsRun = {}, presetRun) {
89
142
  // eslint-disable-next-line prefer-const -- re-assign options
90
143
  let [options, preset] = loadConfig(optionsRun, presetRun);
91
144
  const minifier = async (_tree)=>{
@@ -180,7 +233,13 @@ function htmlnano(optionsRun = {}, presetRun) {
180
233
  });
181
234
  };
182
235
  return minifier;
183
- }
236
+ }, {
237
+ presets,
238
+ getRequiredOptionalDependencies,
239
+ process,
240
+ htmlMinimizerWebpackPluginMinify,
241
+ loadConfig
242
+ });
184
243
  function getRequiredOptionalDependencies(optionsRun, presetRun) {
185
244
  const [options] = loadConfig(optionsRun, presetRun);
186
245
  return Array.from(Object.keys(options).reduce((acc, moduleName)=>{
@@ -200,17 +259,12 @@ function process(html, options, preset, postHtmlOptions) {
200
259
  // https://github.com/webpack-contrib/html-minimizer-webpack-plugin/blob/faca00f2219514bc671c5942685721f0b5dbaa70/src/utils.js#L74
201
260
  function htmlMinimizerWebpackPluginMinify(input, minimizerOptions) {
202
261
  const [[, code]] = Object.entries(input);
203
- return htmlnano.process(code, minimizerOptions, presets.safe).then((result)=>{
262
+ return process(code, minimizerOptions, presets.safe).then((result)=>{
204
263
  return {
205
264
  code: result.html
206
265
  };
207
266
  });
208
267
  }
209
- htmlnano.presets = presets;
210
- htmlnano.getRequiredOptionalDependencies = getRequiredOptionalDependencies;
211
- htmlnano.process = process;
212
- htmlnano.htmlMinimizerWebpackPluginMinify = htmlMinimizerWebpackPluginMinify;
213
- htmlnano.loadConfig = loadConfig;
214
268
  if (typeof module !== 'undefined') {
215
269
  module.exports = htmlnano;
216
270
  }
@@ -218,6 +272,5 @@ if (typeof module !== 'undefined') {
218
272
  exports.default = htmlnano;
219
273
  exports.getRequiredOptionalDependencies = getRequiredOptionalDependencies;
220
274
  exports.htmlMinimizerWebpackPluginMinify = htmlMinimizerWebpackPluginMinify;
221
- exports.htmlnano = htmlnano;
222
275
  exports.loadConfig = loadConfig;
223
276
  exports.process = process;
package/dist/index.mjs CHANGED
@@ -50,7 +50,60 @@ const optionalDependencies = {
50
50
  'svgo'
51
51
  ]
52
52
  };
53
- const interop = (imported)=>imported.then((mod)=>mod.default);
53
+ /**
54
+ * And the old mixing named export and default export again.
55
+ *
56
+ * TL; DR: our bundler has bundled our mixed default/named export module into a "exports" object,
57
+ * and when dynamically importing a CommonJS module using "import" instead of "require", Node.js wraps
58
+ * another layer of default around the "exports" object.
59
+ *
60
+ * The longer version:
61
+ *
62
+ * The bundler we are using outputs:
63
+ *
64
+ * ESM: export { [named], xxx as default }
65
+ * CJS: exports.default = xxx; exports.[named] = ...; exports.__esModule = true;
66
+ *
67
+ * With ESM, the Module object looks like this:
68
+ *
69
+ * ```js
70
+ * Module {
71
+ * default: xxx,
72
+ * [named]: ...,
73
+ * }
74
+ * ```
75
+ *
76
+ * With CJS, Node.js handles dynamic import differently. Node.js doesn't respect `__esModule`,
77
+ * and will wrongly treat a CommonJS module as ESM, i.e. assign the "exports" object on its
78
+ * own "default" on the "Module" object.
79
+ *
80
+ * Now we have:
81
+ *
82
+ * ```js
83
+ * Module {
84
+ * // this is actually the "exports" inside among "exports.__esModule", "exports.[named]", and "exports.default"
85
+ * default: {
86
+ * __esModule: true,
87
+ * // This is the actual "exports.default"
88
+ * default: xxx
89
+ * }
90
+ * }
91
+ * ```
92
+ */ const interop = (imported)=>imported.then((mod)=>{
93
+ let htmlnanoModule;
94
+ while('default' in mod){
95
+ htmlnanoModule = mod;
96
+ mod = mod.default;
97
+ // If we find any htmlnano module hook methods, we know this object is a htmlnano module, return directly
98
+ if ('onAttrs' in mod || 'onContent' in mod || 'onNode' in mod) {
99
+ return mod;
100
+ }
101
+ }
102
+ if (htmlnanoModule && typeof htmlnanoModule.default === 'function') {
103
+ return htmlnanoModule;
104
+ }
105
+ throw new TypeError('The imported module is not a valid htmlnano module');
106
+ });
54
107
  const modules = {
55
108
  collapseAttributeWhitespace: ()=>interop(import('./_modules/collapseAttributeWhitespace.mjs')),
56
109
  collapseBooleanAttributes: ()=>interop(import('./_modules/collapseBooleanAttributes.mjs')),
@@ -76,7 +129,7 @@ const modules = {
76
129
  sortAttributes: ()=>interop(import('./_modules/sortAttributes.mjs')),
77
130
  sortAttributesWithLists: ()=>interop(import('./_modules/sortAttributesWithLists.mjs'))
78
131
  };
79
- function htmlnano(optionsRun = {}, presetRun) {
132
+ const htmlnano = Object.assign(function htmlnano(optionsRun = {}, presetRun) {
80
133
  // eslint-disable-next-line prefer-const -- re-assign options
81
134
  let [options, preset] = loadConfig(optionsRun, presetRun);
82
135
  const minifier = async (_tree)=>{
@@ -171,7 +224,13 @@ function htmlnano(optionsRun = {}, presetRun) {
171
224
  });
172
225
  };
173
226
  return minifier;
174
- }
227
+ }, {
228
+ presets,
229
+ getRequiredOptionalDependencies,
230
+ process,
231
+ htmlMinimizerWebpackPluginMinify,
232
+ loadConfig
233
+ });
175
234
  function getRequiredOptionalDependencies(optionsRun, presetRun) {
176
235
  const [options] = loadConfig(optionsRun, presetRun);
177
236
  return Array.from(Object.keys(options).reduce((acc, moduleName)=>{
@@ -191,19 +250,14 @@ function process(html, options, preset, postHtmlOptions) {
191
250
  // https://github.com/webpack-contrib/html-minimizer-webpack-plugin/blob/faca00f2219514bc671c5942685721f0b5dbaa70/src/utils.js#L74
192
251
  function htmlMinimizerWebpackPluginMinify(input, minimizerOptions) {
193
252
  const [[, code]] = Object.entries(input);
194
- return htmlnano.process(code, minimizerOptions, presets.safe).then((result)=>{
253
+ return process(code, minimizerOptions, presets.safe).then((result)=>{
195
254
  return {
196
255
  code: result.html
197
256
  };
198
257
  });
199
258
  }
200
- htmlnano.presets = presets;
201
- htmlnano.getRequiredOptionalDependencies = getRequiredOptionalDependencies;
202
- htmlnano.process = process;
203
- htmlnano.htmlMinimizerWebpackPluginMinify = htmlMinimizerWebpackPluginMinify;
204
- htmlnano.loadConfig = loadConfig;
205
259
  if (typeof module !== 'undefined') {
206
260
  module.exports = htmlnano;
207
261
  }
208
262
 
209
- export { htmlnano as default, getRequiredOptionalDependencies, htmlMinimizerWebpackPluginMinify, htmlnano, loadConfig, process };
263
+ export { htmlnano as default, getRequiredOptionalDependencies, htmlMinimizerWebpackPluginMinify, loadConfig, process };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "htmlnano",
3
- "version": "2.1.4",
3
+ "version": "2.1.5",
4
4
  "description": "Modular HTML minifier, built on top of the PostHTML",
5
5
  "author": "Kirill Maltsev <maltsevkirill@gmail.com>",
6
6
  "license": "MIT",
@@ -11,7 +11,7 @@
11
11
  "lint": "eslint --fix .",
12
12
  "pretest": "npm run lint && npm run compile",
13
13
  "test": ":",
14
- "posttest": "mocha --timeout 5000 --require @swc-node/register --recursive --check-leaks --globals addresses",
14
+ "posttest": "mocha --timeout 5000 --require @swc-node/register --recursive --check-leaks --globals addresses 'test/**/*.ts'",
15
15
  "prepare": "npm run compile"
16
16
  },
17
17
  "files": [
@@ -59,8 +59,10 @@
59
59
  "posthtml": "^0.16.5"
60
60
  },
61
61
  "devDependencies": {
62
+ "@eslint/js": "^9.35.0",
62
63
  "@stylistic/eslint-plugin": "^5.3.1",
63
64
  "@swc-node/register": "^1.10.10",
65
+ "@types/mocha": "^10.0.10",
64
66
  "@types/node": "^24.0.0",
65
67
  "bunchee": "^6.5.1",
66
68
  "cssnano": "^7.0.0",
@@ -80,7 +82,7 @@
80
82
  "svgo": "^3.0.2",
81
83
  "terser": "^5.21.0",
82
84
  "typescript": "^5.8.3",
83
- "typescript-eslint": "^8.31.1",
85
+ "typescript-eslint": "^8.44.0",
84
86
  "uncss": "^0.17.3"
85
87
  },
86
88
  "peerDependencies": {
@@ -126,6 +128,5 @@
126
128
  "bugs": {
127
129
  "url": "https://github.com/posthtml/htmlnano/issues"
128
130
  },
129
- "homepage": "https://github.com/posthtml/htmlnano",
130
- "packageManager": "pnpm@10.10.0+sha512.d615db246fe70f25dcfea6d8d73dee782ce23e2245e3c4f6f888249fb568149318637dca73c2c5c8ef2a4ca0d5657fb9567188bfab47f566d1ee6ce987815c39"
131
+ "homepage": "https://github.com/posthtml/htmlnano"
131
132
  }