Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ speed-measure-plugin.json
!.vscode/extensions.json
.history/*

# PWA dev service worker output
dev-dist

# misc
/.sass-cache
/connect.lock
Expand Down
3 changes: 1 addition & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
language: node_js
node_js:
- "6.9"
- "20"

branches:
only:
- master

before_script:
- npm install -g firebase-tools
- npm install -g @angular/cli

script:
- npm run build
Expand Down
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
</p>

<p align="center">
A progressive Hacker News client built with Angular
A progressive Hacker News client built with React and TypeScript
</p>

<p align="center">
Expand Down Expand Up @@ -43,7 +43,7 @@

## Offline Support

This app uses [Workbox](https://workboxjs.org/) to generate a service worker as part of the build step to load quickly and work offline.
This app uses [Workbox](https://developer.chrome.com/docs/workbox) (via [vite-plugin-pwa](https://vite-pwa-org.netlify.app/)) to generate a service worker as part of the build step to load quickly and work offline.

## Manifest

Expand Down Expand Up @@ -73,16 +73,16 @@ Feel free to send me feedback on [twitter](https://twitter.com/hdjirdeh) or [fil

## Build process

Note: This project has been ejected (with AOT + production settings) in order to customize Webpack configurations.
This project is built with [Vite](https://vitejs.dev/), React and TypeScript.

- Clone or download the repo
- `npm install`
- `npm start` to run the application with webpack-dev-server or `npm build` to kick off a fresh build and update the output directory (`dist/`)
- `npm start` to run the application with the Vite dev server, or `npm run build` to kick off a fresh production build into the output directory (`dist/`)
- `npm test` to run the unit tests with [Vitest](https://vitest.dev/), and `npm run lint` to lint with ESLint

Note: Any Service Worker changes will not be reflected when you run the application locally in development. To test service worker changes:
- `npm build`
- `npm run precache` to generate the service worker file
- `npm run static-serve` to load the application along with the service worker asset using [live-server](https://github.com/tapio/live-server)
- `npm run build`
- `npm run preview` to serve the production build (including the generated service worker) locally

## Contributors

Expand Down
134 changes: 0 additions & 134 deletions angular.json

This file was deleted.

12 changes: 0 additions & 12 deletions browserslist

This file was deleted.

32 changes: 0 additions & 32 deletions e2e/protractor.conf.js

This file was deleted.

23 changes: 0 additions & 23 deletions e2e/src/app.e2e-spec.ts

This file was deleted.

11 changes: 0 additions & 11 deletions e2e/src/app.po.ts

This file was deleted.

13 changes: 0 additions & 13 deletions e2e/tsconfig.json

This file was deleted.

25 changes: 25 additions & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import js from '@eslint/js';
import globals from 'globals';
import reactHooks from 'eslint-plugin-react-hooks';
import reactRefresh from 'eslint-plugin-react-refresh';
import tseslint from 'typescript-eslint';

export default tseslint.config(
{ ignores: ['dist', 'dev-dist'] },
{
extends: [js.configs.recommended, ...tseslint.configs.recommended],
files: ['**/*.{ts,tsx}'],
languageOptions: {
ecmaVersion: 2020,
globals: globals.browser,
},
plugins: {
'react-hooks': reactHooks,
'react-refresh': reactRefresh,
},
rules: {
...reactHooks.configs.recommended.rules,
'react-refresh/only-export-components': ['warn', { allowConstantExport: true }],
},
}
);
35 changes: 16 additions & 19 deletions src/index.html → index.html

@staging-devin-ai-integration staging-devin-ai-integration Bot Jul 8, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📝 Info: Static manifest removal is consistent with vite-plugin-pwa auto-injection

The incremental change deletes public/manifest.json and removes the <link rel="manifest"> from index.html:35. This is consistent with vite.config.ts:9-31, where VitePWA is configured with an inline manifest block and thus generates manifest.webmanifest and auto-injects the manifest link at build time. Keeping the static reference would have produced a duplicate/conflicting manifest link, so removing it is the correct approach.

Open in Devin Review (Staging)

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

Debug

Playground

Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,23 @@
<head>
<meta charset="utf-8">
<title>Angular 2 HN</title>
<base href="/">

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Page logo and icons break when the site is opened directly on a nested URL

The document's root link was removed (<base href="/"> at index.html:6) while the page keeps relative asset paths, so opening the app directly on a nested address like /item/123 makes the loading logo and icons resolve against the wrong folder and fail to load.
Impact: Users who deep-link or refresh on any page other than the home page see a broken loading logo and missing favicons/touch icons.

