Enhance PWA support and add PDF tools with caching improvements#45
Enhance PWA support and add PDF tools with caching improvements#45sumitsahoo merged 8 commits intomainfrom
Conversation
There was a problem hiding this comment.
Pull request overview
This PR expands CloakPDF’s toolset with three new PDF utilities (Split PDF, Extract Images, Compare PDFs) and improves the PWA/offline update experience via a new service-worker update prompt and updated PWA configuration.
Changes:
- Added new PDF tools: Split PDF, Extract Images, and Compare PDFs (wired into the home screen/tool registry).
- Added a global
ReloadPromptto surface “offline ready” and “update available” PWA states, and adjusted PWA registration strategy. - Updated documentation/marketing assets to reflect the expanded tool count and revised tool grouping.
Reviewed changes
Copilot reviewed 10 out of 16 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| vite.config.ts | Switches PWA registration to “prompt” and tweaks Workbox cache/update behavior. |
| tsconfig.json | Adds Vite PWA React type support. |
| src/utils/pdf-renderer.ts | Re-exports configured pdfjsLib for shared PDF.js usage. |
| src/types.ts | Extends ToolId union with the three new tool IDs. |
| src/tools/SplitPdf.tsx | Implements the Split PDF tool with split-point UI and ZIP/PDF downloads. |
| src/tools/ExtractImages.tsx | Implements image extraction via PDF.js operator lists with selection + ZIP download. |
| src/tools/ComparePdf.tsx | Implements visual compare + pixel-diff overlay across pages. |
| src/components/ReloadPrompt.tsx | Adds PWA update/offline toast and periodic update checks. |
| src/App.tsx | Registers the new tools and mounts the global reload prompt. |
| README.md | Updates feature list/tool count and adds the new tools to documentation. |
| public/icons/og-image.svg | Updates OG image copy to reflect the new tool count/taglines. |
| package.json | Adds workbox-window dependency. |
| pnpm-lock.yaml | Locks workbox-window and related dependency graph updates. |
Files not reviewed (1)
- pnpm-lock.yaml: Language not supported
| {/* Split button */} | ||
| {splitPoints.size > 0 && ( | ||
| <button | ||
| type="button" | ||
| onClick={handleSplit} | ||
| disabled={processing} | ||
| className="w-full bg-primary-600 text-white py-3 px-6 rounded-xl font-medium hover:bg-primary-700 disabled:opacity-50 disabled:cursor-not-allowed transition-colors" | ||
| > | ||
| {processing | ||
| ? "Splitting..." | ||
| : `Split into ${parts.length} Part${parts.length !== 1 ? "s" : ""} & Download`} | ||
| </button> | ||
| )} |
There was a problem hiding this comment.
The primary action button is only rendered when splitPoints.size > 0, but handleSplit explicitly supports the “no split points” case (parts.length === 1). As written, users can’t trigger the download when they haven’t added any split points (and the code path for parts.length === 1 is effectively unreachable from the UI). Consider always rendering the button when a file is loaded (and parts.length > 0), and adjusting the label/UX for the single-part case (e.g., “Download PDF” vs “Split & Download”).
| } = useRegisterSW({ | ||
| onRegisteredSW(swUrl, registration) { | ||
| if (!registration) return; | ||
| // Periodically check for new service worker updates | ||
| setInterval(async () => { | ||
| if (registration.installing || !navigator) return; | ||
| if ("connection" in navigator && !navigator.onLine) return; | ||
| const resp = await fetch(swUrl, { | ||
| cache: "no-store", | ||
| headers: { cache: "no-store" }, | ||
| }); | ||
| if (resp.status === 200) await registration.update(); | ||
| }, UPDATE_CHECK_INTERVAL_MS); |
There was a problem hiding this comment.
setInterval is started in onRegisteredSW but never cleared, and the async interval callback has no error handling. In dev/HMR or if registration happens more than once, this can create multiple intervals; additionally, if fetch(swUrl) rejects (e.g., offline, captive portal), it can trigger unhandled promise rejections. Consider storing the interval id and clearing it in a cleanup path, checking !navigator.onLine unconditionally (not gated on "connection" in navigator), and wrapping the fetch/registration.update() logic in a try/catch.
| pdfjsLib.getDocument({ data: bufB }).promise, | ||
| ]); | ||
|
|
||
| const results = await comparePdfs(pdfA, pdfB, 1.5, (done, total) => |
There was a problem hiding this comment.
handleCompare renders every page of both PDFs at scale 1.5, converts each canvas to a PNG data URL, and (when both pages exist) also runs a full getImageData pixel diff. For multi-page or high-resolution PDFs this will be very CPU/memory intensive and can freeze the UI. Consider using a smaller render scale for comparisons/thumbnails, limiting processing to a window around the current page (lazy render/diff on navigation), and/or moving the diff work off the main thread (e.g., worker/OffscreenCanvas) to keep the UI responsive.
| const results = await comparePdfs(pdfA, pdfB, 1.5, (done, total) => | |
| const totalPages = Math.max(pdfA.numPages, pdfB.numPages); | |
| const comparisonScale = | |
| totalPages > 50 ? 0.5 : totalPages > 20 ? 0.65 : totalPages > 10 ? 0.8 : 1; | |
| const results = await comparePdfs(pdfA, pdfB, comparisonScale, (done, total) => |
This pull request introduces several new PDF tools, updates the tool ordering and descriptions in the UI and documentation, and adds support for service worker-based offline updates. The most significant changes are the addition of three new PDF tools (Split PDF, Extract Images, Compare PDFs), improvements to the user experience for offline/PWA usage, and updates to dependencies to support these features.
New PDF Tools and Features:
Split PDF(divide a PDF into multiple files),Extract Images(extract all embedded images from a PDF), andCompare PDFs(visual diff of two PDFs). These are reflected in both theREADME.mdand the home screen tool grid (src/App.tsx). [1] [2] [3] [4]Progressive Web App (PWA) Enhancements:
ReloadPromptcomponent that notifies users when a new version of the app is available or when offline mode is ready, improving the PWA experience. This component is now rendered globally in the app layout. [1] [2] [3] [4]Dependency and Configuration Updates:
workbox-windowdependency to enable service worker registration and update checks for offline/PWA support. [1] [2]UI and Codebase Organization:
toolsarray and imports insrc/App.tsxto group tools by theme, improve ordering, and add icons for new tools. [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13]These updates collectively expand the app’s functionality, improve user experience, and lay the groundwork for robust offline support.