爲 VUE 項目添加 PWA 解決發佈後刷新報錯問題

爲何要給 VUE 項目添加 PWA

爲何要添加?由於無論是部署在 IIS,仍是 nginx,每次應用部署後,再次訪問由於舊的 js 已經不存在,因此頁面訪問的時候會整個報錯,報錯的結果就是一個白屏。
爲了解決這個問題,個人解決方案是使用 PWA ,這樣就能夠將 js 緩存到本地,再次發佈後,service-worker.js 會使舊的 js 失效,從新請求並緩存 js。css

若是對於問題這個有更好的解決方案,務必請大佬指定一二html

安裝 PWA 的相關依賴包

yarn 安裝vue

yarn add sw-precache-webpack-plugin --dev
yarn add uglify-es --dev

npm 安裝webpack

npm install sw-precache-webpack-plugin --dev-dev
npm install uglify-es --dev-dev

添加修改相關配置

下面這些文件忘記出處是哪,Github也能搜到一些,以前寫的 PWA 的 Demo 裏面拿過來的~nginx

添加 build/service-worker-dev.js

self.addEventListener('install', () => self.skipWaiting())

self.addEventListener('activate', () => {
  self.clients.matchAll({ type: 'window' }).then(windowClients => {
    for (let windowClient of windowClients) {
      // Force open pages to refresh, so that they have a chance to load the
      // fresh navigation response from the local dev server.
      windowClient.navigate(windowClient.url)
    }
  })
})

添加 build/service-worker-prod.js

;(function() {
  'use strict'

  // Check to make sure service workers are supported in the current browser,
  // and that the current page is accessed from a secure origin. Using a
  // service worker from an insecure origin will trigger JS console errors.
  var isLocalhost = Boolean(
    window.location.hostname === 'localhost' ||
      // [::1] is the IPv6 localhost address.
      window.location.hostname === '[::1]' ||
      // 127.0.0.1/8 is considered localhost for IPv4.
      window.location.hostname.match(
        /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
      )
  )

  window.addEventListener('load', function() {
    if (
      'serviceWorker' in navigator &&
      (window.location.protocol === 'https:' || isLocalhost)
    ) {
      navigator.serviceWorker
        .register('service-worker.js')
        .then(function(registration) {
          // updatefound is fired if service-worker.js changes.
          registration.onupdatefound = function() {
            // updatefound is also fired the very first time the SW is installed,
            // and there's no need to prompt for a reload at that point.
            // So check here to see if the page is already controlled,
            // i.e. whether there's an existing service worker.
            if (navigator.serviceWorker.controller) {
              // The updatefound event implies that registration.installing is set
              var installingWorker = registration.installing

              installingWorker.onstatechange = function() {
                switch (installingWorker.state) {
                  case 'installed':
                    // At this point, the old content will have been purged and the
                    // fresh content will have been added to the cache.
                    // It's the perfect time to display a "New content is
                    // available; please refresh." message in the page's interface.
                    break

                  case 'redundant':
                    throw new Error(
                      'The installing ' + 'service worker became redundant.'
                    )

                  default:
                  // Ignore
                }
              }
            }
          }
        })
        .catch(function(e) {
          console.error('Error during service worker registration:', e)
        })
    }
  })
})()

添加 build/load-minified.js

'use strict'

const fs = require('fs')
const UglifyJS = require('uglify-es')

module.exports = function(filePath) {
  const code = fs.readFileSync(filePath, 'utf-8')
  const result = UglifyJS.minify(code)
  if (result.error) return ''
  return result.code
}

修改 build/webpack.prod.conf.js

首先引用sw-precache-webpack-pluginbuild/load-minifiedgit

const SWPrecacheWebpackPlugin = require('sw-precache-webpack-plugin')
const loadMinified = require('./load-minified')

爲 webpack 插件 HtmlWebpackPlugin 添加參數 serviceWorkerLoader: `<script>${loadMinified( path.join(__dirname, './service-worker-prod.js'))}</script>github

plugins: [
      ....
  new HtmlWebpackPlugin({
      filename:
        process.env.NODE_ENV === 'testing' ? 'index.html' : config.build.index,
      template: 'index.html',
      inject: true,
      minify: {
        removeComments: true,
        collapseWhitespace: true,
        removeAttributeQuotes: true
        // more options:
        // https://github.com/kangax/html-minifier#options-quick-reference
      },
      // necessary to consistently work with multiple chunks via CommonsChunkPlugin
      chunksSortMode: 'dependency',
      serviceWorkerLoader: `<script>${loadMinified( path.join(__dirname, './service-worker-prod.js'))}</script>`
    }),

並在最後添加 SWPrecacheWebpackPlugin 插件web

// service worker caching
new SWPrecacheWebpackPlugin({
  cacheId: 'web_pwa',
  filename: 'service-worker.js',
  staticFileGlobs: ['dist/**/*.{js,html,css}'],
  minify: true,
  stripPrefix: 'dist/'
})

在 /index.html 中注入 service-worker.js

<%= htmlWebpackPlugin.options.serviceWorkerLoader %>

以下所示npm

<body>
  <div id="app"></div>
  <%= htmlWebpackPlugin.options.serviceWorkerLoader %>
  <!-- built files will be auto injected -->
</body>

至此,添加完畢,build 以後查看緩存中是否包含 js 檢驗結果緩存

注意:PWA 應用須要在本地上運行或者 https 協議下, 要保證你的頁面是安全頁面。

結語

幾分鐘就搞定了,而後把以前的一個基於VUE的後臺模板項目也升級了,若是有相同需求的能夠參考下。

倉庫地址:https://github.com/yimogit/me-admin-template
線上預覽:https://vue-admin.yimo.link/

相關文章
相關標籤/搜索