Optimize JavaScript Bundle Sizes in SvelteKit by using server load functions
The amount of JavaScript you ship to your users directly impacts your site’s performance. A smaller bundle size means faster initial loading times and an overall snappier experience for end users. In this post, I’ll show you how to analyze your SvelteKit bundle size and optimize it by moving heavy dependencies to the server.
Analyzing Bundle Sizes
Before we start, let’s set up a tool to visualize our bundle sizes. We’ll use rollup-plugin-visualizer, which works great with SvelteKit.
Install the package into your existing SvelteKit project:
npm install --save-dev rollup-plugin-visualizer
Configure it in vite.config.ts
:
import { sveltekit } from '@sveltejs/kit/vite';
import { defineConfig } from 'vitest/config';
import { visualizer } from 'rollup-plugin-visualizer';
export default defineConfig({
plugins: [
sveltekit(),
visualizer({
emitFile: true,
filename: 'stats.html'
})
],
test: {
include: ['src/**/*.{test,spec}.{js,ts}']
}
});
When you build your project with npm run build
, you’ll find a stats.html
file in .svelte-kit/output/client/
(or in build/
if you are using adapter-static). This visualization shows you exactly what makes up your JavaScript bundle. Here’s an example of a client chunk visualization in a brand new SvelteKit project:
Optimizing a Real-World Example: Moment.js
Let’s look at a common scenario – using Moment.js for date formatting. Many developers would import it directly into their Svelte component or +page.svelte files:
// +page.svelte
<script>
import moment from 'moment';
let currentDate;
onMount(() => {
currentDate = moment().format('MMMM Do YYYY');
});
</script>
{currentDate}
When we check our bundle visualization after building, we’ll see that Moment.js takes up a huge portion of our client-side bundle – around 30% bundle size increase just to render a single date!
Universal vs Server Load Functions
We might be tempted to move our date handling to a universal load function. Let’s see if that has any impact on the bundle size:
// +page.ts
import moment from 'moment';
export const load = () => {
return {
date: moment().format('MMMM Do YYYY')
};
};
When we check our bundle size, we’ll see that the bundle size hasn’t changed at all! This is because universal load functions run both on the server and client, meaning the entire Moment.js library still gets shipped to the browser.
What we can do instead is to move the moment import to the server load function. The code remains the same, we simply move it to +page.server.ts
// +page.server.ts
import moment from 'moment';
export const load = () => {
return {
date: moment().format('MMMM Do YYYY')
};
};
The key difference is that a server load functions, as the name implies, only run on the server. Instead of sending the entire Moment.js library to the client, we now just send the formatted date string over the wire. Our bundle visualization now shows a dramatic reduction in size, back to the initial baseline size:
Best Practices for reducing bundle sizes in SvelteKit
- Use the bundle visualizer (rollup-plugin-visualizer) during your final optimization phase or whenever you add new dependencies
- Look for large boxes in the visualization – they represent optimization opportunities in the form of large packages being shipped to the client
- Move heavy data processing to server load functions when possible. Keep in mind that server load functions are still rerun during navigation and when using
invalidate()
orinvalidateAll()
, making them almost as interactive as client side functionality.
This approach can be applied to any heavy processing. Common examples could be data transformation, complex calculations, and text processing.
The two downsides of using server load functions is that:
- You will incur a trip to the backend for each reload of the function
- They can’t be used with prerendered routes or when using adapter-static
By being mindful of where your code runs and using server load functions strategically, you can significantly reduce the amount of JavaScript you ship to your users!
If you want a hands-on demonstration of the above approach, check out my video about SvelteKit bundle sizes below!
Have you tried this approach? How did it work out for you? Leave your thoughts in the comments below!
View Comments
Better AI LLM assistance for Svelte 5 and SvelteKit
With the release of Svelte 5 and its new runes syntax, many developers are wondering...