offline-plugin, service-worker webpack 使用記錄

部份內容引自: https://segmentfault.com/a/1190000014311438?utm_source=tag-newestcss

https://www.cnblogs.com/dojo-lzz/p/8047336.htmlhtml

項目代碼webpack

webpack.prod.conf.jsweb

new OfflinePlugin({
      responseStrategy: 'network-first',  // cache-first // 緩存/網絡優先
      safeToUseOptionalCaches: true,    // Removes warning for about `additional` section usage  
      caches: {                // webpack 打包後須要換的文件 正則匹配
        main: [
          // 'css/app.*.css',
          // 'js/vendor.*.js',
          // 'js/app.*.js',
          // '/'
        ],
        additional: [       
          ':externals:'         // add external assets(from outside of webpack build)
     //['**/.*', '**/*.map, '**/*.gz', '**/manifest-last.json'] //
], optional: [ ':rest:' // all unused/uncached assets // '*.js' ] }, // externals: [ // // list assets that are not bundled by webpack here to cache them // '/' // ], externals: null,      // 設置外部連接, 例如配置 http://hello.com/getuser,  那麼在請求這個接口的時候就會進行接口緩存
  autoUpdate: 1000 * 60 / 20,  // 自動更新 // Tell to OfflinePlugin to generate events for ServiceWorker, console.log to some event  
  ServiceWorker: {
    events:
true,
    navigateFallbackURL:
'/static',
    publicPath:
'/sw.js?t=' + +new Date() // 注意, 一個要加上時間戳
    // publicPath: '/sw.js'
  },
  AppCache: {
    FALLBACK: {
'/': '/' }
  }
  // AppCache: false    // 不啓用 application cache 
})

 

JS文件 ajax

OfflinePluginRuntime.install({
    // 監聽sw事件,當更新ready的時候,調用applyUpdate以跳過等待,新的sw當即接替老的sw
  onUpdateReady: () => {
    console.log('SW Event:', 'onUpdateReady')
    OfflinePluginRuntime.applyUpdate()
  },
  onUpdated: () => {
    console.log('SW Event:', 'onUpdated')
    window.swUpdate = true
  }
})

首先介紹一下assets裏面的三個屬性:
main: [] 這裏配置的是serviceWorker在install階段須要緩存的文件清單,若是其中有一個失敗了,那麼整個serviceWorder就會安裝失敗,因此必須謹慎配置json

additional: [] 這裏配置的文件清單會在serviceWorker activate的時候進行緩存,與main不同,若是這裏的文件緩存失敗,不會影響serviceWorker的正常安裝。並且,在接下來頁面的ajax異步請求中,還能進行緩存嘗試segmentfault

optional: [] 這裏配置的文件清單在serviceWorker安裝激活階段不會進行緩存,只有在監聽到網絡請求的時候才進行緩存。瀏覽器

剛纔說到做用域的時候有坑,若是按照上面的文件配置,最後在網頁中會提示,sw最大的做用域權限在/static下面,言外之意這麼寫是沒法將sw的做用域設置在/根路徑下面。
因此這邊須要服務端在返回sw.js的時候手動設置Service-Worker-Allowed頭字段,而且值設置爲/,同時這個文件的緩存時間設爲0,不然,當更新serviceWorker的時候,因爲瀏覽器緩存了sw.js用戶端這邊的serviceWorker沒法第一時間更新。緩存

最後來一張線上項目,在網速極慢的狀況下也能實現秒開網絡

-------------------追加--------------------擴展fetch事件
首先在配置文件裏添加入口

new OfflinePlugin({
      responseStrategy: 'network-first',
      safeToUseOptionalCaches: true,
      caches: {
        main: [
          // 'css/app.*.css',
          // 'js/vendor.*.js',
          // 'js/app.*.js',
          // '/'
        ],
        additional: [
          ':externals:'         // add external assets(from outside of webpack build)
        ],
        optional: [
          ':rest:'           // all unused/uncached assets
          // '*.js'
        ]
      },
      externals: null,
      autoUpdate: 1000 * 60 / 20,
      // Tell to OfflinePlugin to generate events for ServiceWorker, console.log to some event
      ServiceWorker: {
        events: true,
        navigateFallbackURL: '/static',
        entry: path.json(__dirname, './sw-entry.js'),   //  重寫sw
        publicPath: '/sw.js?t=' + +new Date()
        // publicPath: '/sw.js'
      },
      AppCache: false
    })

 

sw.entry.js

self.addEventListener('fetch', function (event) {
  function cachesMatch (request, cacheName) {
    return caches.match(request, {
      cacheName: cacheName
    }).then(function (response) {
      return response
    })
    // Return void if error happened (cache not found)
    ['catch'](function () {})
  }
  function cacheFirst(cacheUrl, CACHE_NAME) {
    var resource = cachesMatch(cacheUrl, CACHE_NAME).then(function (response) {
      if (response) {
        return response;
      }
      // Load and cache known assets
      var fetching = fetch(urlString).then(function (response) {
        if (!response.ok) {
          return response;
        }
        (function () {
          var responseClone = response.clone();
          var storing = caches.open(CACHE_NAME).then(function (cache) {
            return cache.put(urlString, responseClone);
          }).then(function () {
            console.log('[SW]:', 'Cache asset: ' + urlString);
          });
          event.waitUntil(storing);
        })();

        return response;
      });

      return fetching;
    })
    return resource
  }
  function netWorkFirst(cacheUrl, CACHE_NAME) {
    var resource = fetch(cacheUrl).then(response => {
      if (response.ok) {
        var responseClone = response.clone()
        var storing = caches.open(CACHE_NAME).then(function (cache) {
          cache.put(cacheUrl, responseClone);
        }).then(function () {
          console.log('[SW]:', 'Cache asset: ' + cacheUrl);
        });
        event.waitUntil(storing);
        return response;
      }
      // Throw to reach the code in the catch below
      throw new Error('Response is not ok');
    })
    ['catch'](function () {
      return cachesMatch(cacheUrl, CACHE_NAME);
    });
    return resource
  }

  var url = new URL(event.request.url)
  url.hash = ''
  var pathname = url.pathname
  var urlString = url.toString()
  var cacheUrl = urlString
  var IS_KANO = /kano\.guahao\.cn/
  var IS_STATIC = /\/static\//
  var IS_HOME = /^\/(e|u|n)\/(\d+)$/
  var IS_EDITOR = /^\/editor(?!\.)/
  var IS_PREVIEW = /^\/preview(?!\.)/
  var CACHE_PREFIX = __wpo.name
  var CACHE_TAG = __wpo.version
  var CACHE_NAME = CACHE_PREFIX + ':' + CACHE_TAG
  var resource = undefined
  var isGET = event.request.method === 'GET'
  // 以緩存優先的形式緩存 kano 以及 static/* 靜態資源
  if ((cacheUrl.match(IS_KANO) || pathname.match(IS_STATIC)) && isGET) {
    resource = cacheFirst(cacheUrl, CACHE_NAME)
    event.respondWith(resource)
  }
  // 以網絡優先的形式緩存 editor頁面 preview頁面和 production頁面
  if ((pathname.match(IS_HOME) || pathname.match(IS_EDITOR) || pathname.match(IS_PREVIEW)) && isGET) {
    resource = netWorkFirst(cacheUrl, CACHE_NAME)
    event.respondWith(resource)
  }
})
相關文章
相關標籤/搜索