Skip to content

feature: React + TypeScript + Vite foundation (wave 1 of Angular rewrite) - #688

Open
devin-ai-integration[bot] wants to merge 2 commits into
masterfrom
devin/1787678779-react-foundation
Open

feature: React + TypeScript + Vite foundation (wave 1 of Angular rewrite)#688
devin-ai-integration[bot] wants to merge 2 commits into
masterfrom
devin/1787678779-react-foundation

Conversation

@devin-ai-integration

@devin-ai-integration devin-ai-integration Bot commented Aug 25, 2026

Copy link
Copy Markdown

Summary

Wave 1 of the Angular 9 → React rewrite: everything shared, nothing feature-level. Later PRs branch off this one and each own a single component file + its SCSS, so this PR deliberately defines all root/shared files up front and leaves the feature components as stubs.

What lands here:

  • Tooling swap: package.json drops all @angular/*, rxjs, zone.js, unfetch, karma/protractor/jasmine/tslint/codelyzer; adds react 18, react-router-dom 6, vite, @vitejs/plugin-react, vite-plugin-pwa, sass, typescript 5. Scripts are dev/build (tsc && vite build)/preview. Deleted angular.json, tsconfig.app.json, tsconfig.spec.json, tslint.json, karma.conf.js, ngsw-config.json, src/test.ts, browserslist, e2e/, yarn.lock (npm + package-lock.json now).
  • Vite entry: root index.html ports the PWA/social metadata, #skip link and .app-loader shell from src/index.html; <app-root><div id="root">; GA snippet and <base href> dropped. Static files moved src/assets|favicon.ico|manifest.jsonpublic/, referenced as absolute /assets/....
  • PWA: vite-plugin-pwa (registerType: 'autoUpdate') reproduces the ngsw-config.json App Shell — precache js/css/html/ico, runtime CacheFirst for /assets/* and image/font extensions — and generates the webmanifest from the old manifest.json values. The static manifest <link> was removed so the build has exactly one manifest.
  • Angular sources are untouched (src/app/**, src/main.ts, polyfills.ts, environments/) and excluded in tsconfig.json so they don't type-check; wave 3 deletes them.

Ported shared layer:

  • src/models/story, comment, user, poll-result, settings, feed-type.type as interfaces, field names preserved verbatim (including the crated_time typo). Story.time_ago is typed string (the Angular model said number but templates render it as text). New feed-name.type.ts ('news' | 'newest' | 'show' | 'ask' | 'jobs') is the Feed prop contract wave-2 sessions code against.
  • src/api/hackerNewsApi.tsHackerNewsAPIService as async fetch functions (fetchFeed, fetchItemContent, fetchPollContent, fetchUser), throwing on non-2xx. Poll logic preserved but parallelized:
    if (story.type === 'poll') {
      story.poll_votes_count = 0;
      const results = await Promise.all(story.poll.map((_, i) => fetchPollContent(story.id + i + 1)));
      results.forEach((r, i) => { story.poll[i] = r; story.poll_votes_count += r.points; });
    }
  • src/context/SettingsContext.tsxSettingsService as SettingsProvider + useSettings(), same localStorage keys/defaults (theme: 'default', titleFontSize: '16', listSpacing: '0') and the same prefers-color-scheme: dark listener, including the "no saved theme → adopt system scheme on mount" behavior.
  • src/utils/comment.ts — the comment pipe as commentCount(n) (identical discuss/singular/plural output).
  • src/components/Loader.tsx, ErrorMessage.tsx (+ their SCSS) ported from the shared Angular components.

Routing (src/App.tsx) reproduces app.component.html (themed wrapper → body-coverwrapper → Header / routes / Footer) and the full v6 table from app.routes.ts: //news/1, /{news,newest,show,ask,jobs}/:page<Feed feedType=…/>, /item/:id, /user/:id; bare feed paths also redirect to page 1. Header, Footer, Settings, Feed, Item, ItemDetails, Comment, User exist as stubs with their real prop shapes only.

Verified: npx tsc --noEmit, npm run build (emits sw.js + one manifest into dist/), npm run dev serves the stub app.

Note: this targets COG-GTM/angular2-hn — the original request named ankehao-demo/angular2-hn, which Devin has no write access to; both repos are at the same commit.

Devin-Org: engineering

Link to Devin session: https://app.devin.ai/sessions/3fd46ac1891c4708a8268feee29628b5
Requested by: @abboudp


Note

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


Devin Review

Status Commit
⚪ Not started

Run Devin Review

Devin Review (Staging)

devin-ai-integration Bot and others added 2 commits August 25, 2026 17:30
Co-Authored-By: Paul Abboud <abboudpaul112@gmail.com>
Co-Authored-By: Paul Abboud <abboudpaul112@gmail.com>
@devin-ai-integration

Copy link
Copy Markdown
Author

🤖 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
Author

Smoke test: React + TS + Vite foundation

Tested locally on devin/1787678779-react-foundation (commits fb65e8e + 1681532) with a clean npm ci, npm run build, npm run dev and npm run preview. Scoped as a foundation smoke testHeader/Footer/Feed/Item/ItemDetails/User/Comment/Settings are intentional stubs, so missing HN UI/data/styling was not treated as a defect.

Recording: https://app.devin.ai/attachments/fc8cdfa4-fc7a-4a3b-a7cd-6abf8fe3e89b/react-foundation-smoke-edited.mp4

Routing + app shell (dev server)

//news/1, bare /news/news/1, and every feed route renders the correct feedType; Header/Footer appear on all routes inside the themed root wrapper (default class default). /item/123 and /user/pg render their stubs. Console: 0 errors (only React Router v7 future-flag warnings and an apple-mobile-web-app-capable deprecation).

dev server / redirects to /news/1

SettingsContext theme persistence & system color scheme

localStorage.theme='night' → root wrapper class="night" and survives repeated reloads; 'amoledblack' applies too. With no saved theme and devtools emulating prefers-color-scheme: dark, the app adopts night and writes it to localStorage; resetting to light yields default. titleFontSize/listSpacing/openLinkInNewTab all persist across reloads (not yet observable in the UI, since the stubs don't consume them).

night theme applied and persisted
system dark scheme adopted and written to localStorage

Production build: PWA + deep links

tsc && vite build exits 0. dist/ contains sw.js + workbox-*.js, and dist/index.html has exactly one <link rel="manifest">. Under vite preview, the service worker reaches #0 activated and is running, manifest.json parses as an App Manifest, icons resolve from public/assets, and deep links like /news/2 serve without a 404.

service worker activated on the preview build
PWA icon served from public/assets

Notes / non-blocking
  • Upstream https://node-hnapi.herokuapp.com/news?page=1 returned HTTP 200 from the test machine, so later data-fetching waves have a live endpoint.
  • npm run build emits Sass legacy @import deprecation warnings originating from the still-present Angular SCSS under src/app/**; these should disappear when those sources are deleted in a later wave.
  • The security/snyk check fails on react-router-dom@6.30.6 (open redirect, high; fixed in 7.18.0) — the rewrite spec pins react-router-dom v6, so that needs a call on v7 vs. a policy exception.

Session: https://app.devin.ai/sessions/3fd46ac1891c4708a8268feee29628b5

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