200 lines
9.7 KiB
JavaScript
200 lines
9.7 KiB
JavaScript
|
"use strict";
|
||
|
|
||
|
Object.defineProperty(exports, "__esModule", {
|
||
|
value: true
|
||
|
});
|
||
|
exports.default = void 0;
|
||
|
exports.loadConfig = loadConfig;
|
||
|
var _posthtml = _interopRequireDefault(require("posthtml"));
|
||
|
var _cosmiconfig = require("cosmiconfig");
|
||
|
var _safe = _interopRequireDefault(require("./presets/safe.cjs"));
|
||
|
var _ampSafe = _interopRequireDefault(require("./presets/ampSafe.cjs"));
|
||
|
var _max = _interopRequireDefault(require("./presets/max.cjs"));
|
||
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||
|
function __transformExtension(filepath, extMapping) {
|
||
|
if (!filepath.startsWith('./') && !filepath.startsWith('../')) {
|
||
|
// Package import
|
||
|
return filepath;
|
||
|
}
|
||
|
const idx = filepath.lastIndexOf('.');
|
||
|
if (idx === -1 || filepath.includes('/', idx)) {
|
||
|
// No extension
|
||
|
const newExt = extMapping[''];
|
||
|
if (newExt) {
|
||
|
return filepath + newExt;
|
||
|
}
|
||
|
return filepath;
|
||
|
}
|
||
|
for (let [origExt, newExt] of Object.entries(extMapping).sort((a, b) => b[0].length - a[0].length)) {
|
||
|
if (filepath.endsWith(origExt)) {
|
||
|
return filepath.slice(0, -origExt.length) + newExt;
|
||
|
}
|
||
|
}
|
||
|
return filepath;
|
||
|
}
|
||
|
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
||
|
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
||
|
const presets = {
|
||
|
safe: _safe.default,
|
||
|
ampSafe: _ampSafe.default,
|
||
|
max: _max.default
|
||
|
};
|
||
|
function loadConfig(options, preset, configPath) {
|
||
|
let {
|
||
|
skipConfigLoading = false,
|
||
|
...rest
|
||
|
} = options || {};
|
||
|
if (!skipConfigLoading) {
|
||
|
const explorer = (0, _cosmiconfig.cosmiconfigSync)('htmlnano');
|
||
|
const rc = configPath ? explorer.load(configPath) : explorer.search();
|
||
|
if (rc) {
|
||
|
const {
|
||
|
preset: presetName
|
||
|
} = rc.config;
|
||
|
if (presetName) {
|
||
|
if (!preset && presets[presetName]) {
|
||
|
preset = presets[presetName];
|
||
|
}
|
||
|
delete rc.config.preset;
|
||
|
}
|
||
|
if (!options) {
|
||
|
rest = rc.config;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return [rest || {}, preset || _safe.default];
|
||
|
}
|
||
|
const optionalDependencies = {
|
||
|
minifyCss: ['cssnano', 'postcss'],
|
||
|
minifyJs: ['terser'],
|
||
|
minifyUrl: ['relateurl', 'srcset', 'terser'],
|
||
|
minifySvg: ['svgo']
|
||
|
};
|
||
|
const modules = {
|
||
|
collapseAttributeWhitespace: () => Promise.resolve().then(() => _interopRequireWildcard(require("./modules/collapseAttributeWhitespace.cjs"))),
|
||
|
collapseBooleanAttributes: () => Promise.resolve().then(() => _interopRequireWildcard(require("./modules/collapseBooleanAttributes.cjs"))),
|
||
|
collapseWhitespace: () => Promise.resolve().then(() => _interopRequireWildcard(require("./modules/collapseWhitespace.cjs"))),
|
||
|
custom: () => Promise.resolve().then(() => _interopRequireWildcard(require("./modules/custom.cjs"))),
|
||
|
deduplicateAttributeValues: () => Promise.resolve().then(() => _interopRequireWildcard(require("./modules/deduplicateAttributeValues.cjs"))),
|
||
|
example: () => Promise.resolve().then(() => _interopRequireWildcard(require("./modules/example.cjs"))),
|
||
|
mergeScripts: () => Promise.resolve().then(() => _interopRequireWildcard(require("./modules/mergeScripts.cjs"))),
|
||
|
mergeStyles: () => Promise.resolve().then(() => _interopRequireWildcard(require("./modules/mergeStyles.cjs"))),
|
||
|
minifyConditionalComments: () => Promise.resolve().then(() => _interopRequireWildcard(require("./modules/minifyConditionalComments.cjs"))),
|
||
|
minifyCss: () => Promise.resolve().then(() => _interopRequireWildcard(require("./modules/minifyCss.cjs"))),
|
||
|
minifyJs: () => Promise.resolve().then(() => _interopRequireWildcard(require("./modules/minifyJs.cjs"))),
|
||
|
minifyJson: () => Promise.resolve().then(() => _interopRequireWildcard(require("./modules/minifyJson.cjs"))),
|
||
|
minifySvg: () => Promise.resolve().then(() => _interopRequireWildcard(require("./modules/minifySvg.cjs"))),
|
||
|
minifyUrls: () => Promise.resolve().then(() => _interopRequireWildcard(require("./modules/minifyUrls.cjs"))),
|
||
|
normalizeAttributeValues: () => Promise.resolve().then(() => _interopRequireWildcard(require("./modules/normalizeAttributeValues.cjs"))),
|
||
|
removeAttributeQuotes: () => Promise.resolve().then(() => _interopRequireWildcard(require("./modules/removeAttributeQuotes.cjs"))),
|
||
|
removeComments: () => Promise.resolve().then(() => _interopRequireWildcard(require("./modules/removeComments.cjs"))),
|
||
|
removeEmptyAttributes: () => Promise.resolve().then(() => _interopRequireWildcard(require("./modules/removeEmptyAttributes.cjs"))),
|
||
|
removeOptionalTags: () => Promise.resolve().then(() => _interopRequireWildcard(require("./modules/removeOptionalTags.cjs"))),
|
||
|
removeRedundantAttributes: () => Promise.resolve().then(() => _interopRequireWildcard(require("./modules/removeRedundantAttributes.cjs"))),
|
||
|
removeUnusedCss: () => Promise.resolve().then(() => _interopRequireWildcard(require("./modules/removeUnusedCss.cjs"))),
|
||
|
sortAttributes: () => Promise.resolve().then(() => _interopRequireWildcard(require("./modules/sortAttributes.cjs"))),
|
||
|
sortAttributesWithLists: () => Promise.resolve().then(() => _interopRequireWildcard(require("./modules/sortAttributesWithLists.cjs")))
|
||
|
};
|
||
|
function htmlnano(optionsRun, presetRun) {
|
||
|
let [options, preset] = loadConfig(optionsRun, presetRun);
|
||
|
return async function minifier(tree) {
|
||
|
const nodeHandlers = [];
|
||
|
const attrsHandlers = [];
|
||
|
const contentsHandlers = [];
|
||
|
options = {
|
||
|
...preset,
|
||
|
...options
|
||
|
};
|
||
|
let promise = Promise.resolve(tree);
|
||
|
for (const [moduleName, moduleOptions] of Object.entries(options)) {
|
||
|
if (!moduleOptions) {
|
||
|
// The module is disabled
|
||
|
continue;
|
||
|
}
|
||
|
if (_safe.default[moduleName] === undefined) {
|
||
|
throw new Error('Module "' + moduleName + '" is not defined');
|
||
|
}
|
||
|
(optionalDependencies[moduleName] || []).forEach(async dependency => {
|
||
|
try {
|
||
|
await (specifier => new Promise(r => r(`${specifier}`)).then(s => _interopRequireWildcard(require(s))))(__transformExtension(dependency, {
|
||
|
".mjs": ".cjs"
|
||
|
}));
|
||
|
} catch (e) {
|
||
|
if (e.code === 'MODULE_NOT_FOUND' || e.code === 'ERR_MODULE_NOT_FOUND') {
|
||
|
console.warn(`You have to install "${dependency}" in order to use htmlnano's "${moduleName}" module`);
|
||
|
} else {
|
||
|
throw e;
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
const module = moduleName in modules ? await modules[moduleName]() : await (specifier => new Promise(r => r(`${specifier}`)).then(s => _interopRequireWildcard(require(s))))(__transformExtension(`./modules/${moduleName}.mjs`, {
|
||
|
".mjs": ".cjs"
|
||
|
}));
|
||
|
if (typeof module.onAttrs === 'function') {
|
||
|
attrsHandlers.push(module.onAttrs(options, moduleOptions));
|
||
|
}
|
||
|
if (typeof module.onContent === 'function') {
|
||
|
contentsHandlers.push(module.onContent(options, moduleOptions));
|
||
|
}
|
||
|
if (typeof module.onNode === 'function') {
|
||
|
nodeHandlers.push(module.onNode(options, moduleOptions));
|
||
|
}
|
||
|
if (typeof module.default === 'function') {
|
||
|
promise = promise.then(async tree => await module.default(tree, options, moduleOptions));
|
||
|
}
|
||
|
}
|
||
|
if (attrsHandlers.length + contentsHandlers.length + nodeHandlers.length === 0) {
|
||
|
return promise;
|
||
|
}
|
||
|
return promise.then(tree => {
|
||
|
tree.walk(node => {
|
||
|
if (node) {
|
||
|
if (node.attrs && typeof node.attrs === 'object') {
|
||
|
// Convert all attrs' key to lower case
|
||
|
let newAttrsObj = {};
|
||
|
Object.entries(node.attrs).forEach(([attrName, attrValue]) => {
|
||
|
newAttrsObj[attrName.toLowerCase()] = attrValue;
|
||
|
});
|
||
|
for (const handler of attrsHandlers) {
|
||
|
newAttrsObj = handler(newAttrsObj, node);
|
||
|
}
|
||
|
node.attrs = newAttrsObj;
|
||
|
}
|
||
|
if (node.content) {
|
||
|
node.content = typeof node.content === 'string' ? [node.content] : node.content;
|
||
|
if (Array.isArray(node.content) && node.content.length > 0) {
|
||
|
for (const handler of contentsHandlers) {
|
||
|
const result = handler(node.content, node);
|
||
|
node.content = typeof result === 'string' ? [result] : result;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
for (const handler of nodeHandlers) {
|
||
|
node = handler(node);
|
||
|
}
|
||
|
}
|
||
|
return node;
|
||
|
});
|
||
|
return tree;
|
||
|
});
|
||
|
};
|
||
|
}
|
||
|
htmlnano.getRequiredOptionalDependencies = function (optionsRun, presetRun) {
|
||
|
const [options] = loadConfig(optionsRun, presetRun);
|
||
|
return [...new Set(Object.keys(options).filter(moduleName => options[moduleName]).map(moduleName => optionalDependencies[moduleName]).flat())];
|
||
|
};
|
||
|
htmlnano.process = function (html, options, preset, postHtmlOptions) {
|
||
|
return (0, _posthtml.default)([htmlnano(options, preset)]).process(html, postHtmlOptions);
|
||
|
};
|
||
|
|
||
|
// https://github.com/webpack-contrib/html-minimizer-webpack-plugin/blob/faca00f2219514bc671c5942685721f0b5dbaa70/src/utils.js#L74
|
||
|
htmlnano.htmlMinimizerWebpackPluginMinify = function htmlNano(input, minimizerOptions = {}) {
|
||
|
const [[, code]] = Object.entries(input);
|
||
|
return htmlnano.process(code, minimizerOptions, presets.safe).then(result => {
|
||
|
return {
|
||
|
code: result.html
|
||
|
};
|
||
|
});
|
||
|
};
|
||
|
htmlnano.presets = presets;
|
||
|
var _default = exports.default = htmlnano;
|