vercel-builder icon indicating copy to clipboard operation
vercel-builder copied to clipboard

Serverless Pre-Rendering (SPR)

Open MarvinMiles opened this issue 5 years ago • 10 comments

Hey

Seems like recently introduced Serverless Pre-Rendering (SPR) feature fits perfectly to nuxt, But I feel a little bit confused about configuration. How can I use that?

Where I need define res header cache?

Would be cool to get some expanded docs. Thanks!

MarvinMiles avatar May 05 '19 03:05 MarvinMiles

Okey. I made it:

import generateETag from 'etag'
import axios from 'axios'

export default {
  async asyncData ({ res }) {
    let { data } = await axios.get(api)
    const etag = await generateETag(JSON.stringify(data))

    if (res) {
      res.setHeader('Cache-Control', 's-maxage=1, stale-while-revalidate')
      res.setHeader("X-version", etag)
    }
    return { data: data, etag: etag }
  },
  mounted () {
    fetch(window.location, {
          headers: {
            pragma: "no-cache"
          }
        }).then(res => {
          if (res.ok && res.headers.get("x-version") !== this.etag) {
            window.location.reload()
          }
    })
  }
}

Also you need configure nuxt.config and set fs to 'empty' for properly building process in now-cloud (required for etag generator)

build: {
    extend (config, { isDev, isClient }) {
      config.node = {
        fs: 'empty'
      }
    }
  }

Probably not the most elegant solution, but it works.

MarvinMiles avatar May 05 '19 09:05 MarvinMiles

@MarvinMiles Nice POC. Something we can do for improvement is moving etag generation logic out of pages into SSR handler. I plan to make a community module for page-level caching. It should also operate in headers-only mode that adds now's so-called SPR support.

pi0 avatar May 05 '19 10:05 pi0

Hey @pi0 @MarvinMiles glad you are talking about this. Does your solution work for you ? Although it's fine locally, when I deploy to now, I still get "public, max-age=0, must-revalidate" I've tried setting the header response as above, and also in server middleware. I can only guess that the header is being set prior to this somehow. Don't suppose either of you have any thoughts ?

Jimtattersall avatar Jun 19 '19 19:06 Jimtattersall

@MarvinMiles Now SPR v2 is about to land - e.g. https://github.com/zeit/now/pull/3067

danielroe avatar Sep 30 '19 20:09 danielroe

Nuxt v2.9 brought new cool feature that related to SPR use case: $nuxt.refresh(). $nuxt.refresh() can refresh page data reactively without actually reloading i.e rerendering the page like window.location.reload() do. Useful in case etag doesn't matches.

P.S. Still feel myself uncomfortable to manually manage etag logic.

MarvinMiles avatar Sep 30 '19 23:09 MarvinMiles

I used a server middleware that set the following header to create a simple implementation of SPR that caches for 30 seconds.

module.exports = function (req, res, next) {
  res.setHeader('Cache-Control', 's-maxage=30, stale-while-revalidate')
  next()
}

jake-101 avatar Oct 03 '19 03:10 jake-101

👀

mediabeastnz avatar Nov 10 '19 23:11 mediabeastnz

Something is coming: https://github.com/pi0/nuxt-swr-cache 🤗

MarvinMiles avatar May 05 '20 01:05 MarvinMiles

@MarvinMiles I don’t quite get the SWR thing, does it relate to Now/Vercel SPR in any way or is it a try to get it without vendor lock-in?

appinteractive avatar Jun 01 '20 18:06 appinteractive

@appinteractive Correct. 'stale-while-revalidate' cache strategy isn't a Vercel`s invention. So making nuxt module to handle it without vendor lock-in makes sense.

BTW https://github.com/vercel/swr serves for another purpose. It handles fetching page data on client or server side while SPR handles cache of rendered HTML output only on server side.

MarvinMiles avatar Jun 01 '20 18:06 MarvinMiles