asyncliz / minify-html-literals Goto Github PK
View Code? Open in Web Editor NEWMinify HTML template literal strings
License: MIT License
Minify HTML template literal strings
License: MIT License
The html-minifier
package hasn't been updated for nearly 4 years and has a ReDoS vulnerability. Terser has forked the repo and is actively maintaining it under html-minifier-terser
.
Can this get updated to use the maintained package from Terser?
When trying to import something like const red = css`red`;
as recommended in the lit-element guide for stying, minification breaks.
Here's a barebones repo to show the problem: https://github.com/dakom/temp-bug-repro-rollup-minify-html
Hello! First off, thanks a bunch for this package. It's extremely helpful.
I was alerted via Dependabot about an issue with html-minifier
as I'm using minify-html-literals
with esbuild
in a few projects. It looks like this library depends on html-minifier
which is why it landed in our dependency graph.
At any rate, it appears that html-minifier
has an open vulnerability from 2022: https://nvd.nist.gov/vuln/detail/CVE-2022-37620.
It also appears as though html-minifier
is no longer maintained.
I was wondering if you'd be open to switching to one of the options instead?
I'd be happy to take a stab at opening a PR trying this. I mostly wanted to see if a) this was on your radar b) if you'd be open to it.
Thank you!
I am working on integrating this package into Chrome DevTools. The following test appears to be failing, since <@TEMPLATE_EXPRESSION();
is invalid HTML. The @
and ();
are invalid characters as part of the tag name.
const STATIC_LITERAL_IN_TAG_NAME = `
function nested() {
return LitHtml.html\`<\${Component.litTagName} id="container">
<span>Some content here</span>
</\${Component.litTagName}>
\`;
}
`;
const STATIC_LITERAL_IN_TAG_NAME_MIN = `
function nested() {
return LitHtml.html\`<\${Component.litTagName} id="container"><span>Some content here</span></\${Component.litTagName}>\`;
}
`;
I am currently attempting to write a custom strategy to handle this case and disabling CSS minification (since that's what the @
and ();
appear to be used for), but no dice thus far.
Similar to #1 but for CSS blocks that end with a variable: The placeholder's semicolon gets removed and therfore the validation fails.
Code to reproduce this issue:
const { minifyHTMLLiterals } = require('minify-html-literals');
const source = `
const textColor = 'hotpink';
const styles = css\`
body {
/* it is valid to remove the semicolon here if it's the last element of a block */
color: \${textColor};
}
\`;
`;
try {
// this fails because the placeholder's semicolon gets removed
const result = minifyHTMLLiterals(source, { fileName: 'test.js' });
console.log(result.code);
} catch (e) {
console.error(e);
}
When trying to use this package though https://www.npmjs.com/package/rollup-plugin-html-literals with a rollup ESM configuration (npx rollup -c rollup.config.mjs
) the import of the plugin fails as the TS transpiled code in the npm package uses the legacy module.exports
syntax.
Is this possible to change in the build config for this package to ease the usage?
If I could read documentation, I would see that this is exactly the behaviour specified there, so this is not a bug.
I have a code block in lit-html like so,
css`
circle {
r: 2px;
}
`
But when minifying the file using the plugin, it strips off the circle style completely deeming it to be invalid css due to clean-css
plugin
For now, I have solved this issue by following the advice here but this results in the CSS not being minified. I know that the issue is not with this plugin per se, but just wondering if you have any thoughts on how to solve this.
Thanks!
Given the following input:
import { minifyHTMLLiterals } from 'minify-html-literals';
const result = minifyHTMLLiterals(
`const duration = 2;
html\`
<style>
.selector {
animation-duration: \${duration}s;
}
</style>
\``,
{
fileName: 'render.js'
}
);
console.log(result.code);
The expected output is:
const duration = 2;
html`<style>.selector{animation-duration:${duration}s}</style>`
Instead, the unit (s
) is dropped in the actual output:
const duration = 2;
html`<style>.selector{animation-duration:${duration}}</style>`
In comparison, the unit is preserved when there are no template literals inside:
import { minifyHTMLLiterals } from 'minify-html-literals';
const result = minifyHTMLLiterals(
`html\`
<style>
.selector {
animation-duration: 2s;
}
</style>
\``,
{
fileName: 'render.js'
}
);
console.log(result.code);
I have the following code
uhtml.render(this._view, uhtml.html`
<div class="calendar-button-holder">
<button onclick="${() => this.moveCalendar(-1, 0)}"></button>
</div>`);
And the library is throwing the above error. Peeking your code, I saw in ensureHTMLPartsValid
, htmlParts receives an array that has one entry that looks like <button onclick="@TEMPLATE_EXPRESSION()"
, and I believe that's where things go wrong, as that entry should actually be two entries.
Not sure why, but if instead of onclick
I use any other attribute, things works. In fact, any attribute that starts with on seems to break the minification.
I would like to be able to select which templates to minify based on comments. For example I would like to minify code like this:
element.innerHTML = /*html*/ `
<div>test</div>
`;
This is a convention used by syntax highlighters such as ES6 String HTML.
I have a project using lit
. In a design system our org makes there's code for sharing styles that when you pass in a selector to apply, returns a css
template result. During minfication body's of a selector that gets injected dynamically are removed. I suspect this is might be due to the selector not existing in the template part so maybe its removed under the assumption that the selector wouldn't match anything?
e.g. I would expect
var minifyHtmlLiterals = require("minify-html-literals").minifyHTMLLiterals
minifyHtmlLiterals(`
css\`
foo {
bar: baz;
}
\${unsafeCSS('#foo-id')} {
bar: baz;
}
\`
`).code
to produce
'\n css`foo{bar:baz}${unsafeCSS('#foo-id')}{bar: baz}`\n'
but instead i'm getting back
'\n css`foo{bar:baz}${unsafeCSS('#foo-id')}`\n'
It would be useful when using NPM scripts as a build tool.
Thanks for publishing this awesome package.
Consider this repl:
https://repl.it/@bennypowers/minify-html-literals-css-shadow-parts-concat-bug#index.js
input:
html`<h1> hi </h1>`;
css`
#shadow::part(a b c) {
color: red;
}
CSS-unminified output:
html`<h1>hi</h1>`;
css`
#shadow::part(a b c) {
color: red;
}
`
CSS-minified output:
html`<h1>hi</h1>`;
css`#shadow::part(abc){color:red}`
CSS-minified output:
html`<h1>hi</h1>`;
css`#shadow::part(a b c){color:red}`
this package should maintain the part selector a b c
.
I'm pretty sure this is an upstream issue with CleanCSS
This library looks quite useful for our scenarios. I'm particularly interested in seeing how this could be used in combination with a bundler. Do you have any examples of using this as part of a Webpack or Rollup build?
Having a placeholder with a semicolon breaks the css if added to shorthand attribute values like border
.
Code to reproduce:
const { minifyHTMLLiterals } = require('minify-html-literals');
const source = `
const borderStyle = 'solid';
const styles = css\`
div {
/* adding the placeholder here breaks the css */
border: 1px \${borderStyle} black;
margin: 12px;
}
\`
`;
try {
// this failes because the minifier drops parts of the broken css
const result = minifyHTMLLiterals(source, { fileName: 'test.js' });
console.log(result.code);
} catch (e) {
console.error(e);
}
As the code now lives canonically in lit/lit, please transfer all open issues there and archive this repo
See lit/lit-element#391 for more info.
// In latest version, we can now use `css` literal for styling.
...
statc get styles() {
return [
css`:host { display: block; }`,
];
}
...
If I run this test:
require('minify-html-literals').minifyHTMLLiterals(
'html`<p style="color: ${color}"></p>`'
);
Then I get this error:
Error: splitHTMLByPlaceholder() must return same number of strings as template parts
Replacing "color: ${color}" with "${color}" makes the error go away.
If I try to comment HTML code that has template literal in it I get an error "Error: splitHTMLByPlaceholder() must return same number of strings as template parts"
It faild with both styles of comments:
<!--${this.showRiskIcon ? html`
<tr>
<th>Risk</th>
<td><risk-icon .entityObj="${this.domain}" .commandPostName="${this.commandPostName}"></risk-icon></td>
</tr>
` : ``}-->
and / or
${/*this.showRiskIcon ? html`
<tr>
<th>Risk</th>
<td><risk-icon .entityObj="${this.domain}" .commandPostName="${this.commandPostName}"></risk-icon></td>
</tr>
` : ``*/}
I would really like some way to comment code in templates that will still work with the minifier.
Using version 1.3.5 with minify-html-literals-loader 1.1.1
Thanks
Due to the way the splitting after minification works, some required semicolons are removed, giving invalid css as the result.
Code to reproduce:
const { minifyHTMLLiterals } = require('minify-html-literals');
const assert = require('assert');
const source = `
const fontSize = '12px';
const style = css\`
body {
font-size: \${fontSize};
font-color: black;
}\`;
`;
const expected = `
const fontSize = '12px';
const style = css\`body{font-size:\${fontSize};font-color:#000}\`;
`;
const result = minifyHTMLLiterals(source, { fileName: 'test.js' });
console.log(result.code);
// the semicolon after the ${fontSize} template part gets removed during splitting
assert(source == expected);
This is kinda the inverse of #12 :)
I've been wondering why certain event handlers were completely absent in the production build of my app…
Turns out
html`
<input type="text" .value=${propval} @change=${e =>
this._modify(draft => draft.properties[propname][idx] = e.target.value)
}/>
`
was being minified into
Be`<input type="text" .value="${r}" @change="${e=>this._modify((r=>r.properties[t][o]=e.target.value))}/">`
Look at that slash — it was consumed into the quoted string!
I'd love to use this optimizer in conjunction with other libraries, but minifyHTMLLiterals(validJS)
returns null
, where validJS
can be the source code of any file.
I've tried to pass a filename
too but basically this always returns null
.
Any idea what am I doing wrong? Is this supposed to return null
when the file has no html
template literals in it? If that's the case, what does it return in case the file contains template literals with html in it?
Thanks.
Hello! I'm using the minify-html-literals-loader
in my webpack setup, and basically it throws an error only if I use unsafeCSS
inside the styles e.g.
return css`
:host([type=${unsafeCSS(SomeType.One)}]) {
color: red;
}
`
The error is
Error: splitHTMLByPlaceholder() must return same number of strings as template parts
at Object.ensureHTMLPartsValid (....\node_modules\minify-html-literals\src\minifyHTMLLiterals.js:60:19)
at ....\node_modules\minify-html-literals\src\minifyHTMLLiterals.js:121:26
at Array.forEach (<anonymous>)
at minifyHTMLLiterals (....\node_modules\minify-html-literals\src\minifyHTMLLiterals.js:93:15)
at module.exports (....\node_modules\minify-html-literals-loader\index.js:7:20)
Removing the quotes around attribute values can cause cryptic errors in lit-html templates (and, I suspect, other string-literal based templating systems).
In particular, an attribute value with bindings like this:
<a href="/details/${category}/${item}">
This value doesn't get parsed correctly by lit-html if the quotes are removed. After processing, we end up with an HTML comment wrapped around the second bound value, like this:
<a href=/details/candy/<!-- Swedish+Fish -->>
I ended up setting the removeAttributeQuotes
option to false
to prevent this issue, but it seems like it might be a good default:
options: {
minifyOptions: {
removeAttributeQuotes: false
}
}
Thanks a ton for creating this plugin it has been incredibly helpful! I noticed that when minifying it looks for template strings created with html
or css
functions and minifies them. Can this be extended to minify template strings created using the svg
function in lit-html
as well? That would be really helpful!
Thanks again!
where did the px
go?
in.js:
html`<div style="width: ${a}px;"></div>`;
out.js:
html`<div style="width:${a}"></div>`;
Breaks with this message:
(!) Plugin minify-html-literals: splitHTMLByPlaceholder() must return same number of strings as template parts
input.js:
html`
<div style="--xyz: ${a};">
</div>
`;
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.