Skip to content

Migrate from Angular 9 to React 18 + TypeScript + Vite#414

Open
devanshi-gpta wants to merge 8 commits into
masterfrom
devin/1782850201-angular-to-react-migration
Open

Migrate from Angular 9 to React 18 + TypeScript + Vite#414
devanshi-gpta wants to merge 8 commits into
masterfrom
devin/1782850201-angular-to-react-migration

Conversation

@devanshi-gpta

@devanshi-gpta devanshi-gpta commented Jun 30, 2026

Copy link
Copy Markdown

Summary

Full rewrite of the Hacker News PWA from Angular 9 to React 18 + TypeScript + Vite + react-router-dom, preserving all functionality, styling, the three themes, and PWA/offline support. The entire src/app/ Angular tree and Angular tooling (angular.json, tsconfig.app/spec.json, karma.conf.js, e2e/, tslint.json, polyfills, ngsw-config.json, @angular/* deps) are removed.

Architectural mapping (Angular → React):

  • RxJS service + cancel token → plain async/await fetch module src/api/hackerNews.ts with AbortController. fetchItemContent keeps the poll-aggregation logic (sums poll_votes_count across poll options). Each call accepts an AbortSignal so useEffect cleanup cancels in-flight requests.
  • SettingsService (BehaviorSubject) → React Context src/context/SettingsContext.tsx exposing useSettings(){ settings, toggleSettings, toggleOpenLinksInNewTab, setTheme, setFont, setSpacing }. Same localStorage keys (openLinkInNewTab, theme, titleFontSize, listSpacing) and the prefers-color-scheme listener that toggles default/night.
  • Angular models/classes → plain interfaces in src/models/.
  • comment.pipecommentCount(n) helper in src/helpers/comment.ts.
  • app.routes.tscreateBrowserRouter in src/router.tsx. //news/1; news|newest|show|ask|jobs/:page render Feed (feed type as prop); item/:id and user/:id use React.lazy + Suspense (preserving the original lazy-loaded chunks).
  • Components → function components under src/components/<Name>/: App (theme class wrapper + Header/Outlet/Footer), Header, Settings, Footer, Feed, Item, ItemDetails, Comment (recursive, per-instance collapse via useState), User, Loader, ErrorMessage. Templates ported with *ngIf→conditional render, *ngFor.map()+key, [innerHTML]dangerouslySetInnerHTML, routerLink<Link>, (click)onClick, controlled inputs.
  • @angular/service-worker (ngsw)vite-plugin-pwa (Workbox) in vite.config.ts: precaches the build and NetworkFirst-caches the HN API; web manifest retained.
  • Theme class names (default, night, amoledblack) and all SCSS partials are preserved (moved to src/styles/).

Scripts: dev/start (vite), build (tsc -b && vite build), lint (eslint, --max-warnings 0), typecheck. .travis.yml updated to Node 18 and the Angular CLI install dropped (Firebase deploy step unchanged).

How this was built

Foundation (scaffolding, models, API, settings context, routing, shared components) was built here, then component porting was parallelized across child sessions (#410 User, #411 Header+Settings, #412 ItemDetails+Comment, #413 Feed+Item) which targeted this branch on disjoint files and were merged in.

Verification

npm run lint, npm run typecheck, and npm run build all pass clean. Smoke-tested in the browser against the live HN API: feeds load/paginate, item details render with nested comments + collapse, settings modal + theme switching work and persist across reloads, lazy chunks load, error state renders.

Note: the /user/:id page shows the error state because node-hnapi.herokuapp.com returns 404 for the user endpoint — this is a pre-existing API limitation (the original Angular app called the exact same endpoint), not a regression. The error UI is the ported ErrorMessage component.

News feed (default theme)
Item details with nested comments

Link to Devin session: https://app.devin.ai/sessions/30935a6faa1c40f6bd3d483cd7f1d4e9
Requested by: @devanshi-gpta


Devin Review

Status Commit
⚪ Not started

Run Devin Review

Open in Devin Review (Staging)

devin-ai-integration Bot and others added 8 commits June 30, 2026 20:13
… API, settings context, routing, shared components, component stubs

Co-Authored-By: Devanshi Gupta <devanshi.gupta@cognition.ai>
Co-Authored-By: Devanshi Gupta <devanshi.gupta@cognition.ai>
Co-Authored-By: Devanshi Gupta <devanshi.gupta@cognition.ai>
Co-Authored-By: Devanshi Gupta <devanshi.gupta@cognition.ai>
Co-Authored-By: Devanshi Gupta <devanshi.gupta@cognition.ai>
…y excludes; update CI for Vite

Co-Authored-By: Devanshi Gupta <devanshi.gupta@cognition.ai>
Co-Authored-By: Devanshi Gupta <devanshi.gupta@cognition.ai>
@devin-ai-integration

Copy link
Copy Markdown

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

@devin-ai-integration

Copy link
Copy Markdown

End-to-end test results

Tested the migrated React app on the Vite dev server against the live HN API, exercising each core flow in a browser. Tests were designed adversarially (concrete expected values). All passed; no regressions or spec deviations.

# Test Result
1 News feed loads & renders stories (default red theme) ✅ passed
2 Pagination — page 2 numbers from 31, shows Prev + More ✅ passed
3 Item details: nested comments + collapse [-][+] ✅ passed
4 Theme switch persists across a full page reload ✅ passed
5 "Open links in a new tab" toggles target/rel ✅ passed (caveat)
6 Poll options render with proportional vote bars ✅ passed
Other feeds (newest / show / ask / jobs) render ✅ passed
User page error state (known API 404 limit) ✅ passed (path limited)
Key evidence: pagination, collapse, theme persistence, polls

Test 2 — pagination starts at 31, Prev appears

Page 2 starts at 31 Prev + More at bottom

Test 3 — nested comments collapse

Before: expanded, nested replies visible After: collapsed [+], replies hidden

Test 4 — theme persists across full reload (localStorage)

Night set (before reload) Still Night (after reload)

Test 6 — poll vote bars proportional to points (179 > 73 > 49)

Test 1 + feeds + user error state

Test 1 — news feed, default red theme

Jobs feed — YC header + job-specific layout

User page — graceful error state (known API 404)

Caveat on Test 5 & known limitation

Test 5: The browser automation strips target="_blank" from page anchors (new-tab prevention), so the DOM attribute appears absent. I verified the React component props directly instead: with the setting ON, React assigns target: "_blank" + rel: "noopener"; with it OFF, neither is present. The code is correct — the missing DOM attribute is a test-environment artifact.

Known limitation (not a regression): /user/:id returns 404 from node-hnapi.herokuapp.com (same endpoint the original Angular app used). The app handles it gracefully with the ErrorMessage skull state, but the user-data render path can't be exercised since the API returns no data.

Tested via Devin: https://app.devin.ai/sessions/30935a6faa1c40f6bd3d483cd7f1d4e9

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.

1 participant