@@ -54,7 +54,63 @@ const optionalDependencies = {
54
54
minifySvg : [ 'svgo' ]
55
55
} satisfies Partial < Record < keyof HtmlnanoOptions , string [ ] > > ;
56
56
57
- const interop = < T > ( imported : Promise < { default : T } > ) : Promise < T > => imported . then ( mod => mod . default ) ;
57
+ /**
58
+ * And the old mixing named export and default export again.
59
+ *
60
+ * TL; DR: our bundler has bundled our mixed default/named export module into a "exports" object,
61
+ * and when dynamically importing a CommonJS module using "import" instead of "require", Node.js wraps
62
+ * another layer of default around the "exports" object.
63
+ *
64
+ * The longer version:
65
+ *
66
+ * The bundler we are using outputs:
67
+ *
68
+ * ESM: export { [named], xxx as default }
69
+ * CJS: exports.default = xxx; exports.[named] = ...; exports.__esModule = true;
70
+ *
71
+ * With ESM, the Module object looks like this:
72
+ *
73
+ * ```js
74
+ * Module {
75
+ * default: xxx,
76
+ * [named]: ...,
77
+ * }
78
+ * ```
79
+ *
80
+ * With CJS, Node.js handles dynamic import differently. Node.js doesn't respect `__esModule`,
81
+ * and will wrongly treat a CommonJS module as ESM, i.e. assign the "exports" object on its
82
+ * own "default" on the "Module" object.
83
+ *
84
+ * Now we have:
85
+ *
86
+ * ```js
87
+ * Module {
88
+ * // this is actually the "exports" inside among "exports.__esModule", "exports.[named]", and "exports.default"
89
+ * default: {
90
+ * __esModule: true,
91
+ * // This is the actual "exports.default"
92
+ * default: xxx
93
+ * }
94
+ * }
95
+ * ```
96
+ */
97
+ const interop = < T > ( imported : Promise < object > ) : Promise < HtmlnanoModule < T > > => imported . then ( ( mod ) => {
98
+ let htmlnanoModule ;
99
+ while ( 'default' in mod ) {
100
+ htmlnanoModule = mod ;
101
+ mod = mod . default as object ;
102
+ // If we find any htmlnano module hook methods, we know this object is a htmlnano module, return directly
103
+ if ( 'onAttrs' in mod || 'onContent' in mod || 'onNode' in mod ) {
104
+ return mod as HtmlnanoModule < T > ;
105
+ }
106
+ }
107
+
108
+ if ( htmlnanoModule && typeof htmlnanoModule . default === 'function' ) {
109
+ return htmlnanoModule as HtmlnanoModule < T > ;
110
+ }
111
+
112
+ throw new TypeError ( 'The imported module is not a valid htmlnano module' ) ;
113
+ } ) ;
58
114
59
115
const modules = {
60
116
collapseAttributeWhitespace : ( ) => interop ( import ( './_modules/collapseAttributeWhitespace' ) ) ,
@@ -63,23 +119,23 @@ const modules = {
63
119
custom : ( ) => interop ( import ( './_modules/custom' ) ) ,
64
120
deduplicateAttributeValues : ( ) => interop ( import ( './_modules/deduplicateAttributeValues' ) ) ,
65
121
// example: () => import('./_modules/example.mjs'),
66
- mergeScripts : ( ) => interop ( import ( './_modules/mergeScripts.js ' ) ) ,
67
- mergeStyles : ( ) => interop ( import ( './_modules/mergeStyles.js ' ) ) ,
68
- minifyConditionalComments : ( ) => interop ( import ( './_modules/minifyConditionalComments.js ' ) ) ,
69
- minifyCss : ( ) => interop ( import ( './_modules/minifyCss.js ' ) ) ,
70
- minifyJs : ( ) => interop ( import ( './_modules/minifyJs.js ' ) ) ,
71
- minifyJson : ( ) => interop ( import ( './_modules/minifyJson.js ' ) ) ,
72
- minifySvg : ( ) => interop ( import ( './_modules/minifySvg.js ' ) ) ,
73
- minifyUrls : ( ) => interop ( import ( './_modules/minifyUrls.js ' ) ) ,
122
+ mergeScripts : ( ) => interop ( import ( './_modules/mergeScripts' ) ) ,
123
+ mergeStyles : ( ) => interop ( import ( './_modules/mergeStyles' ) ) ,
124
+ minifyConditionalComments : ( ) => interop ( import ( './_modules/minifyConditionalComments' ) ) ,
125
+ minifyCss : ( ) => interop ( import ( './_modules/minifyCss' ) ) ,
126
+ minifyJs : ( ) => interop ( import ( './_modules/minifyJs' ) ) ,
127
+ minifyJson : ( ) => interop ( import ( './_modules/minifyJson' ) ) ,
128
+ minifySvg : ( ) => interop ( import ( './_modules/minifySvg' ) ) ,
129
+ minifyUrls : ( ) => interop ( import ( './_modules/minifyUrls' ) ) ,
74
130
normalizeAttributeValues : ( ) => interop ( import ( './_modules/normalizeAttributeValues' ) ) ,
75
- removeAttributeQuotes : ( ) => interop ( import ( './_modules/removeAttributeQuotes.js ' ) ) ,
76
- removeComments : ( ) => interop ( import ( './_modules/removeComments.js ' ) ) ,
77
- removeEmptyAttributes : ( ) => interop ( import ( './_modules/removeEmptyAttributes.js ' ) ) ,
78
- removeOptionalTags : ( ) => interop ( import ( './_modules/removeOptionalTags.js ' ) ) ,
79
- removeRedundantAttributes : ( ) => interop ( import ( './_modules/removeRedundantAttributes.js ' ) ) ,
80
- removeUnusedCss : ( ) => interop ( import ( './_modules/removeUnusedCss.js ' ) ) ,
81
- sortAttributes : ( ) => interop ( import ( './_modules/sortAttributes.js ' ) ) ,
82
- sortAttributesWithLists : ( ) => interop ( import ( './_modules/sortAttributesWithLists.js ' ) )
131
+ removeAttributeQuotes : ( ) => interop ( import ( './_modules/removeAttributeQuotes' ) ) ,
132
+ removeComments : ( ) => interop ( import ( './_modules/removeComments' ) ) ,
133
+ removeEmptyAttributes : ( ) => interop ( import ( './_modules/removeEmptyAttributes' ) ) ,
134
+ removeOptionalTags : ( ) => interop ( import ( './_modules/removeOptionalTags' ) ) ,
135
+ removeRedundantAttributes : ( ) => interop ( import ( './_modules/removeRedundantAttributes' ) ) ,
136
+ removeUnusedCss : ( ) => interop ( import ( './_modules/removeUnusedCss' ) ) ,
137
+ sortAttributes : ( ) => interop ( import ( './_modules/sortAttributes' ) ) ,
138
+ sortAttributesWithLists : ( ) => interop ( import ( './_modules/sortAttributesWithLists' ) )
83
139
} satisfies Record < string , ( ) => Promise < HtmlnanoModule < any > > > ;
84
140
85
141
const htmlnano = Object . assign ( function htmlnano ( optionsRun : HtmlnanoOptions = { } , presetRun ?: HtmlnanoPreset ) {
0 commit comments