Persisting state with Server Side Rendering

A lot of our projects in the last couple of years have focused on Vue.js. We have used a number of scaffolding solutions and most recently we have had success with Nuxt.js.

One thing we have struggled with however, is state management and persistence. When using a ‘universal’ approach it’s immediately clear that having state traverse between client-side and server-side isn’t that easy. There’s a great plugin that allows you to persist your state into local storage or cookies. Server-Side-Rendering (SSR) doesn’t have access to your local storage, so if you want to harness the power of SSR and state management you have to use cookies.

We have been using the vuex-persistedstate plugin with great success. It works well with nuxt.js and if you create a plugin to handle your storage method, you can create custom hooks for getItem and setItem.

A few online tutorials help you create a snippet to store items in cookies using vuex-persistedstate but we realised that this misses off a fundamental approach. It only allows reading cookies in server-side. What happens if you need to manipulate the state and commit it? Through using cookies, you have to be very selective on what you store due to size restrictions, so we keep ours to a minimum – cookie consent, access tokens and their expiry.

We have an auth guard middleware in place on a project that detects whether the token is valid. If this is invalid it will commit nullify the access token and expiry values before redirecting to the login screen. But the default code doesn’t allow you to persist from SSR code.

We have modified the accepted the nuxt.js approach and hope this will help others.

createPersistedState({
    key: 'cookie-name',
    paths: [
      'module-name',
      'use-dot-notation-for-nested.module-items'
    ],
    storage: {
      getItem: (key) =>
        process.client
          ? Cookies.getJSON(key)
          : cookie.parse(req.headers.cookie || '')[key],
      setItem: (key, value) => {
        if (key !== '@@') {
          process.client
            ? Cookies.set(key, value, { expires: 365, secure: !isDev })
            : res.setHeader(
                'Set-Cookie',
                cookie.serialize(key, value, { maxAge: 365, secure: !isDev })
              )
        }
      },
      removeItem: (key) => Cookies.remove(key)
    }
  })(store)

Hopefully this will help others create ‘universal’ applications that persist a small number of values between server-side and client-side rendering.

Leave a Reply

Your email address will not be published. Required fields are marked *