Skip to content

feature: PWA (vite-plugin-pwa), Firebase Hosting and GitHub Actions CI for the React app - #883

Merged
devin-ai-integration[bot] merged 10 commits into
devin/1791469878-react-phase0-foundationfrom
devin/1791470086-react-pwa-build-deploy
Oct 8, 2026
Merged

devin-ai-integration[bot] merged 10 commits into
devin/1791469878-react-phase0-foundationfrom
devin/1791470086-react-pwa-build-deploy

Conversation

@devin-ai-integration

@devin-ai-integration devin-ai-integration Bot commented Oct 8, 2026 •

Copy link
Copy Markdown

Summary

Workstream E: ports offline support, the Web App Manifest, Firebase Hosting and CI from the Angular app to the Vite app in react-app/.

Service worker / manifest (vite.config.ts, vite-plugin-pwa, generateSW + registerType: 'autoUpdate')

  • The manifest is generated from the Angular src/manifest.json values: name/short_name Angular 2 HN, 144/192/256/512 icons, theme #b92b27, background #ffffff, standalone, portrait, start_url: ./?utm_source=web_app_manifest. The plugin injects <link rel="manifest">.
  • Precache: globPatterns: ['**/*.{js,css,html,ico,png,svg}'] with includeManifestIcons: false and no includeAssets. This avoids the duplicate-URL add-to-cache-list-conflicting-entries trap. navigateFallback: 'index.html' makes deep links like /item/123 work offline.
  • Runtime caching: NetworkFirst for node-hnapi.herokuapp.com (hn-api, 200 entries) and api.hnpwa.com (hnpwa-api, 100 entries), with a 5 s network timeout and 7-day expiry. The origins live in src/pwa/runtime-cache.ts, which both the config and the register module use.
  • skipWaiting + clientsClaim, so the first visit is controlled straight away.

Registration (src/pwa/registerSW.ts, imported once from main.tsx via src/pwa/index.ts)

  • Registers immediately, logs offline-ready and registration errors, and polls registration.update() every hour while online. It skips the poll while offline or while a worker is installing.
  • First-visit cache warm-up. On a first visit the API requests start before the SW controls the page, so they skip the runtime cache. Without a fix, the page you landed on fails offline. Found while checking against the live API. On the first controllerchange, registerSW re-requests every runtime-cached URL that started before control, read from performance resource entries. A PerformanceObserver catches requests still in flight at that moment.
    controllerchange (once, only if no controller at load):
      t = performance.now()
      warmRuntimeCache(resourceEntries.filter(e => e.startTime < t))  // fetch() again, now through the SW
      PerformanceObserver(resource) → same filter, for 60 s
    For comparison, the Angular build fails the same check: first visit, go offline, reload gives "Could not load news stories" (screenshots below).

Retiring the Angular service worker (public/ngsw-worker.js): returning visitors still have @angular/service-worker registered at /ngsw-worker.js, and it would keep serving the cached Angular index. The safety worker served at that URL replaces it on the browser's next update check. It deletes the ngsw:* caches, unregisters itself and reloads open tabs, which then register sw.js. It is excluded from the precache (globIgnores) and served no-cache. I checked the upgrade against the real Angular production build: the same origin switched from dist/angular-hnpwa to react-app/dist, and on the first reload the page was controlled by sw.js with no ngsw:* caches and the React app rendered.

