DEV Community

Yaroslav Polyakov
Yaroslav Polyakov

Posted on

Mix static & client-side rendering on same page with SvelteKit

I love static websites, because they are very fast and very good for SEO, google can 'read' it much better. But these days you need JavaScript almost everywhere.

And I like Svelte as very easy to learn and use lightweight framework.

I've found out, that it's not very simple to mix static rendering and CSR on same page. But possible. I will use time (JavaScript Date() result) as example data, but in production it can be your data, e.g. "BFGoodrich tyre" or "Red apples" or "War and Peace by Leo Tolstoy".

Our example page will print very simple text:

Date: Wed, 18 Jan 2023 15:49:03 GMT
Build: Wed, 18 Jan 2023 15:49:01 GMT
Enter fullscreen mode Exit fullscreen mode

First line (Date:) is content you calculated on client-side, when page is loaded. Second line (Build:) is build-time, something you calculated during npm run build which must be visible to search engine.

Create project

npm create svelte@latest hybrid
cd hybrid
npm install
Enter fullscreen mode Exit fullscreen mode

Enable static adapter

Install it: npm i -D @sveltejs/adapter-static

In svelte.config.js disable adapter-auto and use adapter-static:

import adapter from '@sveltejs/adapter-static';
Enter fullscreen mode Exit fullscreen mode

Now you can generate static website with npm run build and preview it with npm run preview.

src/routes/+page.server.js

export const prerender = true
export function load() {
    return {
        t: new Date().toUTCString()
    }
}
Enter fullscreen mode Exit fullscreen mode

src/routes/+page.svelte:

<script>
    import { browser } from '$app/environment';

    export let data;
    var buildtime = data.t
</script>

Date: {#if browser}{new Date().toUTCString()}{/if}
<br>
Build: {buildtime}
Enter fullscreen mode Exit fullscreen mode

Result

run: npm run build && npm run preview and open http://localhost:4173/ you will see result. If you will reload page in a second, Date will change, but Build will stay same.

Also, if you will open build/index.html you will see there:

...
Date: 
<br>
Build: Wed, 18 Jan 2023 15:58:18 GMT
...
Enter fullscreen mode Exit fullscreen mode

As you see, our statically generated content is clearly visible in page.

Explanation

in +page.server.js we set prerendering=true to generate static HTML site (with JS) as a result. And we return data with current Date(). We must convert it to string here, because client browser may have different timezone and Build: date will be "flashing" (initially it will have date in our timezone, and in fraction of second it will be overwritten). Not nice.

in +page.svelte we use this data. Also we conditionally display new Date() (I used .toUTCString() here just to have both dates to look similar, it's not really needed).

Without {#if} you'd get one date built-in HTML (displayed immediately when page loaded) and other date will overwrite it. Not nice visual effect. With {#if} we suppress first date and display only CSR date over empty page space.

Using this method you can combine benefits for static and client-side rendered content at any SvelteKit page.

Top comments (0)