‌Service Worker‌渐进式Web应用(PWA)

‌Service Worker‌是一种运行在浏览器后台的脚本,主要功能包括提供离线支持、缓存资源、推送通知等。它是渐进式Web应用(PWA)的关键技术之一,旨在提高Web应用的性能和用户体验‌

1.使用场景和优势

Service Worker的主要用途包括:

  1. ‌离线缓存‌:可以缓存静态资源,使得应用在离线时也能访问。 ‌
  2. 网络请求拦截和处理‌:可以拦截并处理网络请求,例如伪造响应、转发请求等。
  3. 消息推送‌:可以向客户端推送消息。 ‌执行耗时任务‌:如大量的数据运算。
  4. ‌执行耗时任务‌:如大量的数据运算。

2.创建serviceWorker.js

在public下新建文件:

const CACHE_VERSION = new Date().toISOString() // 或者一个静态版本号,比如 "v2"
const CACHE_NAME = `react-pwa-cache-${CACHE_VERSION}`
const urlsToCache = ["/", "/index.html", "/static/favicon.svg", "/manifest.json"]

// 安装阶段:预缓存关键静态资源
self.addEventListener("install", event => {
  self.skipWaiting() // 跳过等待,立即激活新的 Service Worker
  event.waitUntil(
    caches.open(CACHE_NAME).then(cache => {
      console.log("Opened cache")
      return cache.addAll(urlsToCache)
    })
  )
})

// 抓取阶段:动态缓存新的请求资源
self.addEventListener("fetch", event => {
  // 跳过 chrome-extension:// 请求
  if (event.request.url.startsWith("chrome-extension://")) {
    return
  }
  // 跳过非 GET 请求
  if (event.request.method !== "GET") {
    return
  }
  event.respondWith(
    caches.match(event.request).then(cachedResponse => {
      const fetchPromise = fetch(event.request).then(response => {
        // 确保响应有效后缓存资源
        if (!response || response.status !== 200 || response.type !== "basic") {
          return response
        }
        // 更新缓存
        const clonedResponse = response.clone()
        caches.open(CACHE_NAME).then(cache => {
          cache.put(event.request, clonedResponse)
        })
        return response
      })

      return cachedResponse || fetchPromise
    })
  )
})

// 激活阶段:清除旧缓存并立即启用新的 Service Worker。
self.addEventListener("activate", event => {
  event.waitUntil(
    caches.keys().then(cacheNames => {
      return Promise.all(
        cacheNames.map(cacheName => {
          if (cacheName !== CACHE_NAME) {
            return caches.delete(cacheName) // 删除旧缓存
          }
        })
      )
    })
  )
  self.clients.claim() // 让新的 Service Worker 生效
})

//通过 message 事件来处理强制更新:
self.addEventListener("message", event => {
  if (event.data === "SKIP_WAITING") {
    self.skipWaiting()
  }
})

3.注册Service Worker

在入口文件,启动函数里进行注册:

const SERVICEWORKER_URL = process.env.NODE_ENV === "production" ? "/serviceWorker.js" : "/serviceWorker.js"
console.log("环境变量:", process.env.NODE_ENV, SERVICEWORKER_URL)
// 注册 Service Worker
start(() => {
  if ("serviceWorker" in navigator) {
    window.addEventListener("load", () => {
      navigator.serviceWorker
        .register(SERVICEWORKER_URL)
        .then(registration => {
          console.log("ServiceWorker registration successful with scope: ", registration.scope)

          // 如果有等待中的新的 Service Worker,发送 SKIP_WAITING 消息
          if (registration.waiting) {
            registration.waiting.postMessage("SKIP_WAITING")
          }

          // 监听 Service Worker 状态变化
          registration.onupdatefound = () => {
            const installingWorker = registration.installing
            if (installingWorker) {
              // 监听安装过程的状态变化
              installingWorker.onstatechange = () => {
                if (installingWorker.state === "installed" && navigator.serviceWorker.controller) {
                  // 新的 Service Worker 安装完成并且页面已由旧的 Service Worker 控制
                  installingWorker.postMessage("SKIP_WAITING")
                }
              }
            }
          }
        })
        .catch(error => {
          console.log("ServiceWorker registration failed: ", error)
        })
    })
  }
})

4.webpack配置

const WorkboxWebpackPlugin = require("workbox-webpack-plugin")
// 在plugins插件中引入
 new WorkboxWebpackPlugin.GenerateSW({
          clientsClaim: true,
          exclude: [/\.map$/, /asset-manifest\.json$/],
          navigateFallback: paths.publicUrlOrPath + "index.html",
          navigateFallbackBlacklist: [
            new RegExp("^/_"), // 排除以 /_ 开头的 URL
            new RegExp("/[^/?]+\\.[^/]+$") // 排除资源文件
          ],
          skipWaiting: true,
          runtimeCaching: [
            {
              urlPattern: /\.(?:png|jpg|jpeg|svg|gif|css|js|html)$/,
              handler: "CacheFirst",
              options: {
                cacheName: "assets-cache",
                expiration: {
                  maxEntries: 50,
                  maxAgeSeconds: 1 * 24 * 60 * 60 // 缓存1天
                }
              }
            },
            {
              urlPattern: /\/api\//,
              handler: "NetworkFirst",
              options: {
                cacheName: "api-cache",
                networkTimeoutSeconds: 10,
                expiration: {
                  maxEntries: 10
                }
              }
            }
          ]
        }),

5.验证流程

查看缓存数据
  1. 打开开发者工具 >应用 >存储空间。
  2. 如需查看可用的缓存,请展开 Cache Storage。

在这里插入图片描述

  1. 查看缓存数据

点击缓存以查看其内容。
在这里插入图片描述

  1. 点击资源即可在表格下方的部分中查看其 HTTP 标头。

在这里插入图片描述

  1. 打开预览标签页以查看资源的内容。

在这里插入图片描述

刷新资源
  1. 查看缓存的数据。
  2. 选择要刷新的资源。开发者工具以蓝色突出显示 已选择。

选择资源。

点击 Refresh 刷新。
过滤资源
  1. 查看缓存的数据。
  2. 使用按路径过滤文本框,以过滤出与指定过滤器的路径不匹配的所有资源。
    在这里插入图片描述
删除一项资源
  1. 查看缓存的数
  2. 点击要删除的资源。开发者工具会以蓝色突出显示它 已选择

在这里插入图片描述

删除所有缓存数据
  1. 打开应用 >存储空间。
  2. 在缓存部分,确保已启用 复选框。 缓存存储。
  3. 点击清除网站数据

在这里插入图片描述

欢迎转载请说明来源即可
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

前端加油站

你遇到的坑将由我来踩

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值