PWA系列 - Workbox插件InjectManifest

2,461 阅读3分钟

PWA系列

PWA系列 - 我所知道的 Service Worker

PWA系列 - Workbox插件GenerateSW

PWA系列 - Workbox插件InjectManifest

不论是GenerateSW或是InjectManifest都是对PWA系列 - 我所知道的 Service Worker原生配置的封装,所以首先应该弄懂service workder原始配置

目录

  • manifest可安装
  • workbox-webpack-plugin 提供webpack插件InjectManifest
  • workbox-window 提供给注册sw的window部分封装
  • workbox-core 提供控制函数
  • workbox-precaching 提供预缓存文件
  • workbox-routing 提供自定义路由注册函数
  • workbox-strategies 提供5中缓存策略对象
  • workbox-cacheable-response 提供响应对象
  • workbox-expiration 提供缓存过期对象

装包

npm i workbox-webpack-plugin copy-webpack-plugin@6.3.2 -D
npm i workbox-core workbox-cacheable-response workbox-expiration workbox-precaching workbox-routing workbox-strategies workbox-window

manifest可安装

首先解决最简单的,pwa可以像app一样安装在桌面,增加mainfest.json文件即可

在src下放favicon.ico、logo192.png、logo512.png、manifest.json文件

vue.config.js 配置

const WorkboxWebpackPlugin = require("workbox-webpack-plugin");
const CopyWebpackPlugin = require("copy-webpack-plugin");
module.exports = {
  configureWebpack: () => ({
    plugins: [
      new CopyWebpackPlugin({
        patterns: [
          { from: "./src/favicon.ico", to: "" },
          { from: "./src/logo192.png", to: "" },
          { from: "./src/logo512.png", to: "" },
          { from: "./src/manifest.json", to: "" },
        ],
      }),
      new WorkboxWebpackPlugin.InjectManifest({
        swSrc: "./src/sw.js",
        swDest: "sw.js",
      }),
    ],
  }),
};

manifest.json 配置

{
	"short_name": "PWA",
	"name": "PWA Example",
	"icons": [
		{
			"src": "favicon.ico",
			"sizes": "64x64 32x32 24x24 16x16",
			"type": "image/x-icon"
		},
		{
			"src": "logo192.png",
			"type": "image/png",
			"sizes": "192x192"
		},
		{
			"src": "logo512.png",
			"type": "image/png",
			"sizes": "512x512"
		}
	],
	"start_url": ".",
	"display": "standalone",
	"theme_color": "#e50914",
	"background_color": "#221f1f"
}

src目录下增加sw.js

可以看到导入了workbox-coreworkbox-precaching包,作用在第一篇功能一样代替self.clients.claim()和预请求资源


import { clientsClaim } from "workbox-core";
import { precacheAndRoute } from "workbox-precaching";

// 放在顶部,sw获得控制权,不然是下次打开页面获得
clientsClaim();
// 跳过等待
self.skipWaiting();
// 预请求资源,__WB_MANIFEST变量会注册webpack打包的所有项目资源文件
precacheAndRoute(self.__WB_MANIFEST);

html文件增加head头

<link rel="manifest" href="/manifest.json" />

main.js入口文件注册sw.js

导入了workbox-window就是代替navigator.serviceWorker.register("/sw.js");这个写法

import { Workbox } from "workbox-window";

if ("serviceWorker" in navigator) {
    const wb = new Workbox("sw.js");
    // wb.addEventListener("installed", (event) => {
    //   if (event.isUpdate) {
    //     if (confirm("检查有新版,是否更新最新?")) {
    //       window.location.reload();
    //     }
    //   }
    // });
    wb.register();
}

效果

点击便可安装到桌面 image.png

image.png

扩展说明-sw.js增加外部路由规则

缓存逻辑在第一篇中说明了,可查看PWA系列 - 我所知道的 Service Worker,非预请求资源,可以增加自定义路由做缓存

根据域名加规则

fonts.googleapis.com 下的请求,采用StaleWhileRevalidate方式缓存到google-fonts-stylesheets这个名下


import { registerRoute } from "workbox-routing";
import { StaleWhileRevalidate, CacheFirst } from "workbox-strategies";

registerRoute(
  ({ url }) => url.origin === "https://fonts.googleapis.com",
  new StaleWhileRevalidate({
    cacheName: "google-fonts-stylesheets",
  })
);

字体域名和过期时间

fonts.gstatic.com 下的请求采用CacheFirst方式缓存到google-fonts-webfonts名下

  • 只缓存200状态码的数据
  • 存60天,30个
import { ExpirationPlugin } from "workbox-expiration";
import { CacheableResponsePlugin } from "workbox-cacheable-response";

registerRoute(
  ({ url }) => url.origin === "https://fonts.gstatic.com",
  new CacheFirst({
    cacheName: "google-fonts-webfonts",
    plugins: [
      new CacheableResponsePlugin({
        statuses: [0, 200],
      }),
      new ExpirationPlugin({
        maxAgeSeconds: 60 * 60 * 24 * 365,// 60天
        maxEntries: 30,
      }),
    ],
  })
);

api接口缓存

CacheableResponsePlugin方式,如果接口通,则返回网络数据,如果接口不同,则返回缓存数据

import { StaleWhileRevalidate } from "workbox-strategies";
import { CacheableResponsePlugin } from "workbox-cacheable-response";
import { ExpirationPlugin } from "workbox-expiration";

registerRoute(
  ({ url }) =>
    url.origin === "https://api.themoviedb.org" &&
    url.pathname.startsWith("/3/discover/tv"),
  new StaleWhileRevalidate({
    cacheName: "movie-api-response",
    plugins: [
      new CacheableResponsePlugin({
        statuses: [0, 200],
      }),
      new ExpirationPlugin({ maxEntries: 1 }), // Will cache maximum 1 requests.
    ],
  })
);

图片缓存

import { CacheFirst } from "workbox-strategies";
import { CacheableResponsePlugin } from "workbox-cacheable-response";
import { ExpirationPlugin } from "workbox-expiration";

registerRoute(
  ({ request }) => request.destination === "image",
  new CacheFirst({
    cacheName: "images",
    plugins: [
      new CacheableResponsePlugin({
        statuses: [0, 200],
      }),
      new ExpirationPlugin({
        maxEntries: 60,
        maxAgeSeconds: 30 * 24 * 60 * 60, // 30 Days
      }),
    ],
  })
);

js和css文件缓存

import { registerRoute } from "workbox-routing";
import { StaleWhileRevalidate } from "workbox-strategies";

registerRoute(
  ({ request }) =>
    request.destination === "script" || request.destination === "style",
  new StaleWhileRevalidate({
    cacheName: "static-resources",
  })
);