diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2b0e976..167add2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,7 +10,7 @@ concurrency: cancel-in-progress: true jobs: - lint: + test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 @@ -20,3 +20,11 @@ jobs: - run: corepack enable - run: pnpm i - run: pnpm lint-check + - run: pnpm exec playwright install chromium --with-deps --no-shell + - run: pnpm test-e2e + - uses: actions/upload-artifact@v7 + if: failure() + with: + name: playwright-report + path: test-results/ + retention-days: 7 diff --git a/.gitignore b/.gitignore index 1048609..5f70dce 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,2 @@ node_modules -.wrangler +test-results diff --git a/docs/prd.md b/docs/prd.md index 14c78c5..b7bb3e7 100644 --- a/docs/prd.md +++ b/docs/prd.md @@ -7,15 +7,19 @@ - [x] chore: add example zip from vitest html artifact - [x] `?url=` param for public URLs (GitHub artifact download requires auth, but pre-signed Azure blob URLs and S3 buckets work) - [x] File picker button (not just drag-and-drop) — mobile/accessibility -- [ ] refactor: rework code - - deduplicate fflate import (script tag on line 6 is dead weight, only the ES module import is needed) - - share constants (CACHE_NAME, PREFIX) between index.html and sw.js instead of duplicating - - move MIME map to sw.js (it's serving the files, not the main thread) - - add try/catch around unzipSync for corrupt/non-zip files - - consider async unzip for large zips (fflate has async `unzip`) - - SW scope may break under subpath hosting -- [ ] "Load another zip" button — currently the drop zone hides permanently after first load, no way to swap without refresh +- [x] refactor: remove dead fflate script tag, use single ESM import +- [x] refactor: fix XSS in fetch error display (Preact escapes by default) +- [x] refactor: parallelize cache.put() with Promise.all +- [x] refactor: consider async unzip for large zips (fflate has async `unzip`) +- [x] refactor: add try/catch around unzipSync for corrupt/non-zip files +- [x] refactor: SW ready blocks event listeners — make non-blocking, show "registering…" status +- [ ] refactor: share constants (CACHE_NAME, PREFIX) between index.html and sw.js +- [ ] refactor: extract ` -
- Vitest Viewer -
- - Source code -
- -
-
Drag & drop or click to upload
-
.zip files only
-
-
- or try an - example -
- - - +
diff --git a/src/sw.js b/src/sw.js index 2f152a3..db6fd54 100644 --- a/src/sw.js +++ b/src/sw.js @@ -1,6 +1,9 @@ const CACHE_NAME = "zipview-v1"; const PREFIX = "/zipview/site/"; +// skipWaiting: activate immediately instead of waiting for old clients to close. +// clients.claim: take control of existing tabs right away. +// Together these ensure the new SW is serving before index.html writes to the cache. self.addEventListener("install", () => self.skipWaiting()); self.addEventListener("activate", (e) => e.waitUntil(self.clients.claim())); diff --git a/vite.config.ts b/vite.config.ts index 9c46f45..682da49 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -2,7 +2,7 @@ import { defineConfig } from "vite-plus"; export default defineConfig({ staged: { - "*": "vp fmt", + "*": "vp check --fix --no-lint", }, fmt: {}, });