You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue.js PWA中运行的Service Worker无法接收消息及路径问题

VueJS PWA Service Worker配置问题

问题背景

首次开发VueJS PWA,已完成基础Service Worker配置:Service Worker已激活运行,应用可正常安装,但存在两个问题:

1. 核心问题

使用Chrome开发者工具推送消息时,消息无法送达Service Worker;点击更新按钮无响应。仅极少数修改代码后刷新浏览器的场景下,调试断点才可能触发,无法确定具体原因。

2. 次要问题

service-worker-dev.js存放于src文件夹时,虽会被复制并修改至dist文件夹,但浏览器无法加载该文件;移至public文件夹后才能正常访问。


相关配置代码

vue.config.js

module.exports = {
  transpileDependencies: [
    'vuetify'
  ],
  pwa: {
    name: "MyWebApp",
    themeColor: "#42b983",
    msTileColor: "#42b983",
    appleMobileWebAppCache: "yes",
    favicon32: 'img/icons/favicon-32x32.png',
    favicon16: 'img/icons/favicon-16x16.png',
    appleTouchIcon: 'img/icons/apple-touch-icon-152x152.png',
    maskIcon: 'img/icons/safari-pinned-tab.svg',
    msTileImage: 'img/icons/msapplication-icon-144x144.png',
    manifestOptions: {
      name: "MyWebApp",
      short_name: "MyWebApp",
      background_color: "#42b983",
      theme_color: "#4DBA87",
      display: "standalone",
      start_url: "."
    },
    workboxPluginMode: "InjectManifest",
    workboxOptions: {
      swSrc: "src/service-worker-dev.js"
    }
  }
}

main.js

import Vue from 'vue'
import VueRouter from 'vue-router'

Vue.use(VueRouter)

import Home from './components/Home.vue'
import Contact from './components/Contact.vue'

import App from './App.vue'
import vuetify from './plugins/vuetify'
import "./registerServiceWorker";

const router = new VueRouter({
  mode: 'history',
  base: __dirname,
  routes: [
    { path: '/', component: Home },
    { path: '/:userId/:commentId', component: Home },
    { path: '/contact', component: Contact },
  ]
});

Vue.config.productionTip = false;

new Vue({
  router,
  vuetify,
  render: h => h(App),
}).$mount('#app')

registerServiceWorker.js

/* eslint-disable no-console */

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

register(`./service-worker-dev.js`, {
    ready() {
        console.log(
            'App is being served from cache by a service worker.\n'
        );
    },
    registered() {
        console.log('Service worker has been registered.');
    },
    cached() {
        console.log('Content has been cached for offline use.');
    },
    updatefound() {
        console.log('New content is downloading.');
    },
    updated(registration) {
        console.log('New content is available; please refresh.');
        let confirmationResult = confirm("New content found! Do you want to reload the app?");
        if (confirmationResult)
            registration.waiting.postMessage({ action: "skipWaiting" });
    },
    offline() {
        console.log('No internet connection found. App is running in offline mode.');
    },
    error(error) {
        console.error('Error during service worker registration:', error);
    },
    message(message) {
        console.log(message);
    }
});

let refreshing;
navigator.serviceWorker.addEventListener("controllerchange", () => {
    if (refreshing) return;
    window.location.reload();
    refreshing = true;
});

navigator.serviceWorker.addEventListener("message", (e) => {
    debugger;
    console.log(e);
});

service-worker-dev.js

workbox.core.setCacheNameDetails({ prefix: "MyWebApp" });

self.__precacheManifest = [].concat(self.__precacheManifest || []);
workbox.precaching.precacheAndRoute(self.__precacheManifest, {});

// install new service worker when ok, then reload page.
self.addEventListener("message", async msg => {
  debugger;
  console.log("message", msg);
  const clients = await self.clients.matchAll({ type: 'window' });
  for (const client of clients) {
    debugger;
    client.postMessage(msg);
  }

  if (msg.data.action == 'skipWaiting') {
    self.skipWaiting()
  }
});

self.addEventListener('fetch', function (event) {
  event.respondWith(async function () {
    try {
      var res = await fetch(event.request);
      var cache = await caches.open('cache');
      cache.put(event.request.url, res.clone());
      return res;
    }
    catch (error) {
      return caches.match(event.request);
    }
  }());
});

更新后的registerServiceWorker.js

/* eslint-disable no-console */

import { register } from 'register-service-worker'
//TODO: Replace with right service worker
register(`./service-worker-dev.js`, {
    ready() {
        console.log(
            'App is being served from cache by a service worker.\n'
        );
    },
    registered() {
        console.log('Service worker has been registered.');
    },
    cached() {
        console.log('Content has been cached for offline use.');
    },
    updatefound() {
        console.log('New content is downloading.');
    },
    updated(registration) {
        console.log('New content is available; please refresh.');
        let confirmationResult = confirm("New content found! Do you want to reload the app?");
        if (confirmationResult)
            registration.waiting.postMessage({ action: "skipWaiting" });
    },
    offline() {
        console.log('No internet connection found. App is running in offline mode.');
    },
    error(error) {
        console.error('Error during service worker registration:', error);
    },
    message(message) {
        console.log(message);
    }
});

let refreshing;
navigator.serviceWorker.addEventListener("controllerchange", () => {
    if (refreshing) return;
    window.location.reload();
    refreshing = true;
});

navigator.serviceWorker.addEventListener("message", (e) => {
    debugger;
    console.log(e);
});

解决方案

核心问题解决办法

  1. 修正Service Worker注册路径
    使用InjectManifest模式时,Workbox会把src/service-worker-dev.js处理后输出到dist根目录,默认文件名是service-worker.js,而非原文件名。因此需要把registerServiceWorker.js里的注册路径改成./service-worker.js,否则浏览器会找不到正确的SW文件,导致消息无法送达。

  2. 添加Push事件监听
    Chrome开发者工具推送消息需要Service Worker注册push事件才能接收,当前代码缺少该逻辑。在service-worker-dev.js中添加:

    self.addEventListener('push', (event) => {
      const content = event.data?.text() || '新消息通知';
      event.waitUntil(
        self.registration.showNotification('MyWebApp', {
          body: content,
          icon: './img/icons/apple-touch-icon-152x152.png'
        })
      );
    });
    
  3. 修复更新无响应问题

    • 关闭Chrome DevTools中「Application > Service Workers」的「Update on reload」选项,该选项会导致SW频繁重启,干扰更新逻辑。
    • 手动触发更新:可以在Vue组件中添加更新按钮,绑定以下逻辑:
      methods: {
        async checkForUpdate() {
          const reg = await navigator.serviceWorker.getRegistration();
          if (reg) reg.update();
        }
      }
      
    • 替换自定义fetch缓存逻辑:当前的fetch事件可能和Workbox预缓存冲突,改用Workbox官方策略更可靠:
      // 替换service-worker-dev.js中的fetch事件
      workbox.routing.registerRoute(
        ({url}) => !url.pathname.includes('/api'), // 根据需求排除API请求
        new workbox.strategies.StaleWhileRevalidate({
          cacheName: 'MyWebApp-runtime-cache'
        })
      );
      

次要问题解决办法

无需将service-worker-dev.js移到public文件夹,只需按核心问题第一条修正注册路径为./service-worker.js即可。Workbox会自动将处理后的SW文件输出到dist根目录,浏览器就能正常加载。


内容的提问来源于stack exchange,提问作者FrenchCalculator

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 22:20:27