Open sherifsalah opened 1 year ago
I have also noticed that the output for custom elements are larger in Svelte 4 (~50% larger).
I have tried to reproduce the difference with a minimal implementation:
npm init vite
)Counter.svelte
a custom element, and configured the project to build custom elements.https://github.com/mnorlin/svelte-4-custom-element-issue
commit | description | js output size |
---|---|---|
318d240 | Svelte 4 | 7.74 kB |
22e7f08 | Svelte 3 | 4.58 kB |
(@sherifsalah: your reproduction don't seem to build, and I think all the bundled CSS in the component makes it hard to compare the output size of the generated javascript, as the size differences probably becomes less significant with more CSS).
A slight increase in the baseline bundle size is expected, since we're now using a wrapper around the existing Svelte components to create the custom elements. It shouldn't account for that big of an increase though.
I instead suspect this being due to the CSS being inlined into the JavaScript (else there's no reliable way to load them since shadow dom is used). Could you share your repository where this happens? If that's not possible, what are the compiler options you pass to Svelte?
@mnorlin @dummdidumm I used a lot of CSS and sometimes imports from CSS Frameworks and i know all the limitations cause i made a lot of plugins using svelte custom elements, and currently i do my best to manually purge any unsed css based on the used classes' names, anyways in any case logically the same amount of inline CSS shouldn't change in both versions. (10KB of CSS as example shouldn't increase!) the main problem here, the size grows exponentially as i mentioned 70KB in svelte 3 became 120KB in svelte 4 so it is up to 100% increase in size! @dummdidumm sorrowfully i can't share any existing repos that's why i tried to fabricate a close example using an existing repl, if you need me to fabricate another example or fix any issues with the current one i'll gladly do so, i depend a lot on svelte for more than 3 or 4 years now and i really need to help fixing this problem or i'll stuck with svelte 3 for a long time or until i find an alternative. i don't mind a "slight" increase in the wrapper as you mentioned maybe 5 or 10 more Kbs not a big deal but not 50Kbs!
I tried to isolate the problem is it JS or CSS and compiled the plugin without any CSS at all and here is the results: with Svelte 3:
vite v4.3.9 building for production...
✓ 19 modules transformed.
dist/index.html 54.93 kB │ gzip: 7.33 kB
dist/assets/index-260c33d6.js 39.28 kB │ gzip: 13.82 kB
✓ built in 3.85s
with Svelte 4:
✓ 40 modules transformed.
dist/index.html 54.93 kB │ gzip: 7.33 kB
dist/assets/index-d5085aed.js 42.51 kB │ gzip: 14.60 kB
✓ built in 4.27s
And with CSS with Svelte 3:
✓ 19 modules transformed.
dist/index.html 54.93 kB │ gzip: 7.33 kB
dist/assets/index-c1c13d88.js 69.78 kB │ gzip: 19.79 kB
✓ built in 4.68s
with Svelte 4:
✓ 40 modules transformed.
dist/index.html 54.93 kB │ gzip: 7.33 kB
dist/assets/index-6a6bdca3.js 106.18 kB │ gzip: 22.35 kB
✓ built in 4.88s
Concluding that the JS difference is 3.23KB
which is not a big deal and with CSS the difference is 36.4KB
The provided example without CSS in Svelte 3:
✓ 8 modules transformed.
dist/index.html 0.40 kB │ gzip: 0.28 kB
dist/assets/index-6028c763.js 15.18 kB │ gzip: 6.65 kB
✓ built in 665ms
and without CSS in Svelte 4:
✓ 29 modules transformed.
dist/index.html 0.40 kB │ gzip: 0.28 kB
dist/assets/index-8d43cd03.js 17.97 kB │ gzip: 7.53 kB
✓ built in 774ms
With CSS in Svelte 3:
✓ 8 modules transformed.
dist/index.html 0.40 kB │ gzip: 0.28 kB
dist/assets/index-e5819c2c.js 22.67 kB │ gzip: 8.95 kB
✓ built in 5.24s
And with CSS in Svelte 4:
✓ 29 modules transformed.
dist/index.html 0.40 kB │ gzip: 0.28 kB
dist/assets/index-d63461f3.js 27.21 kB │ gzip: 9.97 kB
✓ built in 5.30s
Concluding that the JS difference is 7.49KB
which is not a big deal and with CSS the difference is 9.24KB
And with @mnorlin example which doesn't have any CSS its 3.16KB
So JS increases as the component grows but not that much, and CSS explodes which is so weird cause its supposed to be a simple same sized string that will be injected into the header.
Quick note: (maybe not related but it affectes the size a tiny bit) there is a lot of fragments in the bundle as well, mostly comes from transition functions i guess!
return{delay:t,duration:n,easing:s,css:(l,b)=>`
transform: ${d} scale(${1-a*b});
opacity: ${f-c*b}
`
From that comparison, the increase in size is mainly due to the new baseline size and due to the Svelte class names now being applied within Svelte components:
-.foo { color: red }
+.foo.svelte-xyz { color: red }
which is necessary because internally you can now use Svelte components as normally. This also shows due to the very small difference in size when gzipped as the hashes can be minified very well.
So far this all looks like expected, but the increase of almost 100% from 70kb to 120kb still sounds weird - which is why we need a proper reproduction for this.
@dummdidumm I guess i found the problem, there is redundant class names in CSS, i'll share portions of my actual code and the built bundle and you will get the idea. Here is the actual CSS code: and this is the result:
As you can see the class name is written multiple times:
.svelte-11mb47x.svelte-11mb47x.svelte-11mb47x.svelte-11mb47x::after{box-sizing:border-box}
while we only need it once?!
After manually deleting the redundant .svelte-11mb47x
and minify the script again it became pretty normal reduced to 83KB
@dummdidumm can I suggest to have an option to change ‘svelte-‘ prefix to a shorter abbreviation or something to save some bytes! Maybe ‘sv-‘ or whatever.
You can do that yourself using the cssHash option - if you're sure that your styles don't need to be scoped in any way, you can just return a single character from that option, which should get your script size down.
In the end it won't make a big difference though since most servers will compress everything and those algorithms are very good at shrinking character sequences that appear often.
You can do that yourself using the cssHash option - if you're sure that your styles don't need to be scoped in any way, you can just return a single character from that option, which should get your script size down.
In the end it won't make a big difference though since most servers will compress everything and those algorithms are very good at shrinking character sequences that appear often.
That was a side request anyways.. Thank you so much for this info, i know it will not make a big difference in small elements but in my case it will save a few KBs.
Apart from that i hope that my last example is clear enough, the same redundancy problem exists in the original provided example as well like this .svelte-1wbq7af.svelte-1wbq7af
The issue is somewhat more general, example REPL. We'll look into whether or not it's safe to deduplicate the hash in that case.
The issue is somewhat more general, example REPL. We'll look into whether or not it's safe to deduplicate the hash in that case.
Oooh wow, never noticed that before (nobody digs into the generated css code i guess 😄), i hope you can find a solution for that, thanks.
customElement
using single Dialog
component from bits-ui
.
With customElement=true
:
vite v5.3.1 building for production...
✓ 546 modules transformed.
dist/index.js 1,488.17 kB │ gzip: 218.27 kB
dist/index.umd.cjs 830.70 kB │ gzip: 165.71 kB
With customElement=false
:
vite v5.3.1 building for production...
✓ 546 modules transformed.
dist/index.js 114.75 kB │ gzip: 25.89 kB
dist/index.umd.cjs 64.94 kB │ gzip: 20.31 kB
1488 kB??
I'm exploring different bundle sizes using customElement
for my Shopify Theme Extension and noticed a significant increase in bundle size for customElement
components from Svelte 3 to Svelte 5. While larger projects might benefit from decreased component sizes, standalone customElement
bundles have increased notably, making me consider SolidJs for its smaller bundle sizes compared to Svelte 5.
app.js
/ solid.js
are the shared "framework" code between the components (Counter
and Reviews
).
Framework | Counter.js | Reviews.js | app.js/solid.js | manifest.json | app.css |
---|---|---|---|---|---|
Svelte 3 | 2.55 kB (1.19 kB) | 9.92 kB (4.03 kB) | 4.46 kB (1.97 kB) | 0.64 kB (0.24 kB) | 10.64 kB (2.89 kB) |
Svelte 4 | 2.38 kB (1.11 kB) | 9.79 kB (3.97 kB) | 7.41 kB (3.02 kB) | 0.64 kB (0.23 kB) | 10.92 kB (2.91 kB) |
Svelte 5 | 1.82 kB (0.91 kB) | 10.00 kB (4.72 kB) | 19.79 kB (8.04 kB) | 0.64 kB (0.23 kB) | 10.92 kB (2.91 kB) |
SolidJs | 1.65 kB (0.77 kB) | 6.02 kB (2.65 kB) | 14.01 kB (5.32 kB) | 0.69 kB (0.24 kB) | 10.54 kB (2.87 kB) |
This is a simple counter component that is rendered as a custom element.
This is a simple counter component that is rendered as a custom element.
This is a simple counter component that is rendered as a custom element.
This is a simple counter component that is rendered as a custom element.
Note: I used Vite (v^5.3.4
) with the @sveltejs/vite-plugin-svelte
(v^3.1.1
for Svelte v3/4 and v^4.0.0-next.4
for Svelte v5) and vite-plugin-solid
(v^2.10.2
for SolidJs v1) plugin with minify
= true
and Counter.xyz
and Reviews.xyz
as entry points (input
). And for styling I used Tailwind with PostCss.
My question is whether my basic analysis is correct in concluding that for Svelte 5, the shared framework function will increase by over 100%, or if I've misconfigured something and can significantly decrease the bundle size for Svelte 5?
Thanks :)
Can you show the code for Reviews.svelte
? Curious to know why it's bigger than Svelte 4.
In general, yes, the runtime is bigger in Svelte 5 than in Svelte 4, though there's definitely room to improve the tree-shakeability of parts of it and/or shrink it down.
@dummdidumm Thanks for the quick reply. Reviews.svelte
is mainly HTML code.
Ok, so it's expected to have a 100% + larger runtime size. Do you know how much room for improvement there might be?
Thanks :)
{reviews.average} out of 5 stars
Based on {reviews.totalCount} reviews
{count.rating} star reviews
If you’ve used this product, share your thoughts with other customers
Write a review{review.rating} out of 5 stars
Describe the bug
I created a plugin as a custom element with Svelte 3 it was generating a small bundle size around
70kb
but after migration to Svelte 4 its now around120kb
, that's almost double the size .. nothing changed at all just svelte version.I provided a quick example from svelte's own examples that's generating
22.67kb
with Svelte 3 and27.21kb
with Svelte 4 .. and added sass support and imported a few sass modules from bootstrap just for testing purposes.Reproduction
REPL
Logs
System Info
Severity
annoyance