Why relative URLs break without a base element

This is a single-page app served with index.html as the fallback for every route. The pre-loader markup still uses relative URLs, e.g. assets/images/logo.svg at index.html:55, and the icon/meta links at index.html:14,38-44 are also relative. With <base href="/"> these resolved against the site root. After its removal, on a URL such as /item/123 the browser resolves assets/images/logo.svg to /item/assets/images/logo.svg, which 404s. The Angular version kept <base href="/"> precisely to avoid this. Note the in-app Header uses absolute paths (/assets/images/logo.svg), so only the pre-React loader image and the document icons are affected.

Prompt for agents
The <base href="/"> element was removed from index.html during the Angular-to-Vite migration. Because this is an SPA whose index.html is served as the fallback for deep routes (e.g. /item/123, /user/foo), the remaining relative asset URLs in index.html (the pre-loader logo at 'assets/images/logo.svg', favicon 'favicon.ico', touch icons under 'assets/icons/...', and og/twitter image 'assets/images/logo-loading.png') now resolve relative to the current path instead of the site root, causing 404s on nested routes. Fix by either re-adding <base href="/"> in <head>, or converting these relative asset references to root-absolute paths (leading '/').
Open in Devin Review (Staging)

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

Debug

Playground


<meta name="description" content="A Hacker News client built with Angular CLI, RxJS and Webpack"/>
<meta name="description" content="A Hacker News client built with React, TypeScript and Vite"/>

<meta name="twitter:card" content="summary">
<meta name="twitter:site" content="@hdjirdeh">
<meta name="twitter:title" content="Angular 2 HN">
<meta name="twitter:description" content="A Hacker News client built with Angular CLI, RxJS and Webpack">
<meta name="twitter:creator" content="@hdjirdeh">
<meta name="twitter:image" content="assets/images/logo-loading.png">
<meta name="twitter:card" content="summary">
<meta name="twitter:site" content="@hdjirdeh">
<meta name="twitter:title" content="Angular 2 HN">
<meta name="twitter:description" content="A Hacker News client built with React, TypeScript and Vite">
<meta name="twitter:creator" content="@hdjirdeh">
<meta name="twitter:image" content="assets/images/logo-loading.png">

<meta property="og:title" content="Angular 2 HN"/>
<meta property="og:type" content="website"/>
<meta property="og:url" content="https://angular2-hn.firebaseapp.com/"/>
<meta property="og:image" content="assets/images/logo-loading.png"/>
<meta property="og:description" content="A Hacker News client built with Angular CLI, RxJS and Webpack"/>
<meta property="og:site_name" content="Angular 2 HN"/>
<meta property="fb:admins" content="10202985971279760"/>
<meta property="og:title" content="Angular 2 HN"/>
<meta property="og:type" content="website"/>
<meta property="og:url" content="https://angular2-hn.firebaseapp.com/"/>
<meta property="og:image" content="assets/images/logo-loading.png"/>
<meta property="og:description" content="A Hacker News client built with React, TypeScript and Vite"/>
<meta property="og:site_name" content="Angular 2 HN"/>
<meta property="fb:admins" content="10202985971279760"/>

<meta name="viewport" content="width=device-width, initial-scale=1">

Expand All @@ -43,17 +42,14 @@
<link rel="apple-touch-icon" sizes="180x180" href="assets/icons/apple-touch-icon.png">
<link rel="apple-touch-icon" sizes="120x120" href="assets/icons/apple-touch-icon-120x120.png">
<link rel="apple-touch-icon" sizes="152x152" href="assets/icons/apple-touch-icon-152x152.png">
<link rel="apple-touch-icon" sizes="180x180" href="assets/icons/apple-touch-icon-180x180.png">
<style>
#skip a { position:absolute; left:-10000px; top:auto; width:1px; height:1px; overflow:hidden; }
#skip a:focus { position:static; width:auto; height:auto; }
</style>
<link rel="manifest" href="manifest.webmanifest">
<meta name="theme-color" content="#1976d2">
</head>
<body>
<div id="skip"><a href="#content">skip to navigation</a></div>
<app-root></app-root>
<div id="root"></div>

<div class="app-loader" id="content">
<img class="logo" src="assets/images/logo.svg" alt="Logo">
Expand All @@ -74,5 +70,6 @@ <h4 style="font-family: 'HelveticaNeue-Light', 'Helvetica Neue Light', 'Helvetic
ga('create', 'UA-66348622-3', 'auto');

</script>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
Loading