Skip to content

Commit ce06cd9

Browse files
author
Eliott Gandiolle
committed
Initial npm visualizer app setup with data pipeline, interactive dashboard, and deployment workflow.
Made-with: Cursor
0 parents  commit ce06cd9

39 files changed

+4753
-0
lines changed

.github/workflows/deploy.yml

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
name: Fetch data & deploy to GitHub Pages
2+
3+
on:
4+
push:
5+
branches: [main]
6+
schedule:
7+
- cron: '0 */6 * * *' # refresh data every 6 hours
8+
workflow_dispatch: # manual trigger from the Actions tab
9+
10+
permissions:
11+
contents: read
12+
pages: write
13+
id-token: write
14+
15+
concurrency:
16+
group: pages
17+
cancel-in-progress: true
18+
19+
jobs:
20+
deploy:
21+
runs-on: ubuntu-latest
22+
environment:
23+
name: github-pages
24+
url: ${{ steps.deploy.outputs.page_url }}
25+
26+
steps:
27+
- name: Checkout
28+
uses: actions/checkout@v4
29+
30+
- name: Setup Bun
31+
uses: oven-sh/setup-bun@v2
32+
33+
- name: Install dependencies
34+
run: bun install
35+
36+
- name: Fetch npm & GitHub data
37+
run: bun scripts/fetch-data.ts
38+
env:
39+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
40+
41+
- name: Build
42+
run: bun run build
43+
env:
44+
VITE_BASE_URL: /${{ github.event.repository.name }}/
45+
46+
- name: Configure Pages
47+
uses: actions/configure-pages@v5
48+
49+
- name: Upload artifact
50+
uses: actions/upload-pages-artifact@v3
51+
with:
52+
path: dist
53+
54+
- name: Deploy to GitHub Pages
55+
id: deploy
56+
uses: actions/deploy-pages@v4

.gitignore

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Logs
2+
logs
3+
*.log
4+
npm-debug.log*
5+
yarn-debug.log*
6+
yarn-error.log*
7+
pnpm-debug.log*
8+
lerna-debug.log*
9+
10+
node_modules
11+
dist
12+
dist-ssr
13+
*.local
14+
15+
# Editor directories and files
16+
.vscode/*
17+
!.vscode/extensions.json
18+
.idea
19+
.DS_Store
20+
*.suo
21+
*.ntvs*
22+
*.njsproj
23+
*.sln
24+
*.sw?

README.md

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
# React + TypeScript + Vite
2+
3+
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
4+
5+
Currently, two official plugins are available:
6+
7+
- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) (or [oxc](https://oxc.rs) when used in [rolldown-vite](https://vite.dev/guide/rolldown)) for Fast Refresh
8+
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
9+
10+
## React Compiler
11+
12+
The React Compiler is not enabled on this template because of its impact on dev & build performances. To add it, see [this documentation](https://react.dev/learn/react-compiler/installation).
13+
14+
## Expanding the ESLint configuration
15+
16+
If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules:
17+
18+
```js
19+
export default defineConfig([
20+
globalIgnores(['dist']),
21+
{
22+
files: ['**/*.{ts,tsx}'],
23+
extends: [
24+
// Other configs...
25+
26+
// Remove tseslint.configs.recommended and replace with this
27+
tseslint.configs.recommendedTypeChecked,
28+
// Alternatively, use this for stricter rules
29+
tseslint.configs.strictTypeChecked,
30+
// Optionally, add this for stylistic rules
31+
tseslint.configs.stylisticTypeChecked,
32+
33+
// Other configs...
34+
],
35+
languageOptions: {
36+
parserOptions: {
37+
project: ['./tsconfig.node.json', './tsconfig.app.json'],
38+
tsconfigRootDir: import.meta.dirname,
39+
},
40+
// other options...
41+
},
42+
},
43+
])
44+
```
45+
46+
You can also install [eslint-plugin-react-x](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x) and [eslint-plugin-react-dom](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-dom) for React-specific lint rules:
47+
48+
```js
49+
// eslint.config.js
50+
import reactX from 'eslint-plugin-react-x'
51+
import reactDom from 'eslint-plugin-react-dom'
52+
53+
export default defineConfig([
54+
globalIgnores(['dist']),
55+
{
56+
files: ['**/*.{ts,tsx}'],
57+
extends: [
58+
// Other configs...
59+
// Enable lint rules for React
60+
reactX.configs['recommended-typescript'],
61+
// Enable lint rules for React DOM
62+
reactDom.configs.recommended,
63+
],
64+
languageOptions: {
65+
parserOptions: {
66+
project: ['./tsconfig.node.json', './tsconfig.app.json'],
67+
tsconfigRootDir: import.meta.dirname,
68+
},
69+
// other options...
70+
},
71+
},
72+
])
73+
```

bun.lock

Lines changed: 698 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

deploy.md

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
# Deployment Guide
2+
3+
The app is a fully static site. There is no server. All data is pre-fetched at build time by a GitHub Action and baked into `public/data.json`. Users load that single file — no API calls happen in their browser.
4+
5+
---
6+
7+
## 1. Create the GitHub repository
8+
9+
```bash
10+
git init
11+
git add .
12+
git commit -m "Initial commit"
13+
14+
# Create the repo on GitHub (replace with your username/repo name)
15+
gh repo create your-username/npm-visualizer --public --source=. --push
16+
```
17+
18+
Or create the repo manually on github.com and push:
19+
20+
```bash
21+
git remote add origin https://github.com/your-username/npm-visualizer.git
22+
git push -u origin main
23+
```
24+
25+
---
26+
27+
## 2. Enable GitHub Pages
28+
29+
1. Go to your repo on GitHub → **Settings****Pages**
30+
2. Under **Source**, select **GitHub Actions**
31+
3. Save
32+
33+
That's it. The workflow handles everything else.
34+
35+
---
36+
37+
## 3. Trigger the first deployment
38+
39+
The workflow runs automatically on every push to `main`. Your initial push in step 1 will trigger it.
40+
41+
You can also trigger it manually:
42+
- Go to **Actions****Fetch data & deploy to GitHub Pages****Run workflow**
43+
44+
The workflow will:
45+
1. Fetch download stats from the npm API (last 18 months)
46+
2. Fetch package metadata from the npm registry
47+
3. Fetch GitHub star counts (authenticated via the built-in `GITHUB_TOKEN` — no setup needed)
48+
4. Write everything to `public/data.json`
49+
5. Build the Vite app
50+
6. Deploy to `https://your-username.github.io/npm-visualizer/`
51+
52+
First deploy takes ~1 minute. After that it auto-refreshes every 6 hours.
53+
54+
---
55+
56+
## 4. Customise the packages
57+
58+
Edit one file:
59+
60+
```ts
61+
// src/constants/packages.ts
62+
export const PACKAGES = [
63+
'@your-org/package-one',
64+
'@your-org/package-two',
65+
// ...
66+
] as const;
67+
```
68+
69+
Commit and push — the Action will re-fetch and redeploy automatically.
70+
71+
---
72+
73+
## Local development
74+
75+
To see real data locally, run the fetch script first:
76+
77+
```bash
78+
bun run fetch-data # writes public/data.json
79+
bun run dev # starts at http://localhost:5173
80+
```
81+
82+
Without running `fetch-data`, the app loads with empty data (skeletons).
83+
84+
---
85+
86+
## How it works
87+
88+
| Step | Where |
89+
|------|-------|
90+
| Package list | `src/constants/packages.ts` |
91+
| Data fetch script | `scripts/fetch-data.ts` |
92+
| GitHub Actions workflow | `.github/workflows/deploy.yml` |
93+
| Data refresh schedule | Every 6 hours (cron `0 */6 * * *`) |
94+
| Data served from | `public/data.json``dist/data.json` |
95+
| GitHub API auth | Auto via `secrets.GITHUB_TOKEN` (built-in, no setup) |

