1
0
mirror of https://github.com/home-assistant/frontend.git synced 2026-07-02 20:15:40 +01:00
Files
frontend/build-scripts/minify-template-literals-loader.cjs
Paul Bottein 389af6e00c Keep self-closing slashes when minifying svg`` templates (#52857)
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Claude <noreply@anthropic.com>
2026-06-25 10:31:58 +01:00

69 lines
2.7 KiB
JavaScript

/* global module, require */
// rspack/webpack loader that minifies the HTML, SVG, and CSS inside lit
// tagged template literals using `minify-literals` (html-minifier-next +
// lightningcss). Replaces the unmaintained babel-plugin-template-html-minifier.
//
// It runs between swc and babel: swc has already stripped TS types and
// decorators (so minify-literals' acorn parser only sees plain ESM), but the
// `html`/`css`/`svg` tagged templates are still intact at ES2021. Running after
// babel instead would miss the legacy build, where babel lowers the templates
// to `_taggedTemplateLiteral()` calls that no longer look like tagged templates.
const remapping = require("@ampproject/remapping");
// minify-literals is ESM-only, so load it via dynamic import from this CJS loader.
let minifyPromise;
const getMinifier = () => {
if (!minifyPromise) {
minifyPromise = import("minify-literals").then((m) => m.minifyHTMLLiterals);
}
return minifyPromise;
};
// HTML options mirror the previous babel-plugin-template-html-minifier config
// (html-minifier-next is option-compatible with html-minifier-terser). CSS in
// css`` templates and inline <style> is handled by minify-literals' lightningcss
// default.
//
// `keepClosingSlash` is required for `svg`` templates: SVG elements such as
// `<path />` and `<circle />` are not void elements in HTML, so dropping the
// trailing slash would break the markup. It is harmless for HTML.
const htmlOptions = {
caseSensitive: true,
collapseWhitespace: true,
conservativeCollapse: true,
decodeEntities: true,
keepClosingSlash: true,
removeComments: true,
removeRedundantAttributes: true,
};
module.exports = function minifyTemplateLiteralsLoader(source, map, meta) {
const callback = this.async();
getMinifier()
.then((minifyHTMLLiterals) =>
minifyHTMLLiterals(source, {
fileName: this.resourcePath,
html: htmlOptions,
})
)
.then((result) => {
if (!result) {
// No tagged templates changed; pass through untouched (incl. incoming map).
callback(null, source, map, meta);
return;
}
// minify-literals builds its map from `source` alone, so `result.map`
// describes minified output -> this loader's input (the swc output), not
// the original file. Compose it over the incoming map (swc output ->
// original source) so the map handed downstream still points at the
// original source; otherwise every minified file's source map is wrong.
const outMap =
map && result.map
? remapping([result.map, map], () => null)
: (result.map ?? map);
callback(null, result.code, outMap, meta);
})
.catch(callback);
};