# 调试 PWA

> 如何使用 Chrome DevTools 的 Application 面板（Manifest、Service workers、Cache storage）在开发过程中检查并排查 PWA 问题。

完成本指南后，你可以在 Chrome DevTools 的 **Application** 面板中读取 PWA 解析后的 manifest、说出 Chrome 看到的确切可安装性失败原因、强制更新 Service Worker、模拟离线，并检查或清空 Cache Storage 条目。该面板是 Chrome 自己的工具；Firefox 与 Safari 的开发者工具界面不同，本指南不涉及。

你需要在待测页面上打开 DevTools 的 Chrome。按 Command+Shift+P（macOS）或 Control+Shift+P（Windows、Linux、ChromeOS），输入 `application`，选择 **Show Application**；侧栏在 "Application" 下列出 **Manifest**、**Service workers** 与 **Storage**，在 "Storage" 下列出 **Cache storage**。

## 读取解析后的 manifest 与 Installability 结论

选择 **Manifest**。面板在 **App Manifest** 下显示 manifest URL，然后是 **Identity**、**Presentation** 与 **Icons** 区块，并渲染每个声明的图标。勾选 **Show only the minimum safe area for maskable icons** 会把每个图标裁到遮罩式启动器保留的区域，是发现画面贴边的最快方法。在 **Protocol Handlers** 下，**Test protocol** 按钮会打开一个带有已声明 scheme 的 URL，用来确认注册。只有 Chrome 发现问题时才会出现 **Installability** 区块，其中每一行都是 DevTools 前端中固定字符串之一。开发中最常见的几条是：

- `Page has no manifest <link> URL`
- `Manifest couldn't be fetched, is empty, or couldn't be parsed`
- `Manifest doesn't contain a 'name' or 'short_name' field`
- `Manifest 'start_url' isn't valid`
- `Manifest 'display' property must be one of 'standalone', 'fullscreen', or 'minimal-ui'`
- `Couldn't download a required icon from the manifest`
- `Page isn't served from a secure origin`

每条都点名了要修的 manifest 成员或服务器条件；页面满足标准后该区块就会消失。

## 在 Service workers 面板中控制 Service Worker

选择 **Service workers**。对作用域内的注册，面板会打印 **Source**（脚本 URL 与接收时间）、**Status**（`#N activated and is running`，附 **stop** 与 **start** 链接）以及 **Clients**。三个复选框在勾选期间改变 Chrome 对 worker 的处理方式：

| 控制项 | 效果 |
|---|---|
| **Offline** | 把页面置于与 Network 面板相同的离线模式 |
| **Update on reload** | 强制 Service Worker 在每次页面加载时更新 |
| **Bypass for network** | 每个请求都直接发往网络，忽略 fetch 处理器 |

**Update** 链接执行一次更新检查；**Unregister** 移除注册；**Push** 与 **Sync** 向 worker 分别派发一个 `push` 事件（默认载荷为 `Test push message from DevTools`）和一个 `sync` 事件。**Update Cycle** 表列出每个版本的 install、wait、activate 时间戳，能告诉你一个「不肯更新」的 worker 卡在哪个阶段。页面脚本仍应守护注册调用，让没有该 API 的浏览器正常加载页面：

```js
if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('/sw.js').then((registration) => {
    console.log('scope', registration.scope);
  });
} else {
  console.info('Service workers unavailable; running without offline support');
}
```

表中带有 `waiting` 的 worker 已安装但未控制页面，因为旧版本仍占有一个打开的客户端；关闭该来源的所有标签页，或勾选 **Update on reload** 让它激活。

## 检查并清空 Cache storage

在 **Storage** 下展开 **Cache storage**，每个 `caches.open()` 名称对应一个条目。选中一个即可列出缓存的请求及其响应状态、内容类型与大小；标为 opaque 的条目是未经 CORS 获取的跨域响应，Chrome 的指南指出 opaque 条目会影响其大小计入来源配额的方式。**Clear storage**（Application 区块顶部）一键注销 Service Worker 并删除缓存、IndexedDB 与本地存储，适合在测试轮次之间重置来源。

:::observed
Chrome 的 PWA 调试指南（developer.chrome.com，2026-10-03 读取）写道："Note that the first time you open a cache and add a resource to it, DevTools might not detect the change"，随后是 "Reload the page and you should see the cache"。因此，在 **Cache storage** 树里看起来什么都没做的 `cache.addAll()`，在保持树展开并刷新一次页面之前，不能当作 bug 的证据。
:::

## 重现离线启动

在 Service workers 面板勾选 **Offline**，然后刷新。fetch 处理器正常的页面会从缓存渲染；没有处理器的页面会显示 Chrome 的离线错误页。自 Android 版 Chrome 108 与桌面版 Chrome 112 起，站点无需 fetch 处理器即可从浏览器菜单安装，Chrome 还会为缺少离线页的已安装应用提供默认离线页，所以这项测试失败不再阻止安装，但仍意味着用户看到的是 Chrome 的页面而不是你的。测试其他内容前取消勾选 **Offline**；该设置在 DevTools 会话内持续有效。

## 另请参阅

- [调试 Service Worker](/zh/reference/service-worker/debugging/)
- [更新流程与 skipWaiting](/zh/reference/service-worker/update-skipwaiting/)
- [Cache Storage](/zh/reference/storage/cache-storage/)
- [Debug Progressive Web Apps](https://developer.chrome.com/docs/devtools/progressive-web-apps/)（developer.chrome.com）
- [Application panel overview](https://developer.chrome.com/docs/devtools/application/)（developer.chrome.com）
- [Update: install criteria](https://developer.chrome.com/blog/update-install-criteria)（developer.chrome.com）