Skip to content

Commit db4f083

Browse files
committed
feat: rebuild the site's crawlable and citable surface
The site was a single URL whose every link left the domain, so there was nothing on initphp.org to index beyond the homepage and nothing for an answer engine to cite: not one Composer package name outside the four in the terminal box, no PHP version requirements, no PSR claims, no dates. Content - Expand src/data/libraries.ts into the single source of truth for every package: slug, Composer name, wiki, Packagist URL, tagline, summary, minimum PHP, release version and date, PSR interfaces, required extensions and dependencies, all verified against Packagist and GitHub. - Derive category membership and the featured set from it; remove src/data/featured.ts and the hand-maintained repo URLs in categories.ts, which could disagree with the catalogue. - Add 27 pages under /libraries/ plus a /libraries/ hub: install command, package facts, source/docs/Packagist links and same-category related libraries. Point the homepage tiles and category lists at them, so the site finally has an internal link graph. - Add an eight-entry FAQ, rendered visibly and mirrored in FAQPage JSON-LD from the same array. Discoverability - Add @astrojs/sitemap (29 URLs, lastmod from real release dates), public/robots.txt with the sitemap and explicit content signals, a 404 page, llms.txt and llms-full.txt. - Replace the lone Organization node with an @graph: Organization, WebSite, per-page CollectionPage/WebPage, ItemList, FAQPage, BreadcrumbList and SoftwareSourceCode/SoftwareApplication per package. - Per-page titles, canonicals and og:url; description trimmed to 155 chars; robots opened up with max-image-preview:large and uncapped snippets. - Lead the h1 with the brand; promote library and featured names from divs and spans to headings. Assets - Generate the favicon set, PWA icons and a 1200x630 og-image from the master logo (scripts/generate-icons.mjs). The 348 KB, 700x700 master was serving as both the favicon and the 32x32 navbar logo, and as a square og:image behind a summary_large_image card. - Drop 1.4 MB of unreferenced logos; preload the Inter latin subset. - Fix the footer's relative license link, which 404'd on any nested page. Tests - Retire tests/parity.test.mjs and its frozen baseline: it asserted the page had not changed, which is now the opposite of the intent. - Add tests/seo.test.mjs covering headings, meta lengths, canonicals, social images, robots values, JSON-LD @id resolution, per-package facts, internal link integrity, image attributes, sitemap, robots.txt and the llms files.
1 parent d8d8e87 commit db4f083

46 files changed

Lines changed: 2931 additions & 1688 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

README.md

