When you create a Svelte web application intended to operate as a fully static site, you opt for prerendering your pages. This means that the HTML files for your application's pages are generated at build time. The key benefit of this approach is an ultra-fast initial load, improved search engine optimization (SEO), and reduced dependency on a server environment.
For a Svelte application that is to be served as a static website, using adapter-static
is the standard approach. By configuring the adapter in your svelte.config.js
file, you essentially convert your project into one that outputs pure static HTML, CSS, and JavaScript files.
In your svelte.config.js
file, include the following configuration:
// Import the adapter
import adapter from '@sveltejs/adapter-static';
export default {
kit: {
// Configure adapter-static for generating static sites
adapter: adapter({
pages: 'build', // Output folder for HTML pages
assets: 'build', // Output folder for assets like CSS and images
fallback: undefined, // Optional: specify a single-page app fallback if needed
precompress: false, // Optional: if you wish to precompress files
strict: true
})
}
};
With this configuration, when you run the Svelte build command, you'll generate a collection of static files that represent your application's pages.
Once the static adapter is configured, you can opt to pre-render your pages entirely. By setting the prerender
option in your page components, you ensure that the HTML output is generated at build time. This means that there is no server-side component actively rendering these pages when a user accesses them.
To instruct SvelteKit to prerender your components, simply include the following declaration in your page’s script:
// In +page.js or +layout.js
export const prerender = true;
This single line ensures that during the build process, SvelteKit captures a static snapshot of your page.
In cases where additional control is needed – such as managing dynamic routes or excluding specific pages from prerendering – you may set the option to "auto" or manage it on a per-route basis. However, by setting it explicitly to true, you're effectively disabling any ongoing server-side rendering or runtime HTML generation.
Even though your pages are served as static content, many web applications require dynamic updates – whether it’s fetching new content from an API or improving interactivity based on real-time data. Since you have already generated the basic structure and content at build time, dynamic data can be loaded when the page is rendered in the browser.
Svelte provides the onMount
lifecycle hook which executes only on the client-side after a component has been mounted to the Document Object Model (DOM). By utilizing this hook, you can fetch updated or dynamic data once the static page is already loaded in the browser.
// Example in a +page.svelte file
<script>
import { onMount } from 'svelte';
let dynamicData = [];
let loading = true;
async function fetchData() {
try {
const res = await fetch('https://api.example.com/data');
dynamicData = await res.json();
} catch (error) {
console.error('Error fetching data:', error);
} finally {
loading = false;
}
}
onMount(fetchData);
</script>
<template>
<h1>Dynamic Content Loaded in Browser</h1>
{#if loading}
<p>Loading data...</p>
{:else}
<ul>
{#each dynamicData as item}
<li>{item.name}</li>
{/each}
</ul>
{/if}
</template>
In this example, the data retrieval process occurs entirely on the client-side once the page has been loaded. This ensures that your initial page load is fast (thanks to prerendering) and user interactivity is maintained with up-to-date content.
Alternatively, if there's a need to use SvelteKit's load
function, you can define a client-centric data loader in your +page.js
file. While the load
function can run on both the server and client, in a static site scenario, be cautious to ensure that truly dynamic data is fetched on the client side.
// In +page.js
export const prerender = true; // Generate static HTML at build time
export function load() {
return fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => {
return { props: { data } };
})
.catch(error => {
console.error('Error fetching data in load function:', error);
return { props: { data: [] } };
});
}
Note that if you intend for the data to update on the client side after the initial rendering, employing the onMount
approach is typically preferred. The load
function in a static adapter scenario is useful for building the initial render, but for subsequent updates without reloading the page, client-side lifecycle hooks are ideal.
For applications that include dynamic routes (for example, blog posts with dynamic slugs), pre-rendering requires a little extra attention. SvelteKit must be aware of all the possible routes during the build process. If the framework is not explicitly informed of every dynamic route, some pages might fail to generate correctly.
You have two primary options to handle dynamic routes during prerendering:
svelte.config.js
under kit.prerender.entries
to explicitly instruct SvelteKit to render those pages.
// In svelte.config.js
export default {
kit: {
adapter: adapter({...}),
prerender: {
entries: [
'/',
'/about',
'/blog',
'/blog/post-1',
'/blog/post-2'
// add other dynamic routes as necessary
]
}
}
};
This configuration ensures that all specified routes are prerendered, avoiding missing pages at runtime.
The overall strategy for creating a Svelte web application that leverages static site generation while still allowing dynamic updates in the browser revolves around the following key steps:
Step | Description | Key Configuration / Code |
---|---|---|
1. Adapter Setup | Configure your project to output static assets using adapter-static . |
|
2. Prerender Pages | Define prerender in page or layout files to generate static HTML. |
|
3. Dynamic Data Loading | Load additional data in the browser using client-side lifecycle hooks. |
|
4. Handling Dynamic Routes | Ensure all routes, including dynamic ones, are included in the prerender configuration. |
|
5. Optional Load Functions | Optionally use load functions for fetching data during the build or hydration phase. |
|
When your objective is to maintain a fully static website without any active server-side rendering at runtime, it is crucial not to incorporate any server-specific operations in your components. This means avoiding the use of +page.server.js
files for operations that are intended to run on the client. Use client-centric code blocks and client-only library functions to manage dynamic data.
Although your pages are pre-rendered, if you fetch data from external APIs, consider caching responses to minimize latency and load times during client-side fetch operations. Browser caching, service workers, and other client-side optimization techniques can significantly enhance user experience.
Also, if you’re fetching data that does not change frequently, you might consider integrating that data during the build process with more advanced static generation strategies rather than refetching it every page load.
Be sure to test locally by building your SvelteKit application and serving the static output folder using a simple static server. This practice will help you catch any edge cases related to dynamic routing or client-side data issues before deploying to a production environment.
Example command for local testing:
// For example, using serve globally installed via npm
npx serve build