为什么捐赠
API 浏览器
联系站长
Quasar CLI with Vite - @quasar/app-vite
配置 PWA

Service Worker

给一个 Quasar 项目添加 PWA 模式后会自动创建一个 /src-pwa 目录,其中包含以下 PWA 相关的文件:

register-service-worker.js
# (或 .ts)管理 service worker 的 UI 代码
manifest.json
# PWA 的 manifest 配置清单文件
custom-service-worker.js
# (或 .ts)可选的自定义 service worker 文件(仅在 injectManifest 模式中)

您可以随意修改这些文件,但要注意以下事情:

  1. register-service-worker.js 会被自动导入到应用中(就像 /src 中的文件一样)。它会注册 service worker(由 Workbox 创建,或者自定义,取决于 workbox 插件模式 – quasar.config file > pwa > workboxPluginMode 配置),您可以在此监听 service worker 的事件。可以使用 ES6 的代码。
  2. 如果 workbox 插件模式被设置为 “injectManifest”(quasar.config file > pwa > workboxMode: ‘injectManifest’),那么将会使用 custom-service-worker.js 作为 service-worker 文件,否则 Quasar 和 Workbox 会创建一个 service-worker 文件。
  3. 仅在生产构建上运行 Lighthouse 测试才有意义。

TIP

阅读更多关于 register-service-worker.js 以及如何与 Service Worker 交互的信息,请前往 处理 Service Worker 文档页面。

quasar.config file

在此可以配置 Workbox 的行为,也可以调整 manifest.json。

pwa: {
  workboxMode?: "GenerateSW" | "InjectManifest";

  /**
   * 生成的 service worker 文件名(必须以 .js 结尾)
   * @default sw.js
   */
  swFilename?: string;

  /**
   * 浏览器使用的 PWA manifest 文件名
   * @default manifest.json
   */
  manifestFilename?: string;

  /**
   * 如果需要在构建时动态修改 /src-pwa/manifest.json,
   * 可以在此方法中实现。
   */
  extendManifestJson?: (json: PwaManifestOptions) => void;

  /**
   * PWA manifest 标签是否需要 crossorigin 认证?
   * @default false
   */
  useCredentialsForManifestTag?: boolean;

  /**
   * 是否自动注入 PWA meta 标签?
   * 如果使用函数形式,返回值为 HTML 标签的单个字符串。
   * @default true
   */
  injectPwaMetaTags?: boolean | ((injectParam: InjectPwaMetaTagsParams) => string);

  /**
   * 扩展用于自定义 service worker 的 Esbuild 配置
   * (仅在 workboxMode: 'InjectManifest' 模式下使用)
   */
  extendPWACustomSWConf?: (config: EsbuildConfiguration) => void;

  /**
   * 扩展/配置 Workbox GenerateSW 选项
   */
  extendGenerateSWOptions?: (config: GenerateSWOptions) => void;

  /**
   * 扩展/配置 Workbox InjectManifest 选项
   */
  extendInjectManifestOptions?: (config: InjectManifestOptions) => void;
}

sourceFiles: {
  pwaRegisterServiceWorker: 'src-pwa/register-service-worker',
  pwaServiceWorker: 'src-pwa/custom-service-worker',
  pwaManifestFile: 'src-pwa/manifest.json',
}

如果您希望修改 /src 中 UI 代码的 Vite 配置:

/quasar.config file

export default defineConfig((ctx) => {
  return {
    build: {
      extendViteConf(viteConf) {
        if (ctx.mode.pwa) {
          // 对 viteConf 进行操作
          // 或者返回一个对象来深度合并到当前的 viteConf
        }
      },
    },
  };
});

更多信息:Workbox

在 index.html 中添加自定义 meta 标签

Quasar CLI 会动态地在 index.html 中添加 PWA 相关的 meta 标签。如果您希望自定义这些标签,首先需要在 /quasar.config 文件中禁用此行为:

/quasar.config file

pwa: {
  injectPwaMetaTags: false;
}

然后,编辑 /index.html 文件。下面是 Quasar CLI 实际动态注入的 meta 标签:

<head>
  <% if (ctx.mode.pwa) { %>
  <meta name="theme-color" content="<%= pwaManifest.theme_color %>" />
  <link rel="mask-icon" href="icons/safari-pinned-tab.svg" color="<%= pwaManifest.theme_color %>" />
  <meta name="mobile-web-app-capable" content="yes" />
  <meta name="apple-mobile-web-app-status-bar-style" content="default" />
  <meta name="msapplication-TileImage" content="icons/ms-icon-144x144.png" />
  <meta name="msapplication-TileColor" content="#000000" />
  <meta name="apple-mobile-web-app-title" content="<%= pwaManifest.name %>" />
  <link rel="apple-touch-icon" href="icons/apple-icon-120x120.png" />
  <link rel="apple-touch-icon" sizes="152x152" href="icons/apple-icon-152x152.png" />
  <link rel="apple-touch-icon" sizes="167x167" href="icons/apple-icon-167x167.png" />
  <link rel="apple-touch-icon" sizes="180x180" href="icons/apple-icon-180x180.png" />
  <% } %>
</head>

注意,您可以通过上面的 pwaManifest 来访问 PWA 的 manifest 配置。

或者,您也可以为 injectPwaMetaTags 分配一个函数,如下所示:

