I've been trying to figure out why my app ships 130kb of css while a new App with almost the same tailwind plugins ship like 3 or 5kbs, and I think that when I switch to output: 'hybrid' // or server , Astro ships all bundled css, going from 3-5 to 20kb all at once. Is it expected behaviour? It is extremely apparent when using tailwind and blocks page load
#Does non-static output ship full CSS bundle?
39 messages · Page 1 of 1 (latest)
I’m very interested in this topic, and so far, I’ve noticed the following, although I don’t fully understand how Astro, Tailwind, or CSS handle this in detail. My CSS file includes only the relevant Tailwind CSS and is around 5.1 KB for each page of the website (using SSR in server mode). It seems that Tailwind successfully purged unnecessary CSS. Additionally, the CSS is minified after the build process. It appears that the CSS is bundled once for the entire website, shipped only once, and then cached. A file size of 130 KB sounds excessive to me, especially considering that websites like Netflix’s Top 10, which also use Tailwind, have CSS sizes of around 8 KB.
I will submit a repro bit later, but now I just moved to separate backend 🙂
Maybe hybrid output can't figure out how to treeshake tailwind
So, static output:
Server:
Hybrid(same):
@ruby sorrel take a look please 🙂
I am not a member of the Astro team and do not wish to present myself as such—I'm simply interested in the topic.
Here’s what I observed:
Initially, the CSS file in server/hybrid is about 27.4kb.
- Removing the Tailwind plugin DaisyUI reduces the file size to ~17.4kb (a reduction of ~10kb).
- Removing the Tailwind class
prosefurther reduces the CSS to ~5kb (a reduction of ~12.4kb).
This is really strange because I also use prose with the server configuration, and my total CSS across the entire site is only about 5kb.
However, when I check the CSS file in the dist directory after the build, it’s almost 29kb. Yet, on the client side, only 5kb actually get delivered (I'm using Vercel).
Are your data coming from the preview or the deployed site @dim isle ?
Tomorrow, I’ll also be deploying my site via Node.js (I need this for a thesis I’m working on about Astro). Maybe I’ll have more information then. In the meantime, I’ll tag the right support—they probably know more about this. <@&1129102257422610512>
I also worry I may have given the wrong impression, making it seem like you're already receiving professional help through this conversation that took place in the ticket.
I can imagine that with static rendering, the CSS is more thoroughly optimized since it won’t change anymore. However, with SSR rendering through server or hybrid modes, this optimization might not happen because, for example, components with lazy loading only receive their CSS later when needed? Could it be that the optimization is happening on the server side in this case?
Well, you told me you're interested, it doesn't matter if you're a part of team or not. Im looking at total file size without gzip as it is gonna be parsed anyway. Ill try to deploy this example to Vercel, but Im sure it'll gonna be the same full bundle included 🥲 Having removed that, my site loads x2 on the same network spec, because there's not as much css now
I would actually prefer optimisations being made always, I think that's the right thing, because otherwise its pretty stupid to have such a huge css bundle anywhere. What's the point of Astro then if there's more css than js
Did you deploy the site with Node.js, or are you taking the numbers/screenshots from npm run preview?
Alright, I just started your project locally on my machine with Node.js after the build, and I'm also getting the same 27kb of CSS. That's really strange. I'm curious to see what results you'll get with Vercel, and tomorrow I'll try deploying my Vercel instance on Node.js as well. Let's see what comes out of it.
Do either of you use the “universal defaults” setting in your tailwind config?
It removes a bunch of bloat
Could you explain what you mean by "universal defaults"? I'm not entirely sure. From the repo we discussed, the Tailwind config looks like this:
import typography from "@tailwindcss/typography";
import daisyui from "daisyui";
/** @type {import('tailwindcss').Config} */
export default {
content: ["./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}"],
theme: {
extend: {},
},
plugins: [
require('@tailwindcss/typography'),
require('daisyui'),
],
};
optimizeUniversalDefaults: true I think is what it’s called
Not at my desk ATM
Try adding this
experimental: {
optimizeUniversalDefaults: true,
},
This reduces the file size to 25.2 kB.
What was it before? Sorry haven’t fully read up
27.4kB
Nice, a crisp 2.2 kB saved 😅
Is there a reason why static only produces 5kb, while hybrid/server produces around 27kb?
I gave a guess here.
I don’t know but your guess does seem reasonable
There may be less optimization if css is transformed during a build vs on request
Could there be an option to optimize css on the fly when using server output? I mean, css treeshakes itself 👀
Just preview
Your CSS has the same exact content in both bundles (case in point, it has the same hash), your static output preview is gzipped, your hybrid one isn't
if you put the 27kb CSS inside a gzip compressor, the output gets to what you'd expect (exact value depending on how much gzip effort you put, here it's low)
So, how should I mitigate this? Use nginx or something for proxying?
I will try to deploy to vercel in few mins, it uses brotli, wanna try that
Yeah, your reverse proxy or hosting platform will typically be the one doing the compression
If for some reason you really want to handle this at the framework level, you could do it with a middleware, see the answers here: https://github.com/withastro/astro/issues/9397
But typically yeah, the reverse proxy / cdn / host etc does it and doing it at the framework level ends up being wasted effort
Okay thank you for pointing that out!!
@sturdy glacier Yeah, you were right! I wonder how I even came to the point of fooling myself here 🤓 Thank you!
Awesome! Thanks Erika! ❤️