Firebase (firebase.json): hosting public: react-app/dist, predeploy = npm --prefix react-app ci && run build, SPA rewrite ** → /index.html, and Cache-Control: no-cache for sw.js, ngsw-worker.js, index.html, manifest.webmanifest and extensionless routes (including /). Hashed /assets/*-[hash].(js|css) get public, max-age=31536000, immutable. The database rules entry is unchanged and .firebaserc is untouched. I checked the headers with the Hosting emulator.

CI (.travis.yml → .github/workflows/react-app.yml): runs on PRs and on pushes to master. Jobs run on Node 20 with npm ci and the npm cache, in react-app/:

  • check: lint, typecheck, test, build, format:check
  • e2e: Playwright against the production build
  • deploy: push to master only, after both jobs pass. It uses FirebaseExtended/action-hosting-deploy with FIREBASE_SERVICE_ACCOUNT, falls back to firebase-tools with FIREBASE_TOKEN, and skips with a notice when neither secret is set. Forks and PRs never fail on missing credentials.

E2E (playwright.config.ts, e2e/offline.spec.ts)

  • Runs against vite build && vite preview. PW_EXPERIMENTAL_SERVICE_WORKER_NETWORK_EVENTS=1 is set at the top of the config. Locally it uses the system Chrome when Playwright browsers aren't installed.
  • The test mocks the API with 1.5 s latency, so the feed request is still in flight when the SW takes control. It loads /news/1 online, waits for SW control, and checks that the feed reaches the runtime cache. Then it opens the item page client-side and goes offline: it removes all routes, aborts every request and calls setOffline, because route mocks otherwise keep answering. It reloads and expects the feed rendered from cache, then deep-links to /item/8863 (served by navigateFallback) and expects the item rendered from cache. A never-visited item must fail.
  • A second test checks manifest.webmanifest and every icon URL. A third registers /ngsw-worker.js over the React SW with a fake ngsw: cache, then asserts the cache is gone and sw.js is back in control after the reload.

Generated precache manifest (dist/sw.js): 28 entries, 28 unique

total 28 unique 28
index.html
favicon.ico
assets/workbox-window.prod.es5-BBnX5xw4.js
assets/sanitize-html-jJTodm-a.js
assets/index-CB7kgWzl.css
assets/index-BDhtGmUk.js
assets/User-DGafOr9I.css
assets/User-BvHx_t4O.js
assets/ItemDetails-De2TYqUo.js
assets/ItemDetails-DbuGppJi.css
assets/images/logo.svg
assets/images/logo-header.png
assets/images/cog.svg
assets/icons/safari-pinned-tab.svg
assets/icons/mstile-150x150.png
assets/icons/favicon-32x32.png
assets/icons/favicon-16x16.png
assets/icons/apple-touch-icon.png
assets/icons/apple-touch-icon-76x76.png
assets/icons/apple-touch-icon-60x60.png
assets/icons/apple-touch-icon-180x180.png
assets/icons/apple-touch-icon-152x152.png
assets/icons/apple-touch-icon-120x120.png
assets/icons/android-chrome-512x512.png
assets/icons/android-chrome-256x256.png
assets/icons/android-chrome-192x192.png
assets/icons/android-chrome-144x144.png
manifest.webmanifest

Lighthouse (mobile preset, vite preview vs Angular ng build --prod, /news/1, 3 runs each)

Performance Accessibility Best Practices SEO
React (this PR) 100 / 100 / 100 100 100 100
Angular prod build 98 / 98 / 97 100 100 92 (no robots.txt)

TBT is 13–19 ms for React and 155–200 ms for Angular. FCP/LCP is about 1.5 s for both, and CLS is 0 for both. The Angular README's claimed 87 is out of date. I added public/robots.txt because the SEO audit flagged it.

Installability: the manifest is valid (name, icons ≥192/512, standalone, start_url), the SW is active and controls the page, and Chrome reports no installability errors (checked with a persistent profile).

Offline screenshots (live API: first visit online, open one item, go offline, reload, then deep link)

The React shell has no header yet; that comes in another workstream.

Desktop Mobile (375px)
React feed, offline reload
React /item/:id deep link, offline
Angular feed, offline reload

Verification

In react-app/, npm run lint, typecheck, test (10 files, 100 tests, 12 of them for registerSW), build, format:check and e2e all pass. The e2e suite (3 tests) also passed --repeat-each=2.

Shared-file changes

  • react-app/src/main.tsx: adds one line, import './pwa';
  • react-app/tsconfig.app.json: adds vite-plugin-pwa/client to types

Devin-Org: engineering

Link to Devin session: https://devin-gtm.devinenterprise.com/sessions/d251403d3f8c4929b5ec9516807084d2
Open in Devin Desktop: https://devin-gtm.devinenterprise.com/desktop/session/d251403d3f8c4929b5ec9516807084d2?variant=devin
Requested by: @ishita-cog


Note

Devin errored when opening this Pull Request as ishita-cog.
As a fallback, Devin opened this PR as itself.


Devin Review

Status Commit
⚪ Not started —

Run Devin Review

Devin Review (Staging)


Devin Review

devin-ai-integration Bot and others added 9 commits October 8, 2026 14:38
…I for the React app

Co-Authored-By: Ishita Gupta <ishita.gupta@cognition.ai>
…undation' into devin/1791470086-react-pwa-build-deploy
Co-Authored-By: Ishita Gupta <ishita.gupta@cognition.ai>
…undation' into devin/1791470086-react-pwa-build-deploy
Co-Authored-By: Ishita Gupta <ishita.gupta@cognition.ai>
…ook control

Co-Authored-By: Ishita Gupta <ishita.gupta@cognition.ai>
Co-Authored-By: Ishita Gupta <ishita.gupta@cognition.ai>
…undation' into devin/1791470086-react-pwa-build-deploy
…rs from cache

Co-Authored-By: Ishita Gupta <ishita.gupta@cognition.ai>
@devin-ai-integration

Copy link
Copy Markdown
Author

I'll fix CI failures and address comments from users with write access. I'll skip comments containing "(aside)".

  • Disable automatic comment, CI, and merge conflict monitoring

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 3 potential issues.

Devin Review

Comment thread firebase.json
Comment on lines +31 to +36
- run: npm ci
- run: npm run lint
- run: npm run typecheck
- run: npm test
- run: npm run build
- run: npm run format:check

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔍 Angular build loses CI coverage

The new workflow checks only the React app while the Angular app remains in the repository. Confirm whether Angular build checks still belong in CI during the migration.

Devin Review


Was this helpful? React with 👍 or 👎 to provide feedback.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is intentional for this workstream: the brief asks to replace .travis.yml with CI for react-app/. Firebase Hosting now serves react-app/dist, so the Angular build is no longer what ships. The old Travis job only ran npm run build on Node 6.9, which no longer runs Angular 9 without --openssl-legacy-provider. Whether to keep an Angular build check until src/ is deleted is the integrator's decision, so I'm leaving this thread open.

Written by Devin

Comment thread react-app/src/pwa/registerSW.ts Outdated
… first-visit cache warm-up

Co-Authored-By: Ishita Gupta <ishita.gupta@cognition.ai>
@devin-ai-integration
devin-ai-integration Bot merged commit ebc47f9 into devin/1791469878-react-phase0-foundation Oct 8, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants