为什么捐赠
API 浏览器
升级指南
NEW!
创建新项目
quasar.config 配置文件
从 Webpack 项目转换
浏览器兼容性
TypeScript 支持
目录结构
命令列表
CSS 预处理器
使用 VueRouter 进行页面路由
懒加载 - 代码分割
资源处理
Boot 文件
预取特性
API 代理
配置 Vite
处理 import.meta.env
使用 Pinia 管理状态
代码检查与格式化
测试与审计
开发移动应用
Ajax 请求
开放开发服务器到公网
联系站长
Quasar CLI with Vite - @quasar/app-vite
PWA 与 TypeScript

当你在一个 TypeScript 项目中添加 PWA 模式(quasar mode add pwa)时,Quasar 会将 Service Worker 脚手架到 /src-pwa/sw/ 目录中,并配备独立的 tsconfig.json,使 WebWorker 上下文的类型检查独立于应用的其余部分。

/src-pwa/sw/tsconfig.json 是一个指向 .quasar/ 中生成配置的简洁引用:

/src-pwa/sw/tsconfig.json

{
  "extends": "../../.quasar/tsconfig.pwa-sw.json"
}

生成的 .quasar/tsconfig.pwa-sw.json 处理了 WebWorker lib 替换,并将 include/exclude 限定到 SW 目录。如需自定义,建议在 quasar.config.ts 中使用 pwa.extendPWASwTsConfig 钩子,而不是直接编辑 src-pwa/sw/tsconfig.json

/quasar.config.ts

pwa: {
  /**
   * Extend the generated `.quasar/tsconfig.pwa-sw.json` file.
   *
   * NOT async! Can directly modify the "config" parameter or
   * return a new one that will be merged with the default one.
   */
  extendPWASwTsConfig (tsConfig) {
    tsConfig.compilerOptions!.lib!.push('WebWorker.AsyncIterable')
  }
}

register-sw.ts 保留在 /src-pwa/ 根目录,因为它在主线程中运行,会随 /src 一起通过 Vite 打包到应用中。/src-pwa/sw/ 内的所有内容则由 Rolldown 单独构建,运行在 Service Worker 上下文中。你可以在 sw/ 中添加更多仅用于 SW 的模块,并从 custom-sw.ts 中导入它们;主线程模块则直接放在 src-pwa/ 下,或从 /src 导入即可。

类型检查的工作原理

TypeScript 在从项目根目录运行 tsc/vue-tsc不会识别嵌套的 tsconfig.json 文件,它会将根编译器选项应用于 include 中的所有文件。为了避免 Service Worker 代码出现类型错误(例如在 DOM lib 下 ServiceWorkerGlobalScope.skipWaiting 不存在),Quasar CLI 在安装 PWA 模式时会在 .quasar/tsconfig.json > excludes 中添加 /src-pwa/sw/

IDE 的语言服务器仍然会将 /src-pwa/sw/tsconfig.json 应用于该目录内的文件(TS 将嵌套的 tsconfig 视为独立项目),所以你依然能在那里获得正确的自动补全和内联诊断。

(ESLint) 在 dev/build 中对 Service Worker 进行类型检查

由于 SW 被排除在根项目之外,运行 vue-tscvite-plugin-checker 实例不会检查它。要在 quasar dev/quasar build 时获得内联的 SW 诊断信息,请在 quasar.config.ts 中为 vite-plugin-checker 配置添加一个 typescript 条目:

/quasar.config.ts

build: {
  vitePlugins: [
    [
      'vite-plugin-checker',
      {
        vueTsc: true,
        typescript: {
          tsconfigPath: './src-pwa/sw/tsconfig.json'
        }
        // ...
      },
      { server: false }
    ]
  ]
}

package.json 中添加一个 typecheck 脚本也是常见做法:

/package.json

{
  "scripts": {
    "typecheck": "vue-tsc --noEmit && tsc -p src-pwa/sw/tsconfig.json --noEmit"
  }
}

将现有 PWA 目录迁移到 TypeScript

如果你在项目还是 JavaScript 时添加了 PWA 模式,后来才切换到 TypeScript,/src-pwa/ 目录不会被重新脚手架。你需要手动转换:

  1. 重命名 /src-pwa/register-sw.js -> /src-pwa/register-sw.ts
  2. 创建 /src-pwa/sw/ 并将 /src-pwa/custom-sw.js 移动到 /src-pwa/sw/custom-sw.ts(同时修改扩展名)。
  3. 创建 /src-pwa/sw/tsconfig.json,内容如上所示。
  4. custom-sw.ts 顶部添加 SW 类型声明(参见下方"默认 Service Worker 内容"),并进行其他 TS 相关的代码调整。
  5. (可选)按上述方式配置 vite-plugin-checkertypescript 条目和/或添加 typecheck 脚本。

默认 Service Worker 内容

/src-pwa/sw/custom-sw.ts

/*
 * This file (which will be your service worker)
 * is picked up by the build system ONLY if
 * quasar.config file > pwa > workboxMode is set to "InjectManifest"
 */

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

declare const self: ServiceWorkerGlobalScope & typeof globalThis

void self.skipWaiting()
clientsClaim()

// Use with precache injection
precacheAndRoute(self.__WB_MANIFEST)

cleanupOutdatedCaches()

if (import.meta.env.QUASAR_PROD) {
  // Non-SSR fallbacks to index.html
  // Production SSR fallbacks to offline.html (except for dev)
  registerRoute(
    new NavigationRoute(
      createHandlerBoundToURL(import.meta.env.QUASAR_PWA_FALLBACK_HTML),
      {
        denylist: [
          new RegExp(import.meta.env.QUASAR_PWA_SERVICE_WORKER_REGEX),
          /workbox-(.)*\.js$/
        ]
      }
    )
  )
}