Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generate CSS/JS bundles at build time #770

Open
jackdbd opened this issue Oct 22, 2024 · 2 comments
Open

Generate CSS/JS bundles at build time #770

jackdbd opened this issue Oct 22, 2024 · 2 comments
Labels
enhancement New feature or request

Comments

@jackdbd
Copy link
Contributor

jackdbd commented Oct 22, 2024

Is your feature request related to a problem?

At the moment Indiekit creates CSS and JS bundles at runtime (see these two lines in middleware/locals.js). This means that on the first request the server has to spend a lot of processing power to generate these bundles. This might not be a big deal if Indiekit is deployed on a VM that runs 24/7, but it's problematic when Indiekit is deployed on a serverless platform like AWS Lambda or Fly.io: every time the serverless platform instantiates the Express app, Indiekit has to recreate those bundles.

I deployed Indiekit on Fly.io and had to wait ~15 seconds on the first request (the second request was almost instantaneous). At first I thought it was due to some cold starts of Fly.io, or long waiting times to establish a connection to MongoDB, or general Express slowness, but the logs told me that my Fly machine started in roughly 800ms, the mongodb driver connected to MongoDB in a few ms, and Express started listening on port 3000 in few ms.

I added a few console.timeLog() and saw that on my laptop Rollup takes ~2.5 seconds to generate the bundle. I didn't manage to have those console.timeLog() printed on the deployed app, but I suspect that most of the waiting time on my small Fly machine (512 MB RAM and a shared CPU) is due to the generation of the CSS and JS bundles.

Describe the solution you’d like

The CSS bundle and the JS bundle, together with the respective source maps, should be generated at build time.

Describe alternatives you’ve considered

No response

Additional context

No response

@jackdbd jackdbd added the enhancement New feature or request label Oct 22, 2024
@paulrobertlloyd
Copy link
Collaborator

Looking at this a bit closer, the 2 lines identified as causing the slowness in start up time are not responsible for compiling assets, but for generating the hashes used for cache busting.

Turns out md5 was a really bad choice for this task; #775 replaces this with sha1, and uses node:crypto’s createHash() method. This results in ~40% improvement generating a hash for the JavaScript file, and ~80% improvement in generating the hash for the CSS file. I’ll ship this in the next release as it’s a quick and clear improvement. Be interesting to see what impact this has on the start-up time on Fly.io.

Looking at compiling CSS and JavaScript, as I thought was the case, this only happens on the first page load (CSS: ~0.08ms, ~JavaScript 1.9s). This isn’t great, but because these assets use the above cache busted asset names and long-lived cache directives, they don’t need to be loaded again, at least until these assets are updated, which is typically when the application is updated to a newer release.

Swapping out Rollup for ESBuild might improve the complication time for the JavaScript bundle; I’d like to try that and see if there’s a significant improvement. However, the reason assets are compiled this way is down to the fact hosts like Heroku only allow writing to disk ephemerally. Other options, such as pre-compiling assets and including them in the package add complexity, and prevent these assets from being dynamically created should different plugins provide their own assets (I don’t think plugins can add assets to these bundles right now, but they could in the future).

@paulrobertlloyd
Copy link
Collaborator

#776 replaces Rollup with esbuild, reducing the time it takes for the JavaScript bundle to be compiled (on first load) by ~13 times. I think this, coupled with the above, should improve asset bundling quite a bit.

The hash creation still takes a little time… one way to potentially avoid that is to use the release version to cache bust assets, but can potentially revisit that as an option later.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants