feat: migrate to Vite vanilla TypeScript, drop jQuery and legacy scripts#4
feat: migrate to Vite vanilla TypeScript, drop jQuery and legacy scripts#4
Conversation
There was a problem hiding this comment.
Copilot wasn't able to review any files in this pull request.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Scaffold Vite v7 + TypeScript project (package.json, vite.config.ts, tsconfig.json) - Replace jQuery + skel.js navigation with vanilla TypeScript (src/main.ts) - Replace web-share.js with typed module (src/web-share.ts) - Move HTML entry to root index.html; strip all legacy script tags - Relocate static assets (icons, images, manifest, SW) to public/ - Update firebase.json to serve from dist/ - Fix service-worker.js: manifest.js → manifest.json, remove stale assets/main.css path - Add .docs/agents.mdc with AI agent codebase guidance - Upgrade Vite to v7 (fixes esbuild CVE GHSA-67mh-4wv8-2f99) Co-authored-by: mayeedwin <17247358+mayeedwin@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 14 out of 32 changed files in this pull request and generated 4 comments.
Comments suppressed due to low confidence (1)
public/service-worker.js:32
- This service worker doesn’t pre-cache the Vite build outputs (hashed JS/CSS under
dist/assets/), so the app won’t work offline even after a successful online load. Consider adding aninstallhandler that pre-caches the built entry assets (or switching to a build-time generated precache list, e.g. via Workbox/Vite PWA plugin) instead of only cachingindex.html, icons, and the manifest.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
src/main.ts
Outdated
| import './style.css' | ||
| import { initWebShare } from './web-share' |
There was a problem hiding this comment.
import './style.css' will fail tsc type-checking unless the project provides Vite/client typings or a *.css module declaration. Add a src/vite-env.d.ts (e.g. /// <reference types="vite/client" />) or a declare module '*.css' declaration so npm run build doesn’t break.
There was a problem hiding this comment.
Added src/vite-env.d.ts with /// <reference types="vite/client" /> in commit 8bef421. This resolves the tsc error on the CSS import.
- Use pwafire webShare/copyText for share with fallback - Use pwafire install for PWA add-to-home-screen - Share buttons on all panels with context-specific text - Modern copy, fonts (DM Sans, Outfit, FA6), manifest - ES6+ features: arrow fns, async/await, destructuring - Remove all console statements from app and service worker
- Replace Font Awesome with inline SVGs (~75KB saved) - Use system fonts, remove Google Fonts - CSS variables, tighter spacing, smaller panels - Add loading=lazy to off-screen images - Remove Twitter widgets from service worker cache
- Dark theme (#0a0a0a) with amber accent (#f59e0b) - Syne + Plus Jakarta Sans typography - Hero layout: circular avatar, pill nav, staggered fade-in - Sub-pages: split image/content grid layout - Slim CSS (~5KB), removed legacy styles - Manifest theme/background match dark palette
- Consolidate to one page (hero + work, about, contact sections) - Remove work/about/contact subpages - Slim CSS (~2KB), simplified service worker - Real bio: Taxually, GDE, PWA Fire
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 20 out of 37 changed files in this pull request and generated 9 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| .then((res) => { | ||
| if (res?.ok) | ||
| caches.open(CACHE).then((c) => c.put(e.request, res.clone())); | ||
| return res; |
There was a problem hiding this comment.
The cache write (caches.open(...).then(c => c.put(...))) isn't tied to the fetch event lifetime. Without e.waitUntil(...), the service worker can be terminated before the put completes, leading to inconsistent caching. Wrap the cache update promise in e.waitUntil(...) (or restructure to await it) so it reliably finishes.
There was a problem hiding this comment.
Fixed in 8bef421 — cache.put is now wrapped in e.waitUntil(caches.open(CACHE).then((c) => c.put(...))) so the write completes before the service worker can be terminated.
| window.addEventListener("load", async () => { | ||
| try { | ||
| await navigator.serviceWorker.register("/service-worker.js"); | ||
| } catch {} | ||
| }); |
There was a problem hiding this comment.
This catch {} swallows service worker registration failures completely, making PWA install/offline issues hard to diagnose in production. Consider at least logging a warning (or reporting to whatever error tracking you use) so failures are observable.
There was a problem hiding this comment.
Fixed in 8bef421 — empty catch {} replaced with catch (err) { console.warn("Service Worker registration failed:", err) }.
| "icons": [ | ||
| {"src": "icons/pwafire512.png", "type": "image/png", "sizes": "48x48"}, | ||
| {"src": "icons/pwafire512.png", "type": "image/png", "sizes": "96x96"}, | ||
| {"src": "icons/pwafire512.png", "type": "image/png", "sizes": "192x192"}, | ||
| {"src": "icons/pwafire512.png", "type": "image/png", "sizes": "512x512"} | ||
| ], |
There was a problem hiding this comment.
The manifest declares multiple icon sizes but points all of them at the same pwafire512.png file. This is incorrect metadata and can cause the wrong icon to be selected (or icons to be ignored). Either reference the actual per-size assets (e.g., 48/96/192/512) or update the sizes entries to match the real dimensions of each file.
There was a problem hiding this comment.
Fixed in 8bef421 — each icon entry now references its actual file: pwafire128white.png (128×128), pwafire144white.png (144×144), pwafire192white.png (192×192), and pwafire512.png (512×512).
.docs/agents.mdc
Outdated
| Anchor clicks on `a[href^="#"]` drive transitions — `locked` boolean prevents re-entrancy. | ||
| `spinX`/`spinY` classes on `<ul>` trigger a 250ms extra delay before switching. | ||
|
|
||
| ### Breakpoints | ||
| Responsive behaviour is handled **entirely by CSS media queries** in `src/style.css`. | ||
| There is no JS breakpoint library (skel.js was removed during the Vite migration). | ||
|
|
||
| ### Web Share API (src/web-share.ts) | ||
| Feature-detected with `navigator.share !== undefined`. | ||
| The `.share` CSS class on any `<a>` element is the trigger button. |
There was a problem hiding this comment.
The documented patterns here don't match the current implementation: there is no panel navigation driven by a[href^="#"] / locked, and web share is now triggered via [data-share] using pwafire helpers (not navigator.share feature-detection nor a .share class). Please reconcile these sections with the current code so the guidance is accurate.
| Anchor clicks on `a[href^="#"]` drive transitions — `locked` boolean prevents re-entrancy. | |
| `spinX`/`spinY` classes on `<ul>` trigger a 250ms extra delay before switching. | |
| ### Breakpoints | |
| Responsive behaviour is handled **entirely by CSS media queries** in `src/style.css`. | |
| There is no JS breakpoint library (skel.js was removed during the Vite migration). | |
| ### Web Share API (src/web-share.ts) | |
| Feature-detected with `navigator.share !== undefined`. | |
| The `.share` CSS class on any `<a>` element is the trigger button. | |
| Navigation logic in `main.ts` attaches click handlers to update the active panel and manage transition timing. | |
| `spinX`/`spinY` classes on `<ul>` still trigger a 250ms extra delay before switching to the target panel. | |
| ### Breakpoints | |
| Responsive behaviour is handled **entirely by CSS media queries** in `src/style.css`. | |
| There is no JS breakpoint library (skel.js was removed during the Vite migration). | |
| ### Web Share API (src/web-share.ts) | |
| Share actions are wired to elements with a `[data-share]` attribute. | |
| Sharing is delegated to `pwafire` helper utilities rather than doing manual `navigator.share` feature detection. |
There was a problem hiding this comment.
Updated in 8bef421 — .docs/agents.mdc now accurately documents the current single-page layout (no panel transitions), [data-share] button pattern, pwafire API usage, and the network-first SW strategy.
| import "./style.css"; | ||
| import { initWebShare } from "./web-share"; | ||
| import { install } from "pwafire"; | ||
|
|
||
| if ("serviceWorker" in navigator) { | ||
| window.addEventListener("load", async () => { | ||
| try { | ||
| await navigator.serviceWorker.register("/service-worker.js"); | ||
| } catch {} | ||
| }); | ||
| } | ||
|
|
||
| document.addEventListener("DOMContentLoaded", () => { | ||
| initWebShare(); | ||
| void install("before"); | ||
| }); |
There was a problem hiding this comment.
PR description mentions rewriting "panel navigation" in src/main.ts, but the current index.html is a single-page layout without panels and src/main.ts contains only service worker + share/install init. Either the navigation rewrite is missing from this PR, or the PR description needs updating to reflect the new simplified layout.
There was a problem hiding this comment.
Updated the PR description to accurately reflect the implementation: src/main.ts handles SW registration + share/install init (no panel navigation), and the layout item now reads "simplified single-page layout replacing the multi-panel structure" rather than implying a navigation rewrite.
| fetch(e.request) | ||
| .then((res) => { | ||
| if (res?.ok) | ||
| caches.open(CACHE).then((c) => c.put(e.request, res.clone())); | ||
| return res; | ||
| }) | ||
| .catch(() => caches.match(e.request)) | ||
| ); |
There was a problem hiding this comment.
The fetch handler falls back to caches.match(e.request), which can resolve to undefined when the request isn't cached (e.g., first load offline). respondWith expects a Response; returning undefined will cause a runtime error. Consider providing a deterministic fallback (e.g., for navigations return the cached /index.html, otherwise return Response.error() or a friendly offline response).
There was a problem hiding this comment.
Fixed in 8bef421 — .catch now returns cached ?? Response.error() so respondWith always receives a valid Response even when the request isn't in cache.
| e.stopPropagation(); | ||
| const context = (btn.getAttribute("data-share") ?? | ||
| "home") as ShareContext; | ||
| await sharePage(context); |
There was a problem hiding this comment.
data-share is cast to ShareContext without validation. If the attribute contains an unexpected value, shareTextByContext[context] will be undefined and you may end up sharing/copying incomplete data. Consider validating against the allowed contexts (or falling back to "home") before calling sharePage.
There was a problem hiding this comment.
Fixed in 8bef421 — added VALID_CONTEXTS array and validate the raw attribute value before casting: unknown values fall back to "home" instead of producing undefined from shareTextByContext.
index.html
Outdated
| <a href="https://pwafire.org/developer">PWA Fire</a> | ||
| </p> | ||
| <div class="actions"> | ||
| <a href="#" class="btn" data-share="home">Share</a> |
There was a problem hiding this comment.
The Share control is an <a href="#"> even though it behaves like a button. For accessibility and correct semantics (keyboard interaction, screen readers), prefer a <button type="button"> or add appropriate role="button" + keyboard handlers if it must remain a link.
| <a href="#" class="btn" data-share="home">Share</a> | |
| <button type="button" class="btn" data-share="home">Share</button> |
There was a problem hiding this comment.
Fixed in 8bef421 — changed to <button type="button" class="btn" data-share="home">Share</button>. Also added cursor: pointer and font-family: inherit to .btn in CSS so the button renders identically to the former anchor.
| ``` | ||
| index.html ← Vite HTML entry (root) | ||
| src/ | ||
| main.ts ← Panel navigation logic (vanilla TS, no jQuery) | ||
| web-share.ts ← Web Share API integration | ||
| style.css ← Imports app CSS (Google Fonts, Font Awesome via CDN) | ||
| public/ |
There was a problem hiding this comment.
This architecture block claims src/main.ts contains panel navigation logic and style.css imports Google Fonts + Font Awesome, but the current src/main.ts only registers the service worker / init code and src/style.css imports different fonts and no Font Awesome. Please update this doc to match the current structure/behaviour.
There was a problem hiding this comment.
Fixed in 8bef421 — the architecture section now correctly shows the single-page layout, Syne/Plus Jakarta Sans fonts (no Font Awesome), and main.ts as SW registration + share/install init.
… a11y, validation, docs - Add src/vite-env.d.ts (/// <reference types="vite/client" />) — fixes tsc error on CSS import - Fix service-worker.js: wrap cache.put in e.waitUntil; add Response.error() fallback offline - Fix main.ts: log SW registration failures with console.warn instead of empty catch - Fix manifest.json: each icon entry references its actual file (128/144/192/512) - Fix index.html: Share control changed from <a href="#"> to <button type="button"> - Fix web-share.ts: validate data-share attribute against VALID_CONTEXTS before casting - Update .btn CSS: add cursor/font-family resets for button element parity - Rewrite .docs/agents.mdc to match current architecture (single-page, pwafire, [data-share]) Co-authored-by: mayeedwin <17247358+mayeedwin@users.noreply.github.com>
feat/vite-vanilla-ts.docs/agents.mdcwith codebase guidancepackage.json,vite.config.ts,tsconfig.json)index.htmlat root — simplified layout replacing the multi-panel structureweb-share.jswith typed ES modulesrc/web-share.tsusingpwafireAPIssrc/main.ts— service worker registration +initWebShare()+ install prompt (no panel navigation; layout is single-page)public/(icons, images, manifest, service worker)firebase.jsonto serve fromdist/.gitignoreto excludedist/,node_modules/app/directorysrc/vite-env.d.tsfor Vite client types (fixes CSS import type error intsc)e.waitUntil()around cache write;Response.error()offline fallbackconsole.warn<a href="#">→<button type="button">for accessibilitydata-shareagainstVALID_CONTEXTSbefore casting.btnCSS:cursor: pointer+font-family: inheritfor button element parity.docs/agents.mdcto match current architecture (single-page,pwafireAPIs,[data-share]pattern)npm run buildpasses — TypeScript clean, 0 vulnerabilities, CodeQL 0 alerts🔒 GitHub Advanced Security automatically protects Copilot coding agent pull requests. You can protect all pull requests by enabling Advanced Security for your repositories. Learn more about Advanced Security.