48

在我第一个尝试与官方 PWA 插件(https://github.com/yyx990803/register-service-worker)搏斗的 vue 项目中。我的具体问题:捕获注册的服务人员并将其用于任何事情。github 自述文件显示了生成的确切文件,关于如何与这个服务工作者一起工作的文档似乎为零(我是否捕获了注册实例?如果是,如何?)

我发现了这个问题:https ://github.com/vuejs/vue-cli/issues/1481 并提供了一个更好的地方来讨论这个问题,因为我找不到任何示例代码或关于如何与此合作。

如果有人有一些示例代码,请分享。Vue 和新的 cli 是令人难以置信的工具,记录这样的事情是提高平台采用率的必要步骤

4

2 回答 2

79

正如已经指出的,这更像是一个“服务工作者”问题,而不是一个“vue cli”问题。首先,为了确保我们在同一个页面上,下面是registerServiceWorker.js的样板内容应该是这样的(vue cli 3,官方 pwa 插件):

import { register } from 'register-service-worker'

if (process.env.NODE_ENV === 'production') {
  register(`${process.env.BASE_URL}service-worker.js`, {
    ready () {
      console.log(
        'App is being served from cache by a service worker.\n'
      )
    },
    cached () {
      console.log('Content has been cached for offline use.')
    },
    updated () {
      console.log('New content is available; please refresh.')
    },
    offline () {
      console.log('No internet connection found. App is running in offline mode.')
    },
    error (error) {
      console.error('Error during service worker registration:', error)
    }
  })
}

如果您没有更改 .env 文件中的 BASE_URL 变量,那么它应该对应于您的 vue 应用程序的根目录。您必须在公共文件夹中创建一个名为service-worker.js的文件(以便在构建时将其复制到您的输出目录中)。

现在,重要的是要了解registerServiceWorker.js文件中的所有代码都是注册服务工作者并在其生命周期中提供一些挂钩。这些通常用于调试目的,而不是实际对 service worker 进行编程。您可以通过注意到registerServiceWorker.js文件将被捆绑到app.js文件中并在主线程中运行来理解它。

vue-cli 3 官方 PWA 插件基于 Google 的 workbox,因此要使用 service worker,您必须首先在项目的根目录下创建一个名为 vue.config.js 的文件,并将以下代码复制到其中:

// vue.config.js
module.exports = {
    // ...other vue-cli plugin options...
    pwa: {
        // configure the workbox plugin
        workboxPluginMode: 'InjectManifest',
        workboxOptions: {
            // swSrc is required in InjectManifest mode.
            swSrc: 'public/service-worker.js',
            // ...other Workbox options...
        }
    }
}

如果您已经创建了一个 vue.config.js 文件,那么您只需将 pwa 属性添加到配置对象。这些设置将允许您创建位于的自定义服务工作者,public/service-worker.js并让工作箱在其中注入一些代码:预缓存清单。这是一个 .js 文件,其中对已编译静态资产的引用列表存储在通常名为self.__precacheManifest. 您必须在生产模式下构建您的应用程序,以确保是这种情况。

由于它是在您在生产模式下构建时由工作箱自动生成的,因此预缓存清单对于缓存您的 Vue 应用程序外壳非常重要,因为静态资产通常在编译时被分解成块,您引用这些块会非常乏味每次(重新)构建应用程序时在服务人员中。

要预缓存静态资产,您可以将此代码放在service-worker.js文件的开头(您也可以使用 try/catch 语句):

if (workbox) {
    console.log(`Workbox is loaded`);

    workbox.precaching.precacheAndRoute(self.__precacheManifest);

} 
else {
    console.log(`Workbox didn't load`);
}

然后,您可以通过使用基本的服务工作人员 API或使用工作箱的 API继续在同一个文件中正常地对服务工作人员进行编程。当然,不要犹豫,将这两种方法结合起来。

我希望它有帮助!

于 2018-09-06T22:07:08.097 回答
47

作为上述答案的补充:我写了一个小指南,介绍如何使用上面的设置进一步向自定义服务工作者添加一些功能。你可以在这里找到它。

要记住四个主要事项:

  1. 将 Workbox 配置vue.config.jsInjectManifest模式,将swSrc密钥指向自定义 service-worker 文件/src
  2. 在这个自定义的 service-worker 中,一些行将在构建过程中自动添加用于导入precache-manifestworkbox CDN. 需要在自定义service-worker.js文件中添加以下行以实际预缓存清单文件:

    self.__precacheManifest = [].concat(self.__precacheManifest || []);
    workbox.precaching.suppressWarnings();
    workbox.precaching.precacheAndRoute(self.__precacheManifest, {});
    
  3. 监听文件中的注册事件registerServiceWorker.js。您可以使用作为第一个参数传递给事件处理程序的注册对象将消息发布到service-worker.js文件:

    ...
    updated(registration) {
      console.log("New content is available; please refresh.");
      let worker = registration.waiting
      worker.postMessage({action: 'skipWaiting'})
    },
    ...
    
  4. 订阅service-worker.js文件中的消息并采取相应措施:

    self.addEventListener("message", (e)=>{
        if (e.data.action=='skipWaiting') self.skipWaiting()
    })
    

希望这可以帮助某人。

于 2018-12-05T10:13:42.770 回答