eslint.config.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import js from '@eslint/js'
2+
import globals from 'globals'
3+
import reactHooks from 'eslint-plugin-react-hooks'
4+
import reactRefresh from 'eslint-plugin-react-refresh'
5+
import tseslint from 'typescript-eslint'
6+
import { defineConfig, globalIgnores } from 'eslint/config'
7+
8+
export default defineConfig([
9+
globalIgnores(['dist']),
10+
{
11+
files: ['**/*.{ts,tsx}'],
12+
extends: [
13+
js.configs.recommended,
14+
tseslint.configs.recommended,
15+
reactHooks.configs.flat.recommended,
16+
reactRefresh.configs.vite,
17+
],
18+
languageOptions: {
19+
ecmaVersion: 2020,
20+
globals: globals.browser,
21+
},
22+
},
23+
])

index.html

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
7+
<title>npm-visualizer</title>
8+
</head>
9+
<body>
10+
<div id="root"></div>
11+
<script type="module" src="/src/main.tsx"></script>
12+
</body>
13+
</html>

package.json

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
{
2+
"name": "npm-visualizer",
3+
"private": true,
4+
"version": "0.0.0",
5+
"type": "module",
6+
"scripts": {
7+
"dev": "vite",
8+
"build": "tsc -b && vite build",
9+
"lint": "eslint .",
10+
"preview": "vite preview",
11+
"fetch-data": "bun scripts/fetch-data.ts"
12+
},
13+
"dependencies": {
14+
"@tanstack/react-query": "^5.90.21",
15+
"react": "^19.2.0",
16+
"react-dom": "^19.2.0",
17+
"recharts": "^3.7.0",
18+
"zustand": "^5.0.11"
19+
},
20+
"devDependencies": {
21+
"@eslint/js": "^9.39.1",
22+
"@types/node": "^24.10.1",
23+
"@types/react": "^19.2.7",
24+
"@types/react-dom": "^19.2.3",
25+
"@vitejs/plugin-react": "^5.1.1",
26+
"autoprefixer": "^10.4.27",
27+
"eslint": "^9.39.1",
28+
"eslint-plugin-react-hooks": "^7.0.1",
29+
"eslint-plugin-react-refresh": "^0.4.24",
30+
"globals": "^16.5.0",
31+
"postcss": "^8.5.8",
32+
"tailwindcss": "3",
33+
"typescript": "~5.9.3",
34+
"typescript-eslint": "^8.48.0",
35+
"vite": "^7.3.1"
36+
}
37+
}

postcss.config.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
export default {
2+
plugins: {
3+
tailwindcss: {},
4+
autoprefixer: {},
5+
},
6+
}

0 commit comments

Comments
 (0)