@growth-labs/seo 0.2.2 → 0.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -0
- package/package.json +4 -2
- package/src/components/AeoHead.astro +65 -0
package/README.md
CHANGED
|
@@ -134,6 +134,11 @@ export default {
|
|
|
134
134
|
- `/podcast.xml`, `/listen.xml`
|
|
135
135
|
- `POST /_seo/revalidate` — CMS webhook target (when `onDemandRevalidation: true`)
|
|
136
136
|
|
|
137
|
+
**Head-tag component** (`<AeoHead />`):
|
|
138
|
+
- Consumers import `import AeoHead from '@growth-labs/seo/components/AeoHead.astro'` and render `<AeoHead />` inside their layout's `<head>`. Required because integrations can't directly inject arbitrary HTML into every page's `<head>`.
|
|
139
|
+
- Emits the Apple News discovery link (`<link rel="alternate" type="application/rss+xml">`) when `appleNews.discoveryLink: true`.
|
|
140
|
+
- Emits a per-page markdown twin link (`<link rel="alternate" type="text/markdown" href="<twinUrl>">`) for discoverability on prerendered HTML served by Cloudflare Assets where middleware doesn't run.
|
|
141
|
+
|
|
137
142
|
**Build-time:**
|
|
138
143
|
- Emits `.md` twins + summary twins for public items (static/both modes) under `dist/client/`.
|
|
139
144
|
- Validates hreflang reciprocity.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@growth-labs/seo",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -40,10 +40,12 @@
|
|
|
40
40
|
"./cron": {
|
|
41
41
|
"types": "./dist/cron/prune-aeo-r2.d.ts",
|
|
42
42
|
"import": "./dist/cron/prune-aeo-r2.js"
|
|
43
|
-
}
|
|
43
|
+
},
|
|
44
|
+
"./components/AeoHead.astro": "./src/components/AeoHead.astro"
|
|
44
45
|
},
|
|
45
46
|
"files": [
|
|
46
47
|
"dist",
|
|
48
|
+
"src/components",
|
|
47
49
|
"README.md"
|
|
48
50
|
],
|
|
49
51
|
"publishConfig": {
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
---
|
|
2
|
+
// Side-effect: seeds state in whatever environment Vite bundles for.
|
|
3
|
+
// Required so `getConfig()` works in the Cloudflare prerender Worker.
|
|
4
|
+
import 'virtual:growth-labs/seo/config'
|
|
5
|
+
|
|
6
|
+
// Use package self-imports (not relative ../options.js / ../state.js) because
|
|
7
|
+
// this component ships as source from src/components/ but options.ts and state.ts
|
|
8
|
+
// compile to dist/. Relative `../options.js` would resolve to the non-existent
|
|
9
|
+
// src/options.js inside the consumer's node_modules. Package specifiers route
|
|
10
|
+
// through the exports map to the compiled dist output.
|
|
11
|
+
import { getConfig, resolveAeoTwins } from '@growth-labs/seo'
|
|
12
|
+
|
|
13
|
+
export interface Props {
|
|
14
|
+
/**
|
|
15
|
+
* Override the URL this page resolves to for twin-link emission.
|
|
16
|
+
* Defaults to `Astro.url`. Useful when rendering head tags for a URL that
|
|
17
|
+
* differs from the request URL (e.g. canonicalizing away trailing slash).
|
|
18
|
+
*/
|
|
19
|
+
canonical?: URL | string
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const { canonical } = Astro.props
|
|
23
|
+
const config = getConfig()
|
|
24
|
+
const aeo = resolveAeoTwins(config.aeoTwins)
|
|
25
|
+
|
|
26
|
+
// ─── Apple News discovery link ───
|
|
27
|
+
const appleNews = config.appleNews
|
|
28
|
+
const appleNewsHref =
|
|
29
|
+
appleNews?.enabled && appleNews.discoveryLink
|
|
30
|
+
? `${config.site.replace(/\/$/, '')}${appleNews.feedPath}`
|
|
31
|
+
: null
|
|
32
|
+
|
|
33
|
+
// ─── Per-page markdown twin link (rel="alternate") ───
|
|
34
|
+
// Addresses the gap where prerendered HTML is served directly by Cloudflare
|
|
35
|
+
// Assets — middleware never runs, so the Link: HTTP header it would append
|
|
36
|
+
// is absent. Embedding a <link rel="alternate"> in <head> gives static hosts
|
|
37
|
+
// the same AEO discoverability signal as middleware-backed modes.
|
|
38
|
+
const pageUrl = (() => {
|
|
39
|
+
if (!canonical) return Astro.url.toString()
|
|
40
|
+
if (typeof canonical === 'string') return canonical
|
|
41
|
+
return canonical.toString()
|
|
42
|
+
})()
|
|
43
|
+
|
|
44
|
+
function defaultTwinUrl(url: string): string {
|
|
45
|
+
return `${url.replace(/\/+$/, '')}.md`
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const twinHref =
|
|
49
|
+
aeo && aeo.mode !== 'middleware'
|
|
50
|
+
? (aeo.twinUrl ?? defaultTwinUrl)(pageUrl)
|
|
51
|
+
: null
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
{appleNewsHref && (
|
|
55
|
+
<link
|
|
56
|
+
rel="alternate"
|
|
57
|
+
type="application/rss+xml"
|
|
58
|
+
title={`${appleNews?.channelName} on Apple News`}
|
|
59
|
+
href={appleNewsHref}
|
|
60
|
+
/>
|
|
61
|
+
)}
|
|
62
|
+
|
|
63
|
+
{twinHref && (
|
|
64
|
+
<link rel="alternate" type="text/markdown" href={twinHref} />
|
|
65
|
+
)}
|