Gatsby中的清除缓存page-data.json文件

时间:2019-10-03 16:51:30

标签: node.js browser-cache gatsby

我有一个由gatsby生成的网站,在该网站上我替换了主页的内容。

不幸的是,先前的版本为/page-data/index/page-data.json提供了不正确的缓存控制标头,导致/page-data/index/page-data.json被缓存在客户端浏览器上(并且显示过时的数据,除非强制刷新)。我还发现page-data.json文件没有散列(请参见https://github.com/gatsbyjs/gatsby/issues/15080)。

我已经更新了缓存控制标头,以使以后的版本不会被缓存,但这对现在具有缓存版本的客户端没有帮助。

如何强制客户端请求此文件的最新版本?

3 个答案:

答案 0 :(得分:2)

查看本教程,这是我一直在使用的解决方案。

https://examsworld.co.in/programming/javascript/how-to-cache-bust-a-react-app/

基本上,它是一个包装器组件,用于检查浏览器的缓存版本是否与package.json中的内部版本号匹配。如果没有,它将清除缓存并重新加载页面。

这就是我的使用方式。

gatsby-browser.js

    export const wrapRootElement = ({ element }) => (
     <CacheBuster>
        {({ loading, isLatestVersion, refreshCacheAndReload }) => {
          if (loading) return null
          if (!loading && !isLatestVersion) {
            // You can decide how and when you want to force reload
            refreshCacheAndReload()
          }
          return <AppProvider>{element}</AppProvider>
        }}
      </CacheBuster>
    )

CacheBuster.js

import React from 'react'
import packageJson from '../../package.json'

global.appVersion = packageJson.version

// version from response - first param, local version second param
const semverGreaterThan = (versionA, versionB) => {
  const versionsA = versionA.split(/\./g)

  const versionsB = versionB.split(/\./g)
  while (versionsA.length || versionsB.length) {
    const a = Number(versionsA.shift())

    const b = Number(versionsB.shift())
    // eslint-disable-next-line no-continue
    if (a === b) continue
    // eslint-disable-next-line no-restricted-globals
    return a > b || isNaN(b)
  }
  return false
}

class CacheBuster extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      loading: true,
      isLatestVersion: false,
      refreshCacheAndReload: () => {
        console.info('Clearing cache and hard reloading...')
        if (caches) {
          // Service worker cache should be cleared with caches.delete()
          caches.keys().then(function(names) {
            for (const name of names) caches.delete(name)
          })
        }

        // delete browser cache and hard reload
        window.location.reload(true)
      },
    }
  }

  componentDidMount() {
    fetch('/meta.json')
      .then(response => response.json())
      .then(meta => {
        const latestVersion = meta.version
        const currentVersion = global.appVersion

        const shouldForceRefresh = semverGreaterThan(
          latestVersion,
          currentVersion
        )
        if (shouldForceRefresh) {
          console.info(
            `We have a new version - ${latestVersion}. Should force refresh`
          )
          this.setState({ loading: false, isLatestVersion: false })
        } else {
          console.info(
            `You already have the latest version - ${latestVersion}. No cache refresh needed.`
          )
          this.setState({ loading: false, isLatestVersion: true })
        }
      })
  }

  render() {
    const { loading, isLatestVersion, refreshCacheAndReload } = this.state
    const { children } = this.props
    return children({ loading, isLatestVersion, refreshCacheAndReload })
  }
}

export default CacheBuster

generate-build-version.js

const fs = require('fs')
const packageJson = require('./package.json')

const appVersion = packageJson.version

const jsonData = {
  version: appVersion,
}

const jsonContent = JSON.stringify(jsonData)

fs.writeFile('./static/meta.json', jsonContent, 'utf8', function(err) {
  if (err) {
    console.log('An error occured while writing JSON Object to meta.json')
    return console.log(err)
  }

  console.log('meta.json file has been saved with latest version number')
})

并在package.json中添加这些脚本

 "generate-build-version": "node generate-build-version",
 "prebuild": "npm run generate-build-version"

答案 1 :(得分:1)

除了单独访问每个客户端浏览器并清除其缓存之外,没有其他任何方法可以使所有客户端的缓存失效。如果您的网页位于您可以控制的CDN后面,则您可以在CDN级别强制失效,因此即使CDN缓存了一个已存在的,过时的副本,新客户端也将始终被路由到最新的网页。

答案 2 :(得分:0)

我最终到达那里了...这是在我的gatsby-node.js

const hash = md5(`${new Date().getTime()}`)

const addPageDataVersion = async file => {
  const stats = await util.promisify(fs.stat)(file)
  if (stats.isFile()) {
    console.log(`Adding version to page-data.json in ${file}..`)
    let content = await util.promisify(fs.readFile)(file, 'utf8')
    const result = content.replace(
      /page-data.json(\?v=[a-f0-9]{32})?/g,
      `page-data.json?v=${hash}`
    )
    await util.promisify(fs.writeFile)(file, result, 'utf8')
  }
}

exports.onPostBootstrap = async () => {
  const loader = path.join(__dirname, 'node_modules/gatsby/cache-dir/loader.js')
  await addPageDataVersion(loader)
}

exports.onPostBuild = async () => {
  const publicPath = path.join(__dirname, 'public')
  const htmlAndJSFiles = glob.sync(`${publicPath}/**/*.{html,js}`)
  for (let file of htmlAndJSFiles) {
    await addPageDataVersion(file)
  }
}