Lines changed: 70 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,56 @@ npm install
99
npm run dev
1010
```
1111

12+
## Content model
13+
14+
`src/data/libraries.ts` is the single source of truth for every package:
15+
name, slug, Composer name, repository, wiki, Packagist URL, description,
16+
minimum PHP version, latest version and release date, PSR interfaces,
17+
required extensions, dependencies and star count.
18+
19+
Everything else is derived from it — the homepage cards, the category
20+
lists, the 27 pages under `/libraries/`, the JSON-LD, `llms.txt`,
21+
`llms-full.txt` and the sitemap. Nothing about a package may be restated in
22+
another file, so a package cannot disagree with itself between two sections
23+
of the site.
24+
25+
- `src/data/categories.ts` holds category metadata only; membership comes
26+
from each library's `category` field.
27+
- `src/data/faq.ts` backs both the visible FAQ and its `FAQPage` JSON-LD.
28+
- `src/data/site.ts` holds the origin, titles and social identities that end
29+
up in canonicals and structured data.
30+
31+
Archived Packagist packages (`initphp/cli-table`, `curl`, `event-emitter`,
32+
`http-client`, `http-factory`, `polyfill-php80`, `redis`,
33+
`redis-session-handler`, `var-dumper`) are deliberately absent from the
34+
catalogue: they are marked abandoned upstream and must not be advertised as
35+
installable.
36+
37+
Star counts are the one number that changes without a commit:
38+
39+
```sh
40+
npm run refresh:stars # rewrites `stars:` in libraries.ts from the GitHub API
41+
```
42+
43+
## Assets
44+
45+
`public/` favicons, the PWA icons and the 1200x630 `og-image.png` are all
46+
generated from the single 700x700 master logo:
47+
48+
```sh
49+
npm run icons # scripts/generate-icons.mjs
50+
```
51+
52+
Re-run it after replacing `public/logos/initphp-icon-700.png`. Do not hand-
53+
edit the generated files.
54+
1255
## Styling conventions
1356

1457
- Two approaches exist today, split by component rather than by rule
1558
complexity: `Navbar.astro` and `Hero.astro` put Tailwind utilities on
16-
their outer markup; the other seven components (`Stats`, `FeaturedCard`,
17-
`CategoryCard`, `LibCard`, `Footer`, `Install`, `ScrollTop`) and the page
18-
section shells in `index.astro` are scoped-CSS-only, even for
19-
one-declaration rules. The codebase is not uniform.
59+
their outer markup; the other components and the page section shells are
60+
scoped-CSS-only, even for one-declaration rules. The codebase is not
61+
uniform.
2062
- For new sections, follow the majority pattern: a scoped `<style>` rule per
2163
component, named for what it styles. Reserve utilities for one-off
2264
arbitrary values on an element that doesn't need a named rule.
@@ -33,21 +75,37 @@ npm run dev
3375
## Test
3476

3577
```sh
36-
npm run build # tests/parity.test.mjs reads dist/index.html
78+
npm run build # tests/seo.test.mjs reads dist/
3779
npm test
3880
```
3981

4082
The suite has two parts:
4183

42-
- `tests/parity.test.mjs` compares the built `dist/index.html` against
43-
`tests/fixtures/baseline.html`, a frozen copy of the pre-Astro page, and fails on any
44-
change to its title, meta tags, canonical/favicon, JSON-LD, headings, anchors, images
45-
or rendered body text.
46-
- `tests/data.test.mjs` checks `src/data/*.ts` directly, independently of the build —
47-
entry counts, required fields and their types, Iconify icon id format, that every
48-
repo URL is on github.com, and uniqueness of library names and repos.
84+
- `tests/data.test.mjs` checks `src/data/*.ts` directly, independently of the
85+
build — entry counts, required fields and their types, Iconify icon id
86+
format, Composer/GitHub/Packagist URL agreement, that categories partition
87+
the catalogue exactly, and uniqueness of names, slugs, packages and repos.
88+
- `tests/seo.test.mjs` asserts the crawlable surface of `dist/`: one h1 per
89+
page and no skipped heading levels, title and meta-description lengths,
90+
per-page canonicals and `og:url`, a 1200x630 social image, `robots` values
91+
(including `noindex` on the 404), a resolvable JSON-LD `@graph` on every
92+
page, the homepage `ItemList` and `FAQPage` matching the rendered content,
93+
each library page stating its own install command and package facts, no
94+
internal link pointing at something that was not built, `alt`/`width`/
95+
`height` on every image, sitemap coverage and `lastmod` values, `robots.txt`,
96+
and `llms.txt` / `llms-full.txt` covering every package.
97+
98+
A third file, `tests/parity.test.mjs`, used to diff the build against a
99+
frozen copy of the pre-Astro page. It was retired once the page started
100+
diverging from that baseline on purpose; `tests/extract.mjs`, the HTML
101+
snapshot helper it was built around, is still used by the SEO suite.
49102

50103
## Deploy
51104

52105
Pushing to `main` builds and publishes to GitHub Pages via
53106
`.github/workflows/deploy.yml`. The custom domain comes from `public/CNAME`.
107+
108+
Repository **Settings → Pages → Source** must be set to **GitHub Actions**.
109+
With the older "Deploy from a branch" setting the workflow still reports
110+
success while Pages serves 404, because the branch root holds Astro sources
111+
rather than a built site.

astro.config.mjs

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,48 @@
11
import { defineConfig } from 'astro/config';
22
import tailwindcss from '@tailwindcss/vite';
33
import icon from 'astro-icon';
4+
import sitemap from '@astrojs/sitemap';
5+
// Astro loads this config through Vite, so the TypeScript catalogue can be
6+
// imported directly and the sitemap's lastmod can come from real release
7+
// dates instead of the build clock (which would mark all 29 URLs as changed
8+
// on every deploy, whether or not anything did).
9+
import { lastReleased, libraries } from './src/data/libraries.ts';
10+
11+
const releasedBySlug = new Map(libraries.map((lib) => [lib.slug, lib.released]));
412

513
export default defineConfig({
614
site: 'https://initphp.org',
715
output: 'static',
816
// Astro 7 defaults compressHTML to 'jsx', which strips newline-adjacent
917
// whitespace and would glue icons to their labels. Keep v6 behaviour.
1018
compressHTML: true,
11-
integrations: [icon()],
19+
integrations: [
20+
icon(),
21+
sitemap({
22+
// 404.astro is rendered as a static page by the adapter but must never
23+
// be advertised for crawling.
24+
filter: (page) => !page.includes('/404'),
25+
// The homepage is the entry point; /libraries/ is the hub for the 27
26+
// package pages, which sit one level below both.
27+
serialize(item) {
28+
const path = new URL(item.url).pathname;
29+
if (path === '/') {
30+
return { ...item, changefreq: 'weekly', priority: 1.0, lastmod: new Date(lastReleased) };
31+
}
32+
if (path === '/libraries/') {
33+
return { ...item, changefreq: 'weekly', priority: 0.9, lastmod: new Date(lastReleased) };
34+
}
35+
const slug = path.replace(/^\/libraries\/|\/$/g, '');
36+
const released = releasedBySlug.get(slug);
37+
return {
38+
...item,
39+
changefreq: 'monthly',
40+
priority: 0.8,
41+
...(released ? { lastmod: new Date(released) } : {}),
42+
};
43+
},
44+
}),
45+
],
1246
vite: {
1347
plugins: [tailwindcss()],
1448
},

package-lock.json

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

package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66
"dev": "astro dev",
77
"build": "astro build",
88
"preview": "astro preview",
9-
"test": "node --test 'tests/**/*.test.mjs'"
9+
"test": "node --test 'tests/**/*.test.mjs'",
10+
"icons": "node scripts/generate-icons.mjs",
11+
"refresh:stars": "node scripts/refresh-stars.mjs"
1012
},
1113
"devDependencies": {
1214
"@astrojs/check": "^0.9.10",
@@ -16,6 +18,7 @@
1618
"typescript": "^6.0.3"
1719
},
1820
"dependencies": {
21+
"@astrojs/sitemap": "^3.7.3",
1922
"@fontsource-variable/inter": "^5.3.0",
2023
"@fontsource-variable/jetbrains-mono": "^5.3.0",
2124
"@tailwindcss/vite": "^4.3.3",

public/apple-touch-icon.png

15.1 KB
Loading

public/favicon-16x16.png

1007 Bytes
Loading

public/favicon-32x32.png

1.8 KB
Loading

public/favicon-96x96.png

5.89 KB
Loading

public/favicon.ico

5.28 KB
Binary file not shown.

public/icon-192.png

16.7 KB
Loading

0 commit comments

Comments
 (0)