UNPKG

minify-html-literals

Version:
166 lines 6.78 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.adjustMinifyCSSOptions = exports.defaultStrategy = exports.defaultMinifyOptions = exports.defaultMinifyCSSOptions = void 0; /// <reference types="./types/clean-css" /> // Reference needed for d.ts distribution files in rollup-plugin-minify-html-literals const CleanCSS = require("clean-css"); const optimization_level_1 = require("clean-css/lib/options/optimization-level"); const html_minifier_1 = require("html-minifier"); /** * The default <code>clean-css</code> options, optimized for production * minification. */ exports.defaultMinifyCSSOptions = {}; /** * The default <code>html-minifier</code> options, optimized for production * minification. */ exports.defaultMinifyOptions = { caseSensitive: true, collapseWhitespace: true, decodeEntities: true, minifyCSS: exports.defaultMinifyCSSOptions, minifyJS: true, processConditionalComments: true, removeAttributeQuotes: false, removeComments: true, removeEmptyAttributes: true, removeScriptTypeAttributes: true, removeStyleLinkTypeAttributes: true, useShortDoctype: true }; /** * The default strategy. This uses <code>html-minifier</code> to minify HTML and * <code>clean-css</code> to minify CSS. */ exports.defaultStrategy = { getPlaceholder(parts) { // Using @ and (); will cause the expression not to be removed in CSS. // However, sometimes the semicolon can be removed (ex: inline styles). // In those cases, we want to make sure that the HTML splitting also // accounts for the missing semicolon. const suffix = '();'; let placeholder = '@TEMPLATE_EXPRESSION'; while (parts.some(part => part.text.includes(placeholder + suffix))) { placeholder += '_'; } return placeholder + suffix; }, combineHTMLStrings(parts, placeholder) { return parts.map(part => part.text).join(placeholder); }, minifyHTML(html, options = {}) { let minifyCSSOptions; if (options.minifyCSS) { if (options.minifyCSS !== true && typeof options.minifyCSS !== 'function') { minifyCSSOptions = { ...options.minifyCSS }; } else { minifyCSSOptions = {}; } } else { minifyCSSOptions = false; } let adjustedMinifyCSSOptions = false; if (minifyCSSOptions) { adjustedMinifyCSSOptions = adjustMinifyCSSOptions(minifyCSSOptions); } let result = html_minifier_1.minify(html, { ...options, minifyCSS: adjustedMinifyCSSOptions }); if (options.collapseWhitespace) { // html-minifier does not support removing newlines inside <svg> // attributes. Support this, but be careful not to remove newlines from // supported areas (such as within <pre> and <textarea> tags). const matches = Array.from(result.matchAll(/<svg/g)).reverse(); for (const match of matches) { const startTagIndex = match.index; const closeTagIndex = result.indexOf('</svg', startTagIndex); if (closeTagIndex < 0) { // Malformed SVG without a closing tag continue; } const start = result.substring(0, startTagIndex); let svg = result.substring(startTagIndex, closeTagIndex); const end = result.substring(closeTagIndex); svg = svg.replace(/\r?\n/g, ''); result = start + svg + end; } } if (adjustedMinifyCSSOptions && adjustedMinifyCSSOptions.level[optimization_level_1.OptimizationLevel.One].tidySelectors) { // Fix https://github.com/jakubpawlowicz/clean-css/issues/996 result = fixCleanCssTidySelectors(html, result); } return result; }, minifyCSS(css, options = {}) { const adjustedOptions = adjustMinifyCSSOptions(options); const output = new CleanCSS(adjustedOptions).minify(css); if (output.errors && output.errors.length) { throw new Error(output.errors.join('\n\n')); } if (adjustedOptions.level[optimization_level_1.OptimizationLevel.One].tidySelectors) { output.styles = fixCleanCssTidySelectors(css, output.styles); } return output.styles; }, splitHTMLByPlaceholder(html, placeholder) { const parts = html.split(placeholder); // Make the last character (a semicolon) optional. See above. if (placeholder.endsWith(';')) { const withoutSemicolon = placeholder.substring(0, placeholder.length - 1); for (let i = parts.length - 1; i >= 0; i--) { parts.splice(i, 1, ...parts[i].split(withoutSemicolon)); } } return parts; } }; function adjustMinifyCSSOptions(options = {}) { const level = optimization_level_1.optimizationLevelFrom(options.level); const originalTransform = typeof options.level === 'object' && options.level[1] && options.level[1].transform; level[optimization_level_1.OptimizationLevel.One].transform = (property, value) => { if (value.startsWith('@TEMPLATE_EXPRESSION') && !value.endsWith(';')) { // The CSS minifier has removed the semicolon from the placeholder // and we need to add it back. return (value = `${value};`); } return originalTransform ? originalTransform(property, value) : value; }; return { ...options, level }; } exports.adjustMinifyCSSOptions = adjustMinifyCSSOptions; function fixCleanCssTidySelectors(original, result) { const regex = /(::?.+\((.*)\))[\s\r\n]*{/gm; let match; while ((match = regex.exec(original)) != null) { const pseudoClass = match[1]; const parameters = match[2]; if (!parameters.match(/\s/)) { continue; } const parametersWithoutSpaces = parameters.replace(/\s/g, ''); const resultPseudoClass = pseudoClass.replace(parameters, parametersWithoutSpaces); const resultStartIndex = result.indexOf(resultPseudoClass); if (resultStartIndex < 0) { continue; } const resultEndIndex = resultStartIndex + resultPseudoClass.length; // Restore the original pseudo class with spaces result = result.substring(0, resultStartIndex) + pseudoClass + result.substring(resultEndIndex); } return result; } //# sourceMappingURL=strategy.js.map