/quasar.config file

pwa: {
  injectPwaMetaTags ({ pwaManifest, publicPath }) {
    return `<meta name="mobile-web-app-capable" content="yes">`
      + `<meta name="apple-mobile-web-app-status-bar-style" content="default">`
  }
}

选择 Workbox 模式

Workbox 有两种运行模式:generateSW(默认)和 injectManifest

通过 /quasar.config 文件设置您想要的模式:

/quasar.config file

pwa: {
  workboxMode: 'generateSW',
  extendGenerateSWOptions (cfg) {
    // 配置 generateSW 模式下的选项
  }
}

pwa: {
  workboxMode: 'injectManifest',
  extendInjectManifestOptions (cfg) {
    // 配置 injectManifest 模式下的选项
  }
}

generateSW

何时使用 generateSW:

  • 您希望预缓存文件。
  • 您有简单的运行时配置需求(例如:该配置允许您定义路由和策略)。

何时不使用 generateSW:

  • 您希望使用其他的 Service Worker 特性(例如 Web Push 推送)。
  • 您希望导入其他脚本或添加其他逻辑。

TIP

关于此模式有哪些可用的 workboxOptions,请参考 Workbox 网站

InjectManifest

何时使用 InjectManifest:

  • 您希望对 service worker 有更多控制权。
  • 您希望预缓存文件。
  • 在路由方面,您有更复杂的需求。
  • 您希望将 service worker 与其他 API 一起使用(例如 Web Push 推送)。

何时不使用 InjectManifest:

  • 您希望以最简单的方式将 service worker 添加到您的站点。

提示

  • 如果使用此模式,需要自行编写 service worker 文件(/src-pwa/custom-service-worker.js)。
  • 关于此模式有哪些可用的 workboxOptions,请参考 Workbox 网站

下面的代码片段是自定义 service worker(/src-pwa/custom-service-worker.js)的默认代码,它模仿了 generateSW 模式的行为:

/*
 * 此文件(将作为您的 service worker)
 * 只有当 quasar.config file > pwa > workboxMode
 * 被设置为 "injectManifest" 时才会被构建系统启用
 */

import { clientsClaim } from "workbox-core";
import {
  precacheAndRoute,
  cleanupOutdatedCaches,
  createHandlerBoundToURL,
} from "workbox-precaching";
import { registerRoute, NavigationRoute } from "workbox-routing";

self.skipWaiting();
clientsClaim();

// 与预缓存注入一起使用
precacheAndRoute(self.__WB_MANIFEST);

cleanupOutdatedCaches();

// 非 SSR 回退到 index.html
// 生产环境下 SSR 回退到 offline.html(开发环境除外)
if (process.env.PROD) {
  registerRoute(
    new NavigationRoute(createHandlerBoundToURL(process.env.PWA_FALLBACK_HTML), {
      denylist: [new RegExp(process.env.PWA_SERVICE_WORKER_REGEX), /workbox-(.)*\.js$/],
    }),
  );
}

配置 Manifest 文件

Manifest 文件位于 /src-pwa/manifest.json,您可以自由编辑它。

如果需要在构建时动态修改它,可以通过编辑 /quasar.config 文件来实现:

/quasar.config file

pwa: {
  extendManifestJson (json) {
    // 在此直接修改 json 内容
  }
}

请在开始之前阅读 manifest 配置

WARNING

不需要编辑 index.html 文件(从 /index.html 生成)来链接 manifest 文件。Quasar CLI 会帮您处理好这些事情。

TIP

如果您的 PWA 需要 basic auth 认证或者需要一个 Authorization 请求头,请将 quasar.config file > pwa > useCredentialsForManifestTag 设置为 true,以便在 manifest.json 的 meta 标签中包含 crossorigin="use-credentials"

PWA Checklist

更多信息:PWA Checklist

WARNING

不要在开发构建中运行 Lighthouse,因为在这个阶段,代码故意没有进行优化,并且嵌入了源代码映射(以及其他许多内容)。更多信息请前往测试与审计页面。

重新加载 & 自动更新

对于不想在 service worker 更新时手动重新加载页面、并且使用了默认的 generateSW workbox 模式的用户,Quasar CLI 已经配置了 Workbox 使其立即激活。如果您需要禁用此行为:

/quasar.config file

pwa: {
  extendGenerateSWOptions (cfg) {
    cfg.skipWaiting = false
    cfg.clientsClaim = false
  }
}

文件名哈希的注意事项

由于 Rolldown 构建资源的方式(通过 Vite),当您修改了任何脚本源文件(.js),这也会改变(几乎)所有 .js 文件的哈希部分(例如 assets/index.454d87bd.js 中的 454d87bd)。这意味着 service worker 文件中所有资源的版本号都会发生变化,PWA 更新时将会重新下载所有资源。这既浪费带宽,又延长了 PWA 的更新时间!

默认情况下,Vite 构建的所有文件名都包含哈希部分。但如果您希望文件名不包含哈希部分,需要编辑 /quasar.config 文件:

/quasar.config file

build: {
  useFilenameHashes: false; // 默认为 true
}

当禁用了文件名哈希后,建议同时确保您的 Web 服务器的缓存设置尽可能短(尽可能低的缓存时间),以确保不能使用 PWA 功能的客户端也能获得一致的资源交付。