Feat: implement PWA support for offline access#684
Conversation
Added PWA support with configuration for caching and manifest.
Add service worker registration for PWA support.
❌ Deploy Preview for github-spy failed.
|
📝 WalkthroughWalkthroughThe PR adds Progressive Web App support by configuring the VitePWA Vite plugin with service worker registration, manifest metadata, and GitHub API caching rules, then registers the service worker at runtime before React bootstrap to enable offline access and installability. ChangesPWA Service Worker and Build Configuration
🎯 3 (Moderate) | ⏱️ ~20 minutes
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/main.tsx`:
- Around line 7-10: The call to registerSW({ immediate: true }) can throw and
block app initialization; wrap the registration in a try-catch (or call it
asynchronously after render) so failures don't break the app: locate registerSW
in src/main.tsx and change its invocation to be guarded by a try { await
registerSW({ immediate: true }) } catch (err) { /* log or noop */ } or call
registerSW().catch(...) so errors are caught and logged without preventing React
from mounting.
In `@vite.config.ts`:
- Line 19: The config currently sets orientation: 'portrait' which forces
portrait-only layout; update the exported Vite config (the object passed to
defineConfig / the default export in vite.config.ts) to use orientation: 'any'
(or remove the orientation key) so desktop/tablet/landscape users can view the
dashboard correctly; locate and change the orientation property in the config
object to 'any'.
- Around line 48-50: The cacheableResponse configuration is including status 0
(opaque/error responses) which can cache CORS/network failures; update the
cacheableResponse.statuses in the vite config (the cacheableResponse block) to
remove 0 and only include successful HTTP codes (e.g., [200] or other explicit
GitHub success codes you need) so only real successful responses are cached.
- Line 3: The project imports VitePWA from 'vite-plugin-pwa' in vite.config.ts
but the package isn't declared in the owning package.json; add "vite-plugin-pwa"
to that package.json (preferably under devDependencies), pick a compatible
version for your Vite setup, run the package manager install (npm/yarn/pnpm) to
update node_modules and lockfile, and commit the updated package.json and
lockfile so VitePWA import (VitePWA in vite.config.ts) resolves in CI and local
builds.
- Around line 21-34: The manifest icons in the icons array in vite.config.ts
reference src: 'crl.png' for sizes '192x192' and '512x512' but the actual
public/crl.png is 219x230 (non-square and wrong dimensions); fix by replacing
those entries to reference correctly-sized square icon files that exist in
public (e.g., crl-192.png and crl-512.png) or generate square 192x192 and
512x512 PNGs and update the src and sizes accordingly in the same icons array
while keeping type: 'image/png' and purpose: 'any'.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 20a38b00-33ec-4e67-b7d6-46c99db08996
📒 Files selected for processing (2)
src/main.tsxvite.config.ts
| // Import the service worker registration from the virtual module | ||
| import { registerSW } from "virtual:pwa-register"; | ||
| // Register the service worker to handle automatic background updates | ||
| registerSW({ immediate: true }); |
There was a problem hiding this comment.
Add error handling around service worker registration.
Calling registerSW({ immediate: true }) synchronously before React rendering means any error (unsupported browser, misconfigured plugin, HTTP context) will prevent the entire app from initializing. Users would see a blank page instead of a helpful error or the app functioning without PWA features.
🛡️ Recommended fix: Wrap registration in try-catch
// Import the service worker registration from the virtual module
import { registerSW } from "virtual:pwa-register";
-// Register the service worker to handle automatic background updates
-registerSW({ immediate: true });
+
+// Register the service worker to handle automatic background updates
+// Wrapped in try-catch to prevent blocking app initialization if SW fails
+try {
+ registerSW({ immediate: true });
+} catch (error) {
+ console.warn('Service worker registration failed:', error);
+ // App will continue to function without PWA features
+}This ensures the app remains functional even if PWA features are unavailable.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // Import the service worker registration from the virtual module | |
| import { registerSW } from "virtual:pwa-register"; | |
| // Register the service worker to handle automatic background updates | |
| registerSW({ immediate: true }); | |
| // Import the service worker registration from the virtual module | |
| import { registerSW } from "virtual:pwa-register"; | |
| // Register the service worker to handle automatic background updates | |
| // Wrapped in try-catch to prevent blocking app initialization if SW fails | |
| try { | |
| registerSW({ immediate: true }); | |
| } catch (error) { | |
| console.warn('Service worker registration failed:', error); | |
| // App will continue to function without PWA features | |
| } |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/main.tsx` around lines 7 - 10, The call to registerSW({ immediate: true
}) can throw and block app initialization; wrap the registration in a try-catch
(or call it asynchronously after render) so failures don't break the app: locate
registerSW in src/main.tsx and change its invocation to be guarded by a try {
await registerSW({ immediate: true }) } catch (err) { /* log or noop */ } or
call registerSW().catch(...) so errors are caught and logged without preventing
React from mounting.
| @@ -1,11 +1,63 @@ | |||
| import { defineConfig } from 'vite' | |||
| import react from '@vitejs/plugin-react' | |||
| import { VitePWA } from 'vite-plugin-pwa' // Import the PWA plugin | |||
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check if vite-plugin-pwa is declared in package.json
if [ -f package.json ]; then
cat package.json | jq -r '.dependencies["vite-plugin-pwa"] // .devDependencies["vite-plugin-pwa"] // "NOT_FOUND"'
else
echo "package.json not found"
fiRepository: GitMetricsLab/github_tracker
Length of output: 82
Add vite-plugin-pwa to dependencies/devDependencies
vite.config.ts imports VitePWA from vite-plugin-pwa, but the repo-root package.json does not list vite-plugin-pwa in dependencies or devDependencies. Add it to the package.json that owns the Vite config to avoid module-resolution failures.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@vite.config.ts` at line 3, The project imports VitePWA from 'vite-plugin-pwa'
in vite.config.ts but the package isn't declared in the owning package.json; add
"vite-plugin-pwa" to that package.json (preferably under devDependencies), pick
a compatible version for your Vite setup, run the package manager install
(npm/yarn/pnpm) to update node_modules and lockfile, and commit the updated
package.json and lockfile so VitePWA import (VitePWA in vite.config.ts) resolves
in CI and local builds.
| theme_color: '#0d1117', | ||
| background_color: '#0d1117', | ||
| display: 'standalone', | ||
| orientation: 'portrait', |
There was a problem hiding this comment.
Consider using 'any' for orientation to support desktop and tablet users.
Restricting orientation to portrait may provide a suboptimal experience for users on desktop, laptop, or tablet devices viewing the GitHub Tracker dashboard in landscape mode. Unless this is specifically a mobile-only application, orientation: 'any' is typically preferred.
📱 Suggested fix to support all orientations
display: 'standalone',
- orientation: 'portrait',
+ orientation: 'any',
start_url: '/',📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| orientation: 'portrait', | |
| display: 'standalone', | |
| orientation: 'any', | |
| start_url: '/', |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@vite.config.ts` at line 19, The config currently sets orientation: 'portrait'
which forces portrait-only layout; update the exported Vite config (the object
passed to defineConfig / the default export in vite.config.ts) to use
orientation: 'any' (or remove the orientation key) so desktop/tablet/landscape
users can view the dashboard correctly; locate and change the orientation
property in the config object to 'any'.
| icons: [ | ||
| { | ||
| src: 'crl.png', | ||
| sizes: '192x192', | ||
| type: 'image/png', | ||
| purpose: 'any' | ||
| }, | ||
| { | ||
| src: 'crl.png', | ||
| sizes: '512x512', | ||
| type: 'image/png', | ||
| purpose: 'any' | ||
| } | ||
| ] |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check if crl.png exists and report its dimensions
fd -t f "^crl\.png$" public/ -x file {} \; -x identify -format "%f: %wx%h\n" {} 2>/dev/null || echo "crl.png not found or 'identify' (ImageMagick) not available"
# List all PNG files in public directory that might be icons
echo -e "\nAll PNG files in public directory:"
fd -e png . public/Repository: GitMetricsLab/github_tracker
Length of output: 203
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== vite.config.ts (around icons config) =="
if [ -f "vite.config.ts" ]; then
sed -n '1,120p' vite.config.ts | nl -ba | sed -n '15,60p'
else
echo "vite.config.ts not found"
fi
echo
echo "== Search for crl.png usage =="
rg -n "crl\.png" . || true
echo
echo "== Public PNG files =="
fd -e png . public/ | sort || true
echo
echo "== Dimensions via Pillow (crl.png, crl-icon.png) =="
python3 - <<'PY'
from PIL import Image
import os, sys
paths = []
for p in ["public/crl.png", "public/crl-icon.png"]:
if os.path.exists(p):
paths.append(p)
if not paths:
print("No expected icon files found in public/.")
sys.exit(0)
for p in paths:
with Image.open(p) as img:
print(f"{p}: {img.size[0]}x{img.size[1]}")
PYRepository: GitMetricsLab/github_tracker
Length of output: 176
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== Locate vite.config.ts =="
fd -t f "vite.config.ts" . || true
echo
echo "== Show vite.config.ts around 'icons' if found =="
path="$(fd -t f "vite.config.ts" . | head -n 1 || true)"
if [ -n "${path}" ] && [ -f "${path}" ]; then
echo "-- file: ${path} --"
# Print a small window around the first occurrence of "icons"
awk '
{ if ($0 ~ /icons[[:space:]]*:/ && start==0) { start=NR-10; if (start<1) start=1; }
if (start>0 && NR>=start && NR<=start+80) print NR ":" $0
if (start>0 && NR>=start+80) { exit }
}
' "${path}"
else
echo "vite.config.ts not found in repo."
fi
echo
echo "== Search for crl.png usage =="
rg -n "crl\.png" . || true
echo
echo "== Public PNG files =="
fd -e png . public/ | sort || true
echo
echo "== Dimensions via Pillow =="
python3 - <<'PY'
from PIL import Image
import os
paths = ["public/crl.png", "public/crl-icon.png", "public/crl.png".replace("public/","")]
# Deduplicate existing paths
paths = [p for p in ["public/crl.png","public/crl-icon.png"] if os.path.exists(p)]
if not paths:
print("No expected icon files found in public/.")
raise SystemExit(0)
for p in paths:
with Image.open(p) as img:
print(f"{p}: {img.size[0]}x{img.size[1]}")
PYRepository: GitMetricsLab/github_tracker
Length of output: 1777
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== Search for crl-icon.png usage =="
rg -n "crl-icon\.png" . || true
echo
echo "== Install Pillow (needed for dimensions) =="
python3 -m pip -q install Pillow
echo
echo "== Dimensions via Pillow =="
python3 - <<'PY'
from PIL import Image
import os
paths = ["public/crl.png", "public/crl-icon.png"]
for p in paths:
if not os.path.exists(p):
print(f"{p}: MISSING")
continue
with Image.open(p) as img:
print(f"{p}: {img.size[0]}x{img.size[1]}")
PYRepository: GitMetricsLab/github_tracker
Length of output: 692
🏁 Script executed:
#!/bin/bash
set -euo pipefail
python3 -m pip -q install Pillow
python3 - <<'PY'
from PIL import Image
img = Image.open('public/crl.png')
print(f"public/crl.png dimensions: {img.size[0]}x{img.size[1]} (expected 192x192 and 512x512 per vite.config.ts)")
PYRepository: GitMetricsLab/github_tracker
Length of output: 157
🏁 Script executed:
python3 -m pip -q install Pillow
python3 - <<'PY'
from PIL import Image
img = Image.open('public/crl.png')
print('public/crl.png:', img.size)
PYRepository: GitMetricsLab/github_tracker
Length of output: 99
Critical: PWA icons misconfigured—crl.png is 219x230 but declared as 192x192 and 512x512
vite.config.ts declares two manifest icons using src: 'crl.png' for sizes: '192x192' and sizes: '512x512', but public/crl.png is actually 219x230 (non-square / doesn’t match either declared dimension), so the manifest won’t match the intended icon set.
🎨 Recommended fix: reference correctly sized square icons for each declared size
icons: [
{
- src: 'crl.png',
+ src: 'icon-192.png',
sizes: '192x192',
type: 'image/png',
purpose: 'any'
},
{
- src: 'crl.png',
+ src: 'icon-512.png',
sizes: '512x512',
type: 'image/png',
purpose: 'any'
}
]🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@vite.config.ts` around lines 21 - 34, The manifest icons in the icons array
in vite.config.ts reference src: 'crl.png' for sizes '192x192' and '512x512' but
the actual public/crl.png is 219x230 (non-square and wrong dimensions); fix by
replacing those entries to reference correctly-sized square icon files that
exist in public (e.g., crl-192.png and crl-512.png) or generate square 192x192
and 512x512 PNGs and update the src and sizes accordingly in the same icons
array while keeping type: 'image/png' and purpose: 'any'.
| cacheableResponse: { | ||
| statuses: [0, 200] | ||
| } |
There was a problem hiding this comment.
Major: Including status 0 in cacheableResponse may cache CORS errors.
The cacheableResponse.statuses array includes 0, which represents opaque responses (typically CORS errors or network failures). The GitHub API returns proper HTTP status codes, so caching status 0 responses will pollute the cache with errors, causing users to see stale error responses when offline.
🔧 Recommended fix: Cache only successful responses
cacheableResponse: {
- statuses: [0, 200]
+ statuses: [200]
}If the app needs to cache other successful GitHub API response codes, consider:
- statuses: [0, 200]
+ statuses: [200, 201, 204]📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| cacheableResponse: { | |
| statuses: [0, 200] | |
| } | |
| cacheableResponse: { | |
| statuses: [200] | |
| } |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@vite.config.ts` around lines 48 - 50, The cacheableResponse configuration is
including status 0 (opaque/error responses) which can cache CORS/network
failures; update the cacheableResponse.statuses in the vite config (the
cacheableResponse block) to remove 0 and only include successful HTTP codes
(e.g., [200] or other explicit GitHub success codes you need) so only real
successful responses are cached.
|
Hi @mehul-m-prajapati I have successfully implemented and verified the PWA support locally. However, the GitHub Actions checks are failing due to pre-existing ESLint errors in |
Related Issue
Description
This PR introduces Progressive Web App (PWA) support to the application to enable offline capabilities, resource caching, and standalone installability ("Add to Home Screen").
How Has This Been Tested?
Tested locally using a production-built environment to ensure proper service worker registration and manifest recognition:
npm run buildfollowed bynpm run previewto evaluate the production output.Screenshots (if applicable)
bREC.mp4
Type of Change
Summary by CodeRabbit