DEV Community

Cover image for Svelte/Sapper vs Vue
David Porter
David Porter

Posted on

Svelte/Sapper vs Vue

In which I highlight the gap between Sapper and Vue

So I wrote a lovely article with examples comparing Vue and friends to Svelte and Sapper. But twice the draft refused to save and so I gave up. The main point to get across is that .vue components are far more readable than .svelte components. However on every count Svelte requires less code as is their mantra (and it's a good one). But there is one thing where Sapper doesn't quite measure up.

SSR and State Management

While on the surface Server Side Rendering (SSR) is much easier in Sapper, there is one thing isn't quite there. How do we pass the server state back to the client. First let's look at Vue

Vue SSR & Vuex

Vuex helps us manage state centrally in our Vue apps. If you follow the guide the Vuex store is setup as a singleton. It looks something like this.

import Vuex from 'vuex'

const store = new Vuex.Store({
  ...
})
export default store
Enter fullscreen mode Exit fullscreen mode

This is fine on the client, we'll only ever have one store. However when we run SSR we need to service many clients and requests and we can't mixup the store across those requests, so now it needs to look like this.

import Vuex from 'vuex'

export default function createStore(){
 return new Vuex.Store({
  ...
  })
}
Enter fullscreen mode Exit fullscreen mode

Now you can initialise many stores for your many requests. The same principle applies to the Vue app itself as well as Vue Router and Apollo. A quick example of that is as follows.

import Vue from 'vue'
import createStore from './store'

export default createApp(){

  const store = createStore()

  const app = new Vue({
    store
  })

  return { app }
}
Enter fullscreen mode Exit fullscreen mode

in entry-client.js

import createApp from './app'

const { app } = createApp()

app.mount("#app")
Enter fullscreen mode Exit fullscreen mode

On the server once our app has processed the route, mutated the state and rendered the HTML we need to pass the Vuex state to the client before it hydrates, otherwise it will hydrate from a fresh store and now your app will be out of step with your store (which is bad). This is pretty straightforward and you can read about it here. In short the store state is dumped inside <script> tags in the server rendered HTML and when Vue is initialised on the client it slurps it up and updates the client state to match.

Sapper

If you have no idea what Sapper is, it's the equivalent of Nuxt but for Svelte. The creator, Rich Harris, has a nice article introducing Sapper.

Back to SSR, it's not quite the same in Sapper. We don't have the same concept of a Vue class that we can initialise and then feed it things like routers, stores and Apollo clients. In Svelte we have the concept of stores, but as singletons.

When the stores are written to on the server they hang around between requests. This is bad news, not only can you send a user incorrect data, you could send someone else's data (Yikes!). So the best approach would be to not mutate the stores on the server.

But we like having a store on the client and we want the state from the server to come down. Sapper has a couple of approaches towards achieving this.

Session Data

On the server Sapper uses sessions for your user data which you can use to set data on the server and then pass down to the client.

Preload

In the preload function we can fetch data server side before rendering. So in a component you can write something like this

<script context="module">
  export async function preload(page, session) {
     let animal = "dog";
   return { animal }
  }
</script>

<script>
  export let animal;
</script>

<p>
  { animal }
</p>
Enter fullscreen mode Exit fullscreen mode

Then it's up to you on the client side to synchronise the store yourself in the onMount hook. Note that onMount is never called on the server so you can be confident that it is only running on the client.

The preload function however is comparable to asyncData from Nuxt.js and can run on both server AND the client. You can get around this by using the process.browser variable and only executing your server logic inside an if block, but this is cumbersome.

Apollo Client

A big feature of Apollo is caching. In Vue, if we fetch some data server side with Apollo, we can pass down the Apollo state as we did with the Vuex state. Like the above, you've got to handle the heavy lifting yourself and there is no recommended/documented way of doing it and some of things you enjoy (or at least I enjoy) in Vue SSR you just won't be able to achieve with Sapper. While it's not critical, without it you're missing out on an advantage of Apollo.

Summary

Should we all run off and learn Svelte to keep ourselves employed?

The above state management and singleton problem aside... No, if you can do React or Vue then you're still good. If you can't do either of those I would strongly recommend learning one if you want a job as a front end developer. We are in for interesting times however as Svelte production bundles are much much smaller than Vue which means your Time To Interactive (TTI) is also going to be much smaller with Svelte.

Top comments (0)