@earlyseo/blog 1.0.6 → 1.0.7
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 +19 -18
- package/dist/next/sitemap.d.ts +7 -3
- package/dist/next/sitemap.d.ts.map +1 -1
- package/dist/next/sitemap.js +31 -7
- package/dist/next/sitemap.js.map +1 -1
- package/package.json +1 -1
- package/src/cli/init.mjs +8 -18
package/README.md
CHANGED
|
@@ -26,8 +26,8 @@ npx @earlyseo/blog init
|
|
|
26
26
|
The CLI will detect your Next.js project, ask for your site ID, and generate:
|
|
27
27
|
- `app/blog/page.tsx` — Paginated blog listing
|
|
28
28
|
- `app/blog/[slug]/page.tsx` — Article detail with full SEO metadata
|
|
29
|
-
- `app/sitemap.ts` — Blog
|
|
30
|
-
- `.env.local` — `EARLYSEO_SITE_ID`
|
|
29
|
+
- `app/blog/sitemap.ts` — Blog sitemap at `/blog/sitemap.xml` (auto-detects base URL from Host header)
|
|
30
|
+
- `.env.local` — `EARLYSEO_SITE_ID` added automatically
|
|
31
31
|
|
|
32
32
|
That's it — run `npm run dev` and visit `/blog`.
|
|
33
33
|
|
|
@@ -79,38 +79,39 @@ export const generateMetadata = createBlogPostMetadata({ siteId, siteName: "My S
|
|
|
79
79
|
|
|
80
80
|
That's it! Articles published from EarlySEO automatically appear on your blog.
|
|
81
81
|
|
|
82
|
-
### 5. Add sitemap
|
|
82
|
+
### 5. Add blog sitemap
|
|
83
83
|
|
|
84
|
-
|
|
84
|
+
The recommended approach — a dedicated blog sitemap at `/blog/sitemap.xml`:
|
|
85
|
+
|
|
86
|
+
```tsx
|
|
87
|
+
// app/blog/sitemap.ts
|
|
88
|
+
import { createBlogSitemap } from "@earlyseo/blog/next";
|
|
89
|
+
|
|
90
|
+
const siteId = process.env.EARLYSEO_SITE_ID!;
|
|
91
|
+
|
|
92
|
+
// baseUrl is auto-detected from NEXT_PUBLIC_BASE_URL or the request Host header
|
|
93
|
+
export default createBlogSitemap({ siteId });
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Or merge blog entries into your existing `app/sitemap.ts`:
|
|
85
97
|
|
|
86
98
|
```tsx
|
|
87
99
|
import { getBlogSitemapEntries } from "@earlyseo/blog/next";
|
|
88
100
|
import type { MetadataRoute } from "next";
|
|
89
101
|
|
|
90
102
|
const siteId = process.env.EARLYSEO_SITE_ID!;
|
|
91
|
-
const baseUrl = process.env.NEXT_PUBLIC_BASE_URL ?? "https://example.com";
|
|
92
103
|
|
|
93
104
|
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
|
|
94
|
-
const blogEntries = await getBlogSitemapEntries({ siteId
|
|
105
|
+
const blogEntries = await getBlogSitemapEntries({ siteId });
|
|
95
106
|
|
|
96
107
|
return [
|
|
97
|
-
{ url:
|
|
108
|
+
{ url: "https://example.com", lastModified: new Date() },
|
|
98
109
|
...blogEntries,
|
|
99
110
|
];
|
|
100
111
|
}
|
|
101
112
|
```
|
|
102
113
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
```tsx
|
|
106
|
-
// app/blog/sitemap.ts
|
|
107
|
-
import { createBlogSitemap } from "@earlyseo/blog/next";
|
|
108
|
-
|
|
109
|
-
const siteId = process.env.EARLYSEO_SITE_ID!;
|
|
110
|
-
const baseUrl = process.env.NEXT_PUBLIC_BASE_URL ?? "https://example.com";
|
|
111
|
-
|
|
112
|
-
export default createBlogSitemap({ siteId, baseUrl });
|
|
113
|
-
```
|
|
114
|
+
`baseUrl` is resolved automatically: explicit option → `NEXT_PUBLIC_BASE_URL` env var → request `Host` header.
|
|
114
115
|
|
|
115
116
|
---
|
|
116
117
|
|
package/dist/next/sitemap.d.ts
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import type { EarlySeoConfig } from "../types";
|
|
2
2
|
export interface BlogSitemapOptions extends EarlySeoConfig {
|
|
3
|
-
/**
|
|
4
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Your site's public base URL (e.g. "https://example.com").
|
|
5
|
+
* If omitted, falls back to NEXT_PUBLIC_BASE_URL env var,
|
|
6
|
+
* then to the request Host header (via next/headers).
|
|
7
|
+
*/
|
|
8
|
+
baseUrl?: string;
|
|
5
9
|
/** Blog base path (default: "/blog") */
|
|
6
10
|
basePath?: string;
|
|
7
11
|
/** Change frequency hint for sitemap (default: "weekly") */
|
|
@@ -24,7 +28,7 @@ export interface SitemapEntry {
|
|
|
24
28
|
export declare function getBlogSitemapEntries(options: BlogSitemapOptions): Promise<SitemapEntry[]>;
|
|
25
29
|
/**
|
|
26
30
|
* Creates a Next.js App Router sitemap function that returns blog article entries.
|
|
27
|
-
* Use as the default export of `app/blog/sitemap.ts`
|
|
31
|
+
* Use as the default export of `app/blog/sitemap.ts` (serves `/blog/sitemap.xml`).
|
|
28
32
|
*/
|
|
29
33
|
export declare function createBlogSitemap(options: BlogSitemapOptions): () => Promise<SitemapEntry[]>;
|
|
30
34
|
//# sourceMappingURL=sitemap.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sitemap.d.ts","sourceRoot":"","sources":["../../src/next/sitemap.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"sitemap.d.ts","sourceRoot":"","sources":["../../src/next/sitemap.ts"],"names":[],"mappings":"AA6BA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAE/C,MAAM,WAAW,kBAAmB,SAAQ,cAAc;IACxD;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,wCAAwC;IACxC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,4DAA4D;IAC5D,eAAe,CAAC,EACZ,QAAQ,GACR,QAAQ,GACR,OAAO,GACP,QAAQ,GACR,SAAS,GACT,QAAQ,GACR,OAAO,CAAC;IACZ,qDAAqD;IACrD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,qEAAqE;IACrE,SAAS,CAAC,EAAE,WAAW,CAAC;CACzB;AAED,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,IAAI,GAAG,MAAM,CAAC;IAC7B,eAAe,CAAC,EACZ,QAAQ,GACR,QAAQ,GACR,OAAO,GACP,QAAQ,GACR,SAAS,GACT,QAAQ,GACR,OAAO,CAAC;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AA2BD;;;GAGG;AACH,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,kBAAkB,GAC1B,OAAO,CAAC,YAAY,EAAE,CAAC,CA8CzB;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,kBAAkB,SAC1B,OAAO,CAAC,YAAY,EAAE,CAAC,CAGzD"}
|
package/dist/next/sitemap.js
CHANGED
|
@@ -2,15 +2,15 @@
|
|
|
2
2
|
// @earlyseo/blog — Next.js Sitemap Helper
|
|
3
3
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
4
4
|
// Generates sitemap entries for all published blog articles.
|
|
5
|
-
// Designed for Next.js App Router `sitemap.ts` files.
|
|
5
|
+
// Designed for Next.js App Router `app/blog/sitemap.ts` files.
|
|
6
6
|
//
|
|
7
7
|
// Usage:
|
|
8
|
-
// // app/sitemap.ts
|
|
8
|
+
// // app/blog/sitemap.ts → serves /blog/sitemap.xml
|
|
9
9
|
// import { createBlogSitemap } from "@earlyseo/blog/next";
|
|
10
10
|
//
|
|
11
11
|
// const siteId = process.env.EARLYSEO_SITE_ID!;
|
|
12
|
-
//
|
|
13
|
-
//
|
|
12
|
+
// export default createBlogSitemap({ siteId });
|
|
13
|
+
// // baseUrl is auto-detected from NEXT_PUBLIC_BASE_URL or the request host
|
|
14
14
|
//
|
|
15
15
|
// // Or merge with your own sitemap entries:
|
|
16
16
|
// import { getBlogSitemapEntries } from "@earlyseo/blog/next";
|
|
@@ -18,7 +18,6 @@
|
|
|
18
18
|
// export default async function sitemap() {
|
|
19
19
|
// const blogEntries = await getBlogSitemapEntries({
|
|
20
20
|
// siteId: process.env.EARLYSEO_SITE_ID!,
|
|
21
|
-
// baseUrl: "https://example.com",
|
|
22
21
|
// });
|
|
23
22
|
// return [
|
|
24
23
|
// { url: "https://example.com", lastModified: new Date() },
|
|
@@ -27,12 +26,37 @@
|
|
|
27
26
|
// }
|
|
28
27
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
29
28
|
import { EarlySeoClient } from "../client";
|
|
29
|
+
/**
|
|
30
|
+
* Resolve the base URL from: explicit option → NEXT_PUBLIC_BASE_URL → Host header.
|
|
31
|
+
*/
|
|
32
|
+
async function resolveBaseUrl(explicit) {
|
|
33
|
+
if (explicit)
|
|
34
|
+
return explicit;
|
|
35
|
+
const envUrl = process.env.NEXT_PUBLIC_BASE_URL;
|
|
36
|
+
if (envUrl)
|
|
37
|
+
return envUrl;
|
|
38
|
+
// Fallback: read host from the incoming request via next/headers
|
|
39
|
+
try {
|
|
40
|
+
const { headers } = await import("next/headers");
|
|
41
|
+
const headerStore = await headers();
|
|
42
|
+
const host = headerStore.get("host");
|
|
43
|
+
if (host) {
|
|
44
|
+
const proto = headerStore.get("x-forwarded-proto") ?? "https";
|
|
45
|
+
return `${proto}://${host}`;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
// next/headers unavailable (e.g. build time) — fall through
|
|
50
|
+
}
|
|
51
|
+
return "https://localhost:3000";
|
|
52
|
+
}
|
|
30
53
|
/**
|
|
31
54
|
* Fetches all published blog articles and returns an array of sitemap entries.
|
|
32
55
|
* Use this when you want to merge blog entries into an existing sitemap.
|
|
33
56
|
*/
|
|
34
57
|
export async function getBlogSitemapEntries(options) {
|
|
35
|
-
const { siteId, cdnBaseUrl, baseUrl, basePath = "/blog", changeFrequency = "weekly", priority = 0.7, fetchInit, } = options;
|
|
58
|
+
const { siteId, cdnBaseUrl, baseUrl: explicitBaseUrl, basePath = "/blog", changeFrequency = "weekly", priority = 0.7, fetchInit, } = options;
|
|
59
|
+
const baseUrl = await resolveBaseUrl(explicitBaseUrl);
|
|
36
60
|
const client = new EarlySeoClient({ siteId, cdnBaseUrl }, fetchInit);
|
|
37
61
|
const entries = [];
|
|
38
62
|
const manifest = await client.getManifest();
|
|
@@ -66,7 +90,7 @@ export async function getBlogSitemapEntries(options) {
|
|
|
66
90
|
}
|
|
67
91
|
/**
|
|
68
92
|
* Creates a Next.js App Router sitemap function that returns blog article entries.
|
|
69
|
-
* Use as the default export of `app/blog/sitemap.ts`
|
|
93
|
+
* Use as the default export of `app/blog/sitemap.ts` (serves `/blog/sitemap.xml`).
|
|
70
94
|
*/
|
|
71
95
|
export function createBlogSitemap(options) {
|
|
72
96
|
return async function sitemap() {
|
package/dist/next/sitemap.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sitemap.js","sourceRoot":"","sources":["../../src/next/sitemap.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,0CAA0C;AAC1C,gFAAgF;AAChF,6DAA6D;AAC7D
|
|
1
|
+
{"version":3,"file":"sitemap.js","sourceRoot":"","sources":["../../src/next/sitemap.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/cli/init.mjs
CHANGED
|
@@ -101,23 +101,13 @@ export const generateMetadata = createBlogPostMetadata({
|
|
|
101
101
|
}
|
|
102
102
|
|
|
103
103
|
function blogSitemapPage(siteId) {
|
|
104
|
-
return `import {
|
|
105
|
-
import type { MetadataRoute } from "next";
|
|
104
|
+
return `import { createBlogSitemap } from "@earlyseo/blog/next";
|
|
106
105
|
|
|
107
106
|
const siteId = process.env.EARLYSEO_SITE_ID ?? "${siteId}";
|
|
108
|
-
const baseUrl = process.env.NEXT_PUBLIC_BASE_URL ?? "https://example.com";
|
|
109
107
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
baseUrl,
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
return [
|
|
117
|
-
{ url: baseUrl, lastModified: new Date() },
|
|
118
|
-
...blogEntries,
|
|
119
|
-
];
|
|
120
|
-
}
|
|
108
|
+
// baseUrl is auto-detected from NEXT_PUBLIC_BASE_URL or the request Host header.
|
|
109
|
+
// You can also pass it explicitly: createBlogSitemap({ siteId, baseUrl: "https://example.com" })
|
|
110
|
+
export default createBlogSitemap({ siteId });
|
|
121
111
|
`;
|
|
122
112
|
}
|
|
123
113
|
|
|
@@ -198,8 +188,8 @@ async function main() {
|
|
|
198
188
|
await writeFileSafe(listPagePath, blogListPage(siteId));
|
|
199
189
|
await writeFileSafe(postPagePath, blogPostPage(siteId));
|
|
200
190
|
|
|
201
|
-
// 5b. Generate sitemap (
|
|
202
|
-
const sitemapPath = `${
|
|
191
|
+
// 5b. Generate blog sitemap (scoped to /blog/sitemap.xml)
|
|
192
|
+
const sitemapPath = `${blogDir}/sitemap.ts`;
|
|
203
193
|
await writeFileSafe(sitemapPath, blogSitemapPage(siteId));
|
|
204
194
|
|
|
205
195
|
// 6. Add EARLYSEO_SITE_ID and NEXT_PUBLIC_BASE_URL to .env.local
|
|
@@ -229,10 +219,10 @@ async function main() {
|
|
|
229
219
|
console.log(" ✓ Setup complete! Your blog is ready at /blog");
|
|
230
220
|
console.log();
|
|
231
221
|
console.log(" Next steps:");
|
|
232
|
-
console.log(" 1.
|
|
222
|
+
console.log(" 1. Optionally set NEXT_PUBLIC_BASE_URL in .env.local (auto-detected from Host if missing)");
|
|
233
223
|
console.log(" 2. Start your dev server: npm run dev");
|
|
234
224
|
console.log(" 3. Visit: http://localhost:3000/blog");
|
|
235
|
-
console.log(" 4.
|
|
225
|
+
console.log(" 4. Blog sitemap at: http://localhost:3000/blog/sitemap.xml");
|
|
236
226
|
console.log(" 5. Publish articles from your EarlySEO dashboard");
|
|
237
227
|
console.log();
|
|
238
228
|
console.log(" Docs: https://www.npmjs.com/package/@earlyseo/blog");
|