Ivan's Blog
项目实践

PastePreset

PastePreset 是一个 privacy-first、纯浏览器端的图片处理 Web app。package.json、README.md、docs/pwa-offline-support.md 和 public/manifest.

  • Progressive web app
  • Storybook accessibility

目录

技术栈

运行与交付

CI 工作流
  • ci.yml
  • deploy.yml
能力标记
  • github_actions
  • package_json
JSON

Purpose

PastePreset 是一个 privacy-first、纯浏览器端的图片处理 Web app。package.json、README.md、docs/pwa-offline-support.md 和 public/manifest.webmanifest 共同表明,这个项目不只是普通 React/Vite SPA,而是明确把“可安装、可离线启动、图片处理全在本地完成”的 owner-facing 产品面当成长期 contract 维护。

Taxonomy

  • Tags: Progressive web app, Storybook accessibility

Repository map

  • src/ 是 React 应用本体;src/lib/、src/hooks/ 和 src/components/ 围绕图片输入、处理、输出与设置构成完整前端 runtime。
  • public/manifest.webmanifest 与 public/pwa/ 保存 install-facing metadata、icons、maskable icons 和 screenshots。
  • src/pwa/registerServiceWorker.ts、scripts/build-sw.mjs、scripts/sw-template.js 负责 service worker 注册与构建时 precache 注入。
  • tests/e2e-pwa/、playwright.pwa.config.ts 和 docs/pwa-offline-support.md 说明这个 repo 把 PWA 行为单独当作验证面,而不是塞进普通 smoke test。
  • .storybook/ 与 public/storybook/ 保持组件级 QA 和 a11y surface,但它们不是 PWA 交付面的替身。

Runtime and delivery

package.json 的 build 会先写入版本信息,再执行 vite build,最后运行 node scripts/build-sw.mjs,说明离线 app shell 与 version.json 一样属于正式产物,而不是部署后的临时拼装。index.html 和 public/manifest.webmanifest 把 start_url、scope、display: standalone、maskable icons 和 apple-touch-icon 写成稳定 install metadata;test:e2e:pwa 则通过 playwright.pwa.config.ts 走独立浏览器路径,验证 service worker 就绪、离线启动和核心流程。

Architecture notes

这个项目的关键架构边界是“处理逻辑完全本地执行,但 app shell 仍然需要正式的 PWA 运行时 contract”。docs/pwa-offline-support.md 明确要求:先在线访问并安装,之后离线启动时仍要完整渲染 UI;更新采用 next-launch 语义,不允许 skipWaiting() 或 mid-session 强刷。scripts/build-sw.mjs 用 Workbox injectManifest 维护 precache,src/pwa/registerServiceWorker.ts 负责等待/接管逻辑,说明这里的 PWA 不是营销标签,而是真正影响版本切换、资源缓存和 owner handoff 的 runtime 设计。

Workflow and quality gates

前端质量门禁分三层:vitest 负责单元测试,playwright test 负责常规 e2e,playwright test -c playwright.pwa.config.ts 负责 PWA/offline 专项路径。Storybook 安装了 @storybook/addon-a11y,并通过 test-storybook 保持组件 QA;CI 与 deploy workflow 则让 build + PWA asset + 测试链路一起进入交付面。对于这个仓库,单纯 vite build 通过并不能证明交付完成,PWA 专项验证是必需门禁。

Reusable decisions

  • 把 PWA 设计文档单独写进 docs/pwa-offline-support.md,比在 README 里顺带提一句“支持离线”更可靠。
  • 为 PWA 保留独立的 playwright.pwa.config.ts 和 tests/e2e-pwa/,能避免 service worker / offline 逻辑被普通 e2e 稀释掉。
  • 让 build 显式串联版本写入、静态构建和 service worker 注入,可以防止 version.json 或其它 UI-critical 资产漏进 precache。
  • 对 update lifecycle 采取 next-launch 策略,并在设计文档里明确禁止 skipWaiting() 自动接管,是很值得复用的默认习惯。

Risks and open questions

  • iOS Safari 的离线缓存与剪贴板能力仍有平台限制,PWA contract 需要把“best effort”边界说清楚。
  • HEIC 转换相关动态产物若没有被 precache 完整覆盖,离线成功率会看起来随机。
  • 这个仓库是纯前端产品面,后续若引入云同步或外部 API,就必须重新审查当前“离线即完整功能”的假设。

Evidence index

  • README.md
  • package.json
  • index.html
  • public/manifest.webmanifest
  • public/pwa/
  • scripts/build-sw.mjs
  • scripts/sw-template.js
  • src/pwa/registerServiceWorker.ts
  • playwright.config.ts
  • playwright.pwa.config.ts
  • tests/e2e-pwa/pwa-offline.spec.ts
  • .storybook/main.ts
  • .storybook/preview.tsx
  • docs/pwa-offline-support.md