@earlyseo/blog 1.0.5 → 1.0.6
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 +47 -3
- package/dist/next/index.d.ts +1 -0
- package/dist/next/index.d.ts.map +1 -1
- package/dist/next/index.js +2 -0
- package/dist/next/index.js.map +1 -1
- package/dist/next/sitemap.d.ts +30 -0
- package/dist/next/sitemap.d.ts.map +1 -0
- package/dist/next/sitemap.js +76 -0
- package/dist/next/sitemap.js.map +1 -0
- package/package.json +1 -1
- package/src/cli/init.mjs +38 -6
package/README.md
CHANGED
|
@@ -20,13 +20,14 @@ Articles are authored in the EarlySEO dashboard and rendered on your site. No da
|
|
|
20
20
|
|
|
21
21
|
```bash
|
|
22
22
|
npm install @earlyseo/blog
|
|
23
|
-
npx earlyseo
|
|
23
|
+
npx @earlyseo/blog init
|
|
24
24
|
```
|
|
25
25
|
|
|
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
|
-
-
|
|
29
|
+
- `app/sitemap.ts` — Blog URLs added to sitemap automatically
|
|
30
|
+
- `.env.local` — `EARLYSEO_SITE_ID` and `NEXT_PUBLIC_BASE_URL` added automatically
|
|
30
31
|
|
|
31
32
|
That's it — run `npm run dev` and visit `/blog`.
|
|
32
33
|
|
|
@@ -43,6 +44,7 @@ npm install @earlyseo/blog
|
|
|
43
44
|
```env
|
|
44
45
|
# .env.local
|
|
45
46
|
EARLYSEO_SITE_ID=your-site-id
|
|
47
|
+
NEXT_PUBLIC_BASE_URL=https://example.com
|
|
46
48
|
```
|
|
47
49
|
|
|
48
50
|
### 3. Add the blog listing page
|
|
@@ -77,6 +79,39 @@ export const generateMetadata = createBlogPostMetadata({ siteId, siteName: "My S
|
|
|
77
79
|
|
|
78
80
|
That's it! Articles published from EarlySEO automatically appear on your blog.
|
|
79
81
|
|
|
82
|
+
### 5. Add sitemap entries
|
|
83
|
+
|
|
84
|
+
If you already have an existing `app/sitemap.ts`, merge blog entries into it:
|
|
85
|
+
|
|
86
|
+
```tsx
|
|
87
|
+
import { getBlogSitemapEntries } from "@earlyseo/blog/next";
|
|
88
|
+
import type { MetadataRoute } from "next";
|
|
89
|
+
|
|
90
|
+
const siteId = process.env.EARLYSEO_SITE_ID!;
|
|
91
|
+
const baseUrl = process.env.NEXT_PUBLIC_BASE_URL ?? "https://example.com";
|
|
92
|
+
|
|
93
|
+
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
|
|
94
|
+
const blogEntries = await getBlogSitemapEntries({ siteId, baseUrl });
|
|
95
|
+
|
|
96
|
+
return [
|
|
97
|
+
{ url: baseUrl, lastModified: new Date() },
|
|
98
|
+
...blogEntries,
|
|
99
|
+
];
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Or create a dedicated blog sitemap:
|
|
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
|
+
|
|
80
115
|
---
|
|
81
116
|
|
|
82
117
|
## How It Works
|
|
@@ -280,6 +315,15 @@ interface Article {
|
|
|
280
315
|
canonicalUrl?: string;
|
|
281
316
|
version: number;
|
|
282
317
|
}
|
|
318
|
+
|
|
319
|
+
interface BlogSitemapOptions {
|
|
320
|
+
siteId: string;
|
|
321
|
+
baseUrl: string;
|
|
322
|
+
basePath?: string;
|
|
323
|
+
changeFrequency?: "always" | "hourly" | "daily" | "weekly" | "monthly" | "yearly" | "never";
|
|
324
|
+
priority?: number;
|
|
325
|
+
fetchInit?: RequestInit;
|
|
326
|
+
}
|
|
283
327
|
```
|
|
284
328
|
|
|
285
329
|
### Imports
|
|
@@ -288,7 +332,7 @@ interface Article {
|
|
|
288
332
|
|-------------|----------|
|
|
289
333
|
| `@earlyseo/blog` | `EarlySeoClient`, core types, CSS constants |
|
|
290
334
|
| `@earlyseo/blog/react` | Provider, hooks, components |
|
|
291
|
-
| `@earlyseo/blog/next` | Next.js page creators, metadata helpers |
|
|
335
|
+
| `@earlyseo/blog/next` | Next.js page creators, metadata helpers, sitemap helpers |
|
|
292
336
|
| `@earlyseo/blog/css` | `ARTICLE_CSS`, `BLOG_CSS` |
|
|
293
337
|
|
|
294
338
|
---
|
package/dist/next/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { createBlogListPage, type BlogListPageOptions } from "./blog-list-page";
|
|
2
2
|
export { createBlogPostPage, createBlogPostMetadata, createBlogListMetadata, type BlogPostPageOptions, } from "./blog-post-page";
|
|
3
3
|
export { BackLink } from "./back-link";
|
|
4
|
+
export { createBlogSitemap, getBlogSitemapEntries, type BlogSitemapOptions, type SitemapEntry, } from "./sitemap";
|
|
4
5
|
export { EarlySeoClient } from "../client";
|
|
5
6
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/next/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/next/index.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,kBAAkB,EAAE,KAAK,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAChF,OAAO,EACL,kBAAkB,EAClB,sBAAsB,EACtB,sBAAsB,EACtB,KAAK,mBAAmB,GACzB,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAGvC,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/next/index.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,kBAAkB,EAAE,KAAK,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAChF,OAAO,EACL,kBAAkB,EAClB,sBAAsB,EACtB,sBAAsB,EACtB,KAAK,mBAAmB,GACzB,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAGvC,OAAO,EACL,iBAAiB,EACjB,qBAAqB,EACrB,KAAK,kBAAkB,EACvB,KAAK,YAAY,GAClB,MAAM,WAAW,CAAC;AAGnB,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC"}
|
package/dist/next/index.js
CHANGED
|
@@ -6,6 +6,8 @@ export { createBlogListPage } from "./blog-list-page";
|
|
|
6
6
|
export { createBlogPostPage, createBlogPostMetadata, createBlogListMetadata, } from "./blog-post-page";
|
|
7
7
|
// Client components
|
|
8
8
|
export { BackLink } from "./back-link";
|
|
9
|
+
// Sitemap
|
|
10
|
+
export { createBlogSitemap, getBlogSitemapEntries, } from "./sitemap";
|
|
9
11
|
// Re-export client for convenience
|
|
10
12
|
export { EarlySeoClient } from "../client";
|
|
11
13
|
//# sourceMappingURL=index.js.map
|
package/dist/next/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/next/index.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,mCAAmC;AACnC,gFAAgF;AAEhF,yBAAyB;AACzB,OAAO,EAAE,kBAAkB,EAA4B,MAAM,kBAAkB,CAAC;AAChF,OAAO,EACL,kBAAkB,EAClB,sBAAsB,EACtB,sBAAsB,GAEvB,MAAM,kBAAkB,CAAC;AAE1B,oBAAoB;AACpB,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEvC,mCAAmC;AACnC,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/next/index.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,mCAAmC;AACnC,gFAAgF;AAEhF,yBAAyB;AACzB,OAAO,EAAE,kBAAkB,EAA4B,MAAM,kBAAkB,CAAC;AAChF,OAAO,EACL,kBAAkB,EAClB,sBAAsB,EACtB,sBAAsB,GAEvB,MAAM,kBAAkB,CAAC;AAE1B,oBAAoB;AACpB,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEvC,UAAU;AACV,OAAO,EACL,iBAAiB,EACjB,qBAAqB,GAGtB,MAAM,WAAW,CAAC;AAEnB,mCAAmC;AACnC,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { EarlySeoConfig } from "../types";
|
|
2
|
+
export interface BlogSitemapOptions extends EarlySeoConfig {
|
|
3
|
+
/** Your site's public base URL (e.g. "https://example.com") */
|
|
4
|
+
baseUrl: string;
|
|
5
|
+
/** Blog base path (default: "/blog") */
|
|
6
|
+
basePath?: string;
|
|
7
|
+
/** Change frequency hint for sitemap (default: "weekly") */
|
|
8
|
+
changeFrequency?: "always" | "hourly" | "daily" | "weekly" | "monthly" | "yearly" | "never";
|
|
9
|
+
/** Priority hint for blog articles (default: 0.7) */
|
|
10
|
+
priority?: number;
|
|
11
|
+
/** Additional fetch options (e.g. `{ next: { revalidate: 60 } }`) */
|
|
12
|
+
fetchInit?: RequestInit;
|
|
13
|
+
}
|
|
14
|
+
export interface SitemapEntry {
|
|
15
|
+
url: string;
|
|
16
|
+
lastModified?: Date | string;
|
|
17
|
+
changeFrequency?: "always" | "hourly" | "daily" | "weekly" | "monthly" | "yearly" | "never";
|
|
18
|
+
priority?: number;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Fetches all published blog articles and returns an array of sitemap entries.
|
|
22
|
+
* Use this when you want to merge blog entries into an existing sitemap.
|
|
23
|
+
*/
|
|
24
|
+
export declare function getBlogSitemapEntries(options: BlogSitemapOptions): Promise<SitemapEntry[]>;
|
|
25
|
+
/**
|
|
26
|
+
* Creates a Next.js App Router sitemap function that returns blog article entries.
|
|
27
|
+
* Use as the default export of `app/blog/sitemap.ts` or merge into `app/sitemap.ts`.
|
|
28
|
+
*/
|
|
29
|
+
export declare function createBlogSitemap(options: BlogSitemapOptions): () => Promise<SitemapEntry[]>;
|
|
30
|
+
//# sourceMappingURL=sitemap.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sitemap.d.ts","sourceRoot":"","sources":["../../src/next/sitemap.ts"],"names":[],"mappings":"AA8BA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAE/C,MAAM,WAAW,kBAAmB,SAAQ,cAAc;IACxD,+DAA+D;IAC/D,OAAO,EAAE,MAAM,CAAC;IAChB,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;AAED;;;GAGG;AACH,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,kBAAkB,GAC1B,OAAO,CAAC,YAAY,EAAE,CAAC,CA6CzB;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,kBAAkB,SAC1B,OAAO,CAAC,YAAY,EAAE,CAAC,CAGzD"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
2
|
+
// @earlyseo/blog — Next.js Sitemap Helper
|
|
3
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
4
|
+
// Generates sitemap entries for all published blog articles.
|
|
5
|
+
// Designed for Next.js App Router `sitemap.ts` files.
|
|
6
|
+
//
|
|
7
|
+
// Usage:
|
|
8
|
+
// // app/sitemap.ts (or app/blog/sitemap.ts)
|
|
9
|
+
// import { createBlogSitemap } from "@earlyseo/blog/next";
|
|
10
|
+
//
|
|
11
|
+
// const siteId = process.env.EARLYSEO_SITE_ID!;
|
|
12
|
+
// const blogSitemap = createBlogSitemap({ siteId, baseUrl: "https://example.com" });
|
|
13
|
+
// export default blogSitemap;
|
|
14
|
+
//
|
|
15
|
+
// // Or merge with your own sitemap entries:
|
|
16
|
+
// import { getBlogSitemapEntries } from "@earlyseo/blog/next";
|
|
17
|
+
//
|
|
18
|
+
// export default async function sitemap() {
|
|
19
|
+
// const blogEntries = await getBlogSitemapEntries({
|
|
20
|
+
// siteId: process.env.EARLYSEO_SITE_ID!,
|
|
21
|
+
// baseUrl: "https://example.com",
|
|
22
|
+
// });
|
|
23
|
+
// return [
|
|
24
|
+
// { url: "https://example.com", lastModified: new Date() },
|
|
25
|
+
// ...blogEntries,
|
|
26
|
+
// ];
|
|
27
|
+
// }
|
|
28
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
29
|
+
import { EarlySeoClient } from "../client";
|
|
30
|
+
/**
|
|
31
|
+
* Fetches all published blog articles and returns an array of sitemap entries.
|
|
32
|
+
* Use this when you want to merge blog entries into an existing sitemap.
|
|
33
|
+
*/
|
|
34
|
+
export async function getBlogSitemapEntries(options) {
|
|
35
|
+
const { siteId, cdnBaseUrl, baseUrl, basePath = "/blog", changeFrequency = "weekly", priority = 0.7, fetchInit, } = options;
|
|
36
|
+
const client = new EarlySeoClient({ siteId, cdnBaseUrl }, fetchInit);
|
|
37
|
+
const entries = [];
|
|
38
|
+
const manifest = await client.getManifest();
|
|
39
|
+
if (!manifest)
|
|
40
|
+
return entries;
|
|
41
|
+
const normalizedBase = baseUrl.replace(/\/+$/, "");
|
|
42
|
+
const normalizedPath = basePath.replace(/\/+$/, "");
|
|
43
|
+
// Add the blog list page itself
|
|
44
|
+
entries.push({
|
|
45
|
+
url: `${normalizedBase}${normalizedPath}`,
|
|
46
|
+
lastModified: manifest.updatedAt,
|
|
47
|
+
changeFrequency,
|
|
48
|
+
priority: priority - 0.1,
|
|
49
|
+
});
|
|
50
|
+
// Fetch all list pages to gather every article slug
|
|
51
|
+
const totalPages = manifest.totalPages;
|
|
52
|
+
for (let page = 1; page <= totalPages; page++) {
|
|
53
|
+
const listPage = await client.getListPage(page);
|
|
54
|
+
if (!listPage)
|
|
55
|
+
continue;
|
|
56
|
+
for (const article of listPage.articles) {
|
|
57
|
+
entries.push({
|
|
58
|
+
url: `${normalizedBase}${normalizedPath}/${article.slug}`,
|
|
59
|
+
lastModified: article.createdAt,
|
|
60
|
+
changeFrequency,
|
|
61
|
+
priority,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return entries;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Creates a Next.js App Router sitemap function that returns blog article entries.
|
|
69
|
+
* Use as the default export of `app/blog/sitemap.ts` or merge into `app/sitemap.ts`.
|
|
70
|
+
*/
|
|
71
|
+
export function createBlogSitemap(options) {
|
|
72
|
+
return async function sitemap() {
|
|
73
|
+
return getBlogSitemapEntries(options);
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=sitemap.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sitemap.js","sourceRoot":"","sources":["../../src/next/sitemap.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,0CAA0C;AAC1C,gFAAgF;AAChF,6DAA6D;AAC7D,sDAAsD;AACtD,EAAE;AACF,SAAS;AACT,gDAAgD;AAChD,6DAA6D;AAC7D,EAAE;AACF,kDAAkD;AAClD,uFAAuF;AACvF,gCAAgC;AAChC,EAAE;AACF,+CAA+C;AAC/C,iEAAiE;AACjE,EAAE;AACF,8CAA8C;AAC9C,wDAAwD;AACxD,+CAA+C;AAC/C,wCAAwC;AACxC,UAAU;AACV,eAAe;AACf,kEAAkE;AAClE,wBAAwB;AACxB,SAAS;AACT,MAAM;AACN,gFAAgF;AAEhF,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAqC3C;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,OAA2B;IAE3B,MAAM,EACJ,MAAM,EACN,UAAU,EACV,OAAO,EACP,QAAQ,GAAG,OAAO,EAClB,eAAe,GAAG,QAAQ,EAC1B,QAAQ,GAAG,GAAG,EACd,SAAS,GACV,GAAG,OAAO,CAAC;IAEZ,MAAM,MAAM,GAAG,IAAI,cAAc,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,EAAE,SAAS,CAAC,CAAC;IACrE,MAAM,OAAO,GAAmB,EAAE,CAAC;IAEnC,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,WAAW,EAAE,CAAC;IAC5C,IAAI,CAAC,QAAQ;QAAE,OAAO,OAAO,CAAC;IAE9B,MAAM,cAAc,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACnD,MAAM,cAAc,GAAG,QAAQ,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAEpD,gCAAgC;IAChC,OAAO,CAAC,IAAI,CAAC;QACX,GAAG,EAAE,GAAG,cAAc,GAAG,cAAc,EAAE;QACzC,YAAY,EAAE,QAAQ,CAAC,SAAS;QAChC,eAAe;QACf,QAAQ,EAAE,QAAQ,GAAG,GAAG;KACzB,CAAC,CAAC;IAEH,oDAAoD;IACpD,MAAM,UAAU,GAAG,QAAQ,CAAC,UAAU,CAAC;IACvC,KAAK,IAAI,IAAI,GAAG,CAAC,EAAE,IAAI,IAAI,UAAU,EAAE,IAAI,EAAE,EAAE,CAAC;QAC9C,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;QAChD,IAAI,CAAC,QAAQ;YAAE,SAAS;QAExB,KAAK,MAAM,OAAO,IAAI,QAAQ,CAAC,QAAQ,EAAE,CAAC;YACxC,OAAO,CAAC,IAAI,CAAC;gBACX,GAAG,EAAE,GAAG,cAAc,GAAG,cAAc,IAAI,OAAO,CAAC,IAAI,EAAE;gBACzD,YAAY,EAAE,OAAO,CAAC,SAAS;gBAC/B,eAAe;gBACf,QAAQ;aACT,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,OAA2B;IAC3D,OAAO,KAAK,UAAU,OAAO;QAC3B,OAAO,qBAAqB,CAAC,OAAO,CAAC,CAAC;IACxC,CAAC,CAAC;AACJ,CAAC"}
|
package/package.json
CHANGED
package/src/cli/init.mjs
CHANGED
|
@@ -100,6 +100,27 @@ export const generateMetadata = createBlogPostMetadata({
|
|
|
100
100
|
`;
|
|
101
101
|
}
|
|
102
102
|
|
|
103
|
+
function blogSitemapPage(siteId) {
|
|
104
|
+
return `import { getBlogSitemapEntries } from "@earlyseo/blog/next";
|
|
105
|
+
import type { MetadataRoute } from "next";
|
|
106
|
+
|
|
107
|
+
const siteId = process.env.EARLYSEO_SITE_ID ?? "${siteId}";
|
|
108
|
+
const baseUrl = process.env.NEXT_PUBLIC_BASE_URL ?? "https://example.com";
|
|
109
|
+
|
|
110
|
+
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
|
|
111
|
+
const blogEntries = await getBlogSitemapEntries({
|
|
112
|
+
siteId,
|
|
113
|
+
baseUrl,
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
return [
|
|
117
|
+
{ url: baseUrl, lastModified: new Date() },
|
|
118
|
+
...blogEntries,
|
|
119
|
+
];
|
|
120
|
+
}
|
|
121
|
+
`;
|
|
122
|
+
}
|
|
123
|
+
|
|
103
124
|
// ── Main ─────────────────────────────────────────────────────────────────────
|
|
104
125
|
|
|
105
126
|
async function main() {
|
|
@@ -177,9 +198,14 @@ async function main() {
|
|
|
177
198
|
await writeFileSafe(listPagePath, blogListPage(siteId));
|
|
178
199
|
await writeFileSafe(postPagePath, blogPostPage(siteId));
|
|
179
200
|
|
|
180
|
-
//
|
|
201
|
+
// 5b. Generate sitemap (at app root)
|
|
202
|
+
const sitemapPath = `${appDir}/sitemap.ts`;
|
|
203
|
+
await writeFileSafe(sitemapPath, blogSitemapPage(siteId));
|
|
204
|
+
|
|
205
|
+
// 6. Add EARLYSEO_SITE_ID and NEXT_PUBLIC_BASE_URL to .env.local
|
|
181
206
|
const envPath = path.join(cwd, ".env.local");
|
|
182
207
|
const envKey = "EARLYSEO_SITE_ID";
|
|
208
|
+
const baseUrlKey = "NEXT_PUBLIC_BASE_URL";
|
|
183
209
|
if (fs.existsSync(envPath)) {
|
|
184
210
|
const envContent = fs.readFileSync(envPath, "utf-8");
|
|
185
211
|
if (envContent.includes(envKey)) {
|
|
@@ -188,9 +214,13 @@ async function main() {
|
|
|
188
214
|
fs.appendFileSync(envPath, `\n# EarlySEO Blog SDK\n${envKey}=${siteId}\n`);
|
|
189
215
|
console.log(` ✅ Added ${envKey} to .env.local`);
|
|
190
216
|
}
|
|
217
|
+
if (!envContent.includes(baseUrlKey)) {
|
|
218
|
+
fs.appendFileSync(envPath, `${baseUrlKey}=https://example.com\n`);
|
|
219
|
+
console.log(` ✅ Added ${baseUrlKey} to .env.local (update with your site URL)`);
|
|
220
|
+
}
|
|
191
221
|
} else {
|
|
192
|
-
fs.writeFileSync(envPath, `# EarlySEO Blog SDK\n${envKey}=${siteId}\n`, "utf-8");
|
|
193
|
-
console.log(` ✅ Created .env.local with ${envKey}`);
|
|
222
|
+
fs.writeFileSync(envPath, `# EarlySEO Blog SDK\n${envKey}=${siteId}\n${baseUrlKey}=https://example.com\n`, "utf-8");
|
|
223
|
+
console.log(` ✅ Created .env.local with ${envKey} and ${baseUrlKey}`);
|
|
194
224
|
}
|
|
195
225
|
|
|
196
226
|
// 7. Done
|
|
@@ -199,9 +229,11 @@ async function main() {
|
|
|
199
229
|
console.log(" ✓ Setup complete! Your blog is ready at /blog");
|
|
200
230
|
console.log();
|
|
201
231
|
console.log(" Next steps:");
|
|
202
|
-
console.log(" 1.
|
|
203
|
-
console.log(" 2.
|
|
204
|
-
console.log(" 3.
|
|
232
|
+
console.log(" 1. Update NEXT_PUBLIC_BASE_URL in .env.local with your site URL");
|
|
233
|
+
console.log(" 2. Start your dev server: npm run dev");
|
|
234
|
+
console.log(" 3. Visit: http://localhost:3000/blog");
|
|
235
|
+
console.log(" 4. Sitemap available at: http://localhost:3000/sitemap.xml");
|
|
236
|
+
console.log(" 5. Publish articles from your EarlySEO dashboard");
|
|
205
237
|
console.log();
|
|
206
238
|
console.log(" Docs: https://www.npmjs.com/package/@earlyseo/blog");
|
|
207
239
|
console.log();
|