Vue Cli 3如何使用官方PWA插件(服务工作者)

49

我在我的第一个Vue项目中尝试使用官方的PWA插件(https://github.com/yyx990803/register-service-worker),但遇到了具体问题:如何捕获已注册的Service Worker并将其用于其他操作。GitHub上的readme文件展示了生成的确切文件,但似乎没有任何关于如何处理已实例化的Service Worker的文档(需要捕获注册实例吗?如果是,该如何操作?)

我找到了这个问题:https://github.com/vuejs/vue-cli/issues/1481,并提供了一个更好的讨论平台,因为我无法找到任何有关如何处理此问题的示例代码或清晰的文档。

如果有人有一些示例代码,请分享。Vue和新的CLI都是不可思议的工具,记录像这样的内容是推动平台采用率的必要步骤。


有一些人似乎已经找到了另一种解决方案,那就是不使用这个插件和它提供的样板,而是根据他们在网上找到的任何文档创建自己的服务工作者。这是一个可行的解决方案,但我想过周末试试看这个插件是否可以实际使用。 - Erik White
1
我认为这可能更多是你对服务工作者的知识的缺乏,而不是真正与vue相关的问题。 - Derek Pollard
1
非常可能。观察得非常好。 - Erik White
2
我曾经也遇到过vue-cli 3 PWA插件的同样问题。文档不是很理想,你说得对。我试图用我在解决这个问题时获得的所有知识来回答你的问题。希望能对你有所帮助。 - LeCodex
1
是的@LandryBETE,这正是我所希望的。当我在九月份看到你的回复时,我已经保存了这个标签页,现在才打开它(幸运的是,我的工作项目直到现在都没有要求我深入开发PWA功能)。非常感谢您提供如此丰富、深入的回应,我相信它将会帮助无数人。 - Erik White
2个回答

80

如已指出,这更多是一个“服务工作者”问题,而不是“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应用程序的根目录。您需要在public文件夹中创建一个名为service-worker.js的文件(以便在构建时将其复制到输出目录中)。

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

vue-cli 3官方PWA插件基于Google的workbox,因此要使用服务工作者,您首先需要在项目的根目录下创建一个名为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位置的自定义服务工作者,并使workbox注入一些代码:预缓存清单。这是一个.js文件,其中包含对编译后的静态资源的引用列表,通常命名为self.__precacheManifest。您必须以生产模式构建应用程序,以确保这一点。
由于在生产模式下构建时由workbox自动生成,预缓存清单对于缓存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`);
}

您可以在同一个文件中继续正常编写服务工作者,可以使用基本服务工作者 APIWorkbox 的 API。当然,不要犹豫将这两种方法结合起来。

希望对您有所帮助!


7
PWA插件的默认workboxPluginModeGenerateSW,因此您实际上不需要在公共目录中创建SW文件,因为workbox会代替您完成这个过程。同样重要的是要了解,虽然确实_registerServiceWorker.js文件只是注册服务工作者,但是vue-cli的PWA插件实际上(默认情况下)也会为您创建一个SW文件,在构建生产时,默认地成功缓存整个应用以供离线使用。 - kano
2
不错。 vue.config.js 起了作用,现在它可以正常运行了。只有一个问题:为什么我们需要额外的 vue.config.js 文件,难道它不是已经在 "register()" 中加载了吗?就像...模板没有制作那个额外的文件,但为什么呢? - Fusseldieb

48

除了上面的回答,我还编写了一个小指南,介绍如何进一步添加一些功能到自定义 service-worker 中,使用上述设置。您可以在这里找到它。

记住以下四个主要事项:

  1. vue.config.js 中配置 Workbox 为 InjectManifest 模式,并将 swSrc 键指向位于 /src 中的自定义服务工作者文件。
  2. 在该自定义服务工作者中,某些行将自动添加到构建过程中,以导入 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文件发送消息:

  4. ...
    updated(registration) {
      console.log("New content is available; please refresh.");
      let worker = registration.waiting
      worker.postMessage({action: 'skipWaiting'})
    },
    ...
    
  5. 订阅service-worker.js文件中的消息,并根据需要采取行动:

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

希望这对某人有所帮助。


非常有用和不错的文章!对我来说效果很好。也许cli-plugin-pwa很快就会将这些额外功能(用户提示、skipWaiting等)作为更简单的GenerateSW的一部分添加进去。在那之前,这正是我所需要的。 - Derek Williams
8
我已经到处寻找完整的信息,但这是我唯一找到它的地方。如果你要编写自己的Service Worker,谷歌开发指南会给出完整的信息,但Vue PWA插件默认为您构建它。Vue PWA插件的文档并不是非常有用。register-service-worker npm模块只提供了基本的钩子,但默认情况下不监听消息。因此,这非常有帮助,因为它将它们全部绑在一起。 - John Smith
如果使用workbox版本v4.1.0或更高版本的generateSW模式,则在生成的service-worker.js中已经存在self.addEventListener('message', (event) => { if (event.data && event.data.type === 'SKIP_WAITING') { self.skipWaiting(); } }); - Allan Chain

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接