ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Cache Burst
    Web 2019. 8. 22. 11:51

    1. Overview

    When a static file gets cached it can be stored for very long periods of time before it ends up expiring. Because of that, some visitors can't see changes made. Cache busting solves the browser caching issue by using a unique file version identifier to tell the browser that a new version of the file is available that makes the browser doesn't retrieve the old file from cache but rather makes a request to the origin server for the new file.

     

    There are several ways to solve the cache problem.

    • File name versioning
    • File path versioning
    • Query strings

    Both File name versioning and File path versioning are recommended cache-busting methods. They do not interfere with any caching mechanisms and can be easily updated to reflect a modified file. Query Strings makes some proxies or CDNs unable to cache files so it is recommended not to use it.

     

    But above approaches easy to be forgotten. So there're various ways to solve this problem in an automatic and more sophisticated way.

     

    2. Usages

     

    • VueJS PWA

    If you have used @vue/cli-plugin-pwa plugin, There're three files to update for getting cache busting to work.

    • Service-worker.js
    // service-worker.js
    
    workbox.core.setCacheNameDetails({ prefix: 'd4' })
    //Change this value every time before you build
    const LATEST_VERSION = 'v1.5'
    self.addEventListener('activate', (event) => {
      console.log(`%c ${LATEST_VERSION} `, 'background: #ddd; color: #0000ff')
      if (caches) {
        caches.keys().then((arr) => {
          arr.forEach((key) => {
            if (key.indexOf('d4-precache') < -1) {
              caches.delete(key).then(() => console.log(`%c Cleared ${key}`, 'background: #333; color: #ff0000'))
            } else {
              caches.open(key).then((cache) => {
                cache.match('version').then((res) => {
                  if (!res) {
                    cache.put('version', new Response(LATEST_VERSION, { status: 200, statusText: LATEST_VERSION }))
                  } else if (res.statusText !== LATEST_VERSION) {
                    caches.delete(key).then(() => console.log(`%c Cleared Cache ${LATEST_VERSION}`, 'background: #333; color: #ff0000'))
                  } else console.log(`%c Great you have the latest version ${LATEST_VERSION}`, 'background: #333; color: #00ff00')
                })
              })
            }
          })
        })
      }
    })
    
    workbox.skipWaiting()
    workbox.clientsClaim()
    
    self.__precacheManifest = [].concat(self.__precacheManifest || [])
    workbox.precaching.suppressWarnings()
    workbox.precaching.precacheAndRoute(self.__precacheManifest, {})

    This approach makes service-worker versioning every time you create a production build. But also there's some manual work which is to update LASTEST_VERSION every time you build and deploy a new PWA version.

     

    • registerServiceWorker.js

    All to do is reload the page once the service-worker has been updated. But also note that setting timeout is important. If not, page gets stuck in a reload loop since it calls updated and then tries to activate but then reloads.

    import { register } from 'register-service-worker'
    
    if (process.env.NODE_ENV === 'production') {
      register(`${process.env.BASE_URL}service-worker.js`, {
        ready () {
          console.log('Site is ready')
        },
        cached () {
          console.log('Content has been cached for offline use.')
        },
        updatefound () {
          console.log('New content is downloading.')
        },
        updated () {
          console.log('New content is available; Refresh...')
          setTimeout(() => {
            window.location.reload(true)
          }, 1000)
        },
        offline () {
          console.log('No internet connection found. App is running in offline mode.')
        },
        error (error) {
          console.error('Error during service worker registration:', error)
        },
      })
    }
    • vue.config.js

    Below setting required for keeping and reusing above service-worker instead of replacing new generated one.

    const manifestJSON = require('./public/manifest.json')
    module.exports = {
      pwa: {
        themeColor: manifestJSON.theme_color,
        name: manifestJSON.short_name,
        msTileColor: manifestJSON.background_color,
        appleMobileWebAppCapable: 'yes',
        appleMobileWebAppStatusBarStyle: 'black',
        workboxPluginMode: 'InjectManifest',
        workboxOptions: {
          swSrc: 'service-worker.js',
        },
      },
    …

     

    • index.html

    Lastly, if your app is already in a live state, the above approach doesn't work until the visitor does a full refresh. So there's some code to uninstall service-workers in index.html for a week/month.

    if(window.navigator && navigator.serviceWorker) {
      navigator.serviceWorker.getRegistrations()
      .then(function(registrations) {
        for(let registration of registrations) {
          registration.unregister();
        }
      });
    }

     

    3. References

    https://www.notion.so/31b94a5fe0f0493c8054422be4fb56a7

    https://www.keycdn.com/support/what-is-cache-busting

    https://medium.com/js-dojo/vuejs-pwa-cache-busting-8d09edd22a31

    'Web' 카테고리의 다른 글

    Web Service and Web Application  (0) 2019.08.31
    Comparison between REST and SOAP with HTTP  (0) 2019.08.23

    댓글

Designed by Tistory.