Potential tweaks to allow smaller terser output
coreyfarrell opened this issue · comments
I've been using uhtml in my own projects, I noticed a couple small tweaks that could be made to allow better size reduction by terser. This isn't so much a bug report but just seeking feedback before I propose any PR's / investigate further.
Use arrow functions everywhere.
This is tiny, in my own build switching the two functions reduces final bundle output by 23 bytes. This is because terser can take all arrow functions and output var f1=()=>{},f2=()=>{};
where regular functions it has to output function f1(){}function f2(){}
. Since arrow functions are already used elsewhere I think this should be a non-issue for compatibility.
Make it easier to detect const IE = importNode.length != 1;
in esm/node.js
.
For builds targeting modern browsers a babel plugin changing this to const IE = false;
reduces the bundle by 96 bytes. This is because it allows terser to perform constant evaluation and eliminate IE == true
branches. This isn't strictly required as I could have babel detect the IE
variable declaration in uhtml/esm/node.js
and replace the initialization value.
One question I have is ESM even supported on any platform where document.importNode.length != 1
?
Consider having @ungap/create-content
export createSVG
and createHTML
as separate functions.
This would make it possible for uhtml to use these two functions directly from the html
and svg
functions, allow tree shaking to eliminate the svg code if it is unused in a project. The idea is that uhtml/esm/index.js would have:
const html = tag(createHTML);
const svg = tag(createSVG);
I haven't fully evaluated the changes that would be needed to have uhtml use these two functions directly instead of having the string type
argument and I also haven't looked to see how much this would actually reduce the size. Also not sure if this would be considered a breaking change for the Hole
object to no longer have type: 'html'
.
is ESM even supported on any platform where document.importNode.length != 1
legacy Edge has the same issue but it supports ES2015
This isn't so much a bug report but just seeking feedback before I propose any PR's / investigate further.
how many modules do I need to change, beside uhtml, and for which gain? 200 bytes? I wouldn't bother.
P.S. the new.js
file is already ES2015 only https://github.com/WebReflection/uhtml/blob/master/new.js and it's 5.78 KB vs 6.91 KB
P.S.2 the createContent
change sounds reasonable, but it would break @ungap
so ... it's a major ... but again, for few bytes, I'm not sure the breaking change is worth it.
I've looked this over further and I think renaming the IE
variable in esm/node.js
is the only thing I hope to see merged into uhtml. I have the following in my babel config using babel-replace-variable-init:
plugins: [
babelReplaceVariableInit({
IE: ({types: t}) => t.booleanLiteral(false)
})
]
Unfortunately if anything else declares an IE
variable my babel plugin would reset that as well, so renaming the variable would make my build safer without needing to restrict the plugin to the specific file. My suggestion would be const importNodesLegacyArgs = importNodes.length != 1
. If you don't object to this I could post a PR.
P.S. the
new.js
file is already ES2015 only https://github.com/WebReflection/uhtml/blob/master/new.js and it's 5.78 KB vs 6.91 KB
I'm not able to use this in my build process, I need to import from ES modules - import {html, render} from 'uthml'
.
P.S.2 the
createContent
change sounds reasonable, but it would break@ungap
so ... it's a major ... but again, for few bytes, I'm not sure the breaking change is worth it.
This could be non-breaking if the existing createContent
remained as the default export and createHTML / createSVG became named exports but the changes inside uhtml
could be complicated. Instead I'm just using rollup-plugin-includepaths
to provide a stripped down copy of createContent
which supports HTML only. This eliminates a few hundred bytes from my build without needing difficult or potentially breaking changes in uhtml.
I'm not able to use this in my build process, I need to import from ES modules - import {html, render} from 'uthml'.
my point is that I already drop unnecessary bloat https://github.com/WebReflection/uhtml/blob/master/rollup/new.config.js
maybe you could do the same?
This could be non-breaking if the existing createContent remained as the default export and createHTML / createSVG became named exports but the changes inside uhtml could be complicated.
it's not complicated, it's just that default and named exports usually play very badly with bundlers out there.
so ... IE
has been renamed as isImportNodeLengthWrong
which plays well with the ternary I'm using to define behaiors ... regarding createContent
though, I don't think splitting the module would really allow tree shaking in uhtml, because I still need to check if the type
is html
instead of svg
, and that's a runtime check I'm not sure bundlers can tree-shake.
Anyway, fixing/improving one thing at the time, so I hope this patch update works for you.
P.S. the same trick you do with IE
variable, now renamed, could be applied to createSVG
, as ()=>{}
no-op. Tree shake, if you are sure you'll never use/need svg
in there, would drop the surrounding code related to createSVG
and all you have is a method that does nothing.
Renaming the variable is great, I'm just going to use a stripped @ungap/create-content
in my build which will accomplish the other gains. Thanks!