next-staticblog 0.2.0-beta.2 → 0.2.0-beta.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/LICENSE +1 -1
- package/README-zh.md +298 -0
- package/README.md +260 -3
- package/dist/index.d.ts +4 -4
- package/dist/index.js +1748 -20
- package/index.ts +69 -28
- package/package.json +34 -29
- package/tests/fixtures/custom-posts/custom.md +6 -6
- package/tests/fixtures/posts/hello-world.md +6 -6
- package/tests/fixtures/posts/second-post.md +9 -9
- package/tests/index.test.ts +252 -157
- package/tsconfig.json +14 -14
- package/tsdown.config.ts +10 -0
package/LICENSE
CHANGED
package/README-zh.md
ADDED
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
# next-posts
|
|
2
|
+
|
|
3
|
+
> 載入文章並將 YAML 解析到 Next.js 中!
|
|
4
|
+
|
|
5
|
+
一個輕量、零依賴的 TypeScript 函式庫,用於在 Next.js 中建立靜態部落格等文章頁面。它會解析包含 YAML frontmatter 的 Markdown 檔案,並提供簡潔的工具函式,方便搭配 SSG(Static Site Generation)使用。
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 功能特色
|
|
10
|
+
|
|
11
|
+
- 零執行期依賴 —— 僅使用 Node.js 內建模組
|
|
12
|
+
- 完整 TypeScript 支援(支援泛型 metadata)
|
|
13
|
+
- 支援任意目錄結構
|
|
14
|
+
- 同時支援 `slug` 與 `slug.md` 輸入格式
|
|
15
|
+
- 相容 Next.js App Router 與 Pages Router
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## 安裝
|
|
20
|
+
|
|
21
|
+
使用 npm 或你喜歡的套件管理工具。
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm install next-posts
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## 快速開始
|
|
30
|
+
|
|
31
|
+
在專案根目錄建立 `posts/` 資料夾,並放入 Markdown 檔案:
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
my-next-app/
|
|
35
|
+
└── posts/
|
|
36
|
+
├── hello-world.md
|
|
37
|
+
└── getting-started.md
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
每個檔案應包含 YAML frontmatter 區塊與文章內容:
|
|
41
|
+
|
|
42
|
+
```markdown
|
|
43
|
+
---
|
|
44
|
+
title: Hello World
|
|
45
|
+
date: 2024-01-01
|
|
46
|
+
tags:
|
|
47
|
+
- blog
|
|
48
|
+
- intro
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
Welcome to my blog!
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
接著在 Next.js 中使用:
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
import { getAllPosts, getPostBySlug, getAllPostParams } from "next-posts";
|
|
58
|
+
|
|
59
|
+
interface PostMeta {
|
|
60
|
+
title: string;
|
|
61
|
+
date: string;
|
|
62
|
+
tags?: string[];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// 取得所有文章
|
|
66
|
+
const posts = getAllPosts<PostMeta>();
|
|
67
|
+
|
|
68
|
+
// 取得單篇文章
|
|
69
|
+
const post = getPostBySlug<PostMeta>("hello-world");
|
|
70
|
+
|
|
71
|
+
// 產生靜態路徑(Next.js)
|
|
72
|
+
const paths = getAllPostParams();
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## API
|
|
78
|
+
|
|
79
|
+
### `getAllPosts<T>(directory?)`
|
|
80
|
+
|
|
81
|
+
回傳指定目錄中的所有文章,包含解析後的 frontmatter 與內容。
|
|
82
|
+
|
|
83
|
+
```ts
|
|
84
|
+
const posts = getAllPosts<PostMeta>();
|
|
85
|
+
// [
|
|
86
|
+
// { slug: 'hello-world', metadata: { title: '...' }, content: '...' },
|
|
87
|
+
// ...
|
|
88
|
+
// ]
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
| 參數 | 型別 | 預設值 | 說明 |
|
|
92
|
+
| ----------- | -------- | ---------- | ----------------------------- |
|
|
93
|
+
| `directory` | `string` | `"posts/"` | 相對於 `process.cwd()` 的路徑 |
|
|
94
|
+
|
|
95
|
+
**回傳型別:**
|
|
96
|
+
`Array<{ slug: string; metadata: T; content: string }>`
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
### `getPostBySlug<T>(slug, directory?)`
|
|
101
|
+
|
|
102
|
+
依據 slug 取得單篇文章。支援帶或不帶 `.md` 副檔名。
|
|
103
|
+
|
|
104
|
+
```ts
|
|
105
|
+
const post = getPostBySlug<PostMeta>("hello-world");
|
|
106
|
+
// {
|
|
107
|
+
// slug: 'hello-world',
|
|
108
|
+
// metadata: { title: 'Hello World', ... },
|
|
109
|
+
// content: '...'
|
|
110
|
+
// }
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
| 參數 | 型別 | 預設值 | 說明 |
|
|
114
|
+
| ----------- | -------- | ---------- | ----------------------------- |
|
|
115
|
+
| `slug` | `string` | — | 檔名(可含或不含 `.md`) |
|
|
116
|
+
| `directory` | `string` | `"posts/"` | 相對於 `process.cwd()` 的路徑 |
|
|
117
|
+
|
|
118
|
+
**回傳型別:**
|
|
119
|
+
`{ slug: string; metadata: T; content: string }`
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
### `getAllPostSlugs(directory?)`
|
|
124
|
+
|
|
125
|
+
回傳指定目錄中的原始檔名(包含 `.md` 副檔名)。
|
|
126
|
+
|
|
127
|
+
```ts
|
|
128
|
+
const slugs = getAllPostSlugs();
|
|
129
|
+
// ['hello-world.md', 'getting-started.md']
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
| 參數 | 型別 | 預設值 | 說明 |
|
|
133
|
+
| ----------- | -------- | ---------- | ----------------------------- |
|
|
134
|
+
| `directory` | `string` | `"posts/"` | 相對於 `process.cwd()` 的路徑 |
|
|
135
|
+
|
|
136
|
+
**回傳型別:**
|
|
137
|
+
`string[]`
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
### `getAllPostParams(directory?)`
|
|
142
|
+
|
|
143
|
+
回傳適用於 Next.js `generateStaticParams` 或 `getStaticPaths` 的 slug 參數物件,會自動移除 `.md` 副檔名。
|
|
144
|
+
|
|
145
|
+
```ts
|
|
146
|
+
const params = getAllPostParams();
|
|
147
|
+
// [{ slug: 'hello-world' }, { slug: 'getting-started' }]
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
| 參數 | 型別 | 預設值 | 說明 |
|
|
151
|
+
| ----------- | -------- | ---------- | ----------------------------- |
|
|
152
|
+
| `directory` | `string` | `"posts/"` | 相對於 `process.cwd()` 的路徑 |
|
|
153
|
+
|
|
154
|
+
**回傳型別:**
|
|
155
|
+
`Array<{ slug: string }>`
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
### `parseFrontmatter(input)`
|
|
160
|
+
|
|
161
|
+
解析原始 Markdown 字串並提取 YAML frontmatter。適用於非從檔案系統讀取的 Markdown,或需要較底層控制時使用。
|
|
162
|
+
|
|
163
|
+
```ts
|
|
164
|
+
import { parseFrontmatter } from "next-posts";
|
|
165
|
+
|
|
166
|
+
const raw = `---
|
|
167
|
+
title: Hello World
|
|
168
|
+
date: 2024-01-01
|
|
169
|
+
tags:
|
|
170
|
+
- blog
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
Welcome to my blog!`;
|
|
174
|
+
|
|
175
|
+
const { data, content } = parseFrontmatter(raw);
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
- `data`:解析後的 YAML frontmatter 物件,若無有效 frontmatter 則為 `{}`。
|
|
179
|
+
- `content`:移除 frontmatter 後的 Markdown 內容。
|
|
180
|
+
|
|
181
|
+
| 參數 | 型別 | 說明 |
|
|
182
|
+
| ------- | -------- | -------------------------------- |
|
|
183
|
+
| `input` | `string` | 含有 frontmatter 的原始 Markdown |
|
|
184
|
+
|
|
185
|
+
**回傳型別:**
|
|
186
|
+
`{ data: Record<string, unknown>; content: string }`
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## 搭配 Next.js 使用
|
|
191
|
+
|
|
192
|
+
### App Router
|
|
193
|
+
|
|
194
|
+
```ts
|
|
195
|
+
// app/blog/[slug]/page.tsx
|
|
196
|
+
import { getAllPostParams, getPostBySlug } from 'next-posts';
|
|
197
|
+
|
|
198
|
+
interface PostMeta {
|
|
199
|
+
title: string;
|
|
200
|
+
date: string;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
export function generateStaticParams() {
|
|
204
|
+
return getAllPostParams();
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
export default function BlogPost({ params }: { params: { slug: string } }) {
|
|
208
|
+
const { metadata, content } = getPostBySlug<PostMeta>(params.slug);
|
|
209
|
+
|
|
210
|
+
return (
|
|
211
|
+
<article>
|
|
212
|
+
<h1>{metadata.title}</h1>
|
|
213
|
+
<p>{metadata.date}</p>
|
|
214
|
+
<div dangerouslySetInnerHTML={{ __html: content }} />
|
|
215
|
+
</article>
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
### Pages Router
|
|
223
|
+
|
|
224
|
+
```ts
|
|
225
|
+
// pages/blog/[slug].tsx
|
|
226
|
+
import { GetStaticPaths, GetStaticProps } from "next";
|
|
227
|
+
import { getAllPostParams, getPostBySlug } from "next-posts";
|
|
228
|
+
|
|
229
|
+
interface PostMeta {
|
|
230
|
+
title: string;
|
|
231
|
+
date: string;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
export const getStaticPaths: GetStaticPaths = () => ({
|
|
235
|
+
paths: getAllPostParams().map(({ slug }) => ({ params: { slug } })),
|
|
236
|
+
fallback: false,
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
export const getStaticProps: GetStaticProps = ({ params }) => {
|
|
240
|
+
const post = getPostBySlug<PostMeta>(params!.slug as string);
|
|
241
|
+
return { props: { post } };
|
|
242
|
+
};
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
## 自訂文章目錄
|
|
248
|
+
|
|
249
|
+
所有函式皆支援傳入自訂目錄:
|
|
250
|
+
|
|
251
|
+
```ts
|
|
252
|
+
const posts = getAllPosts("content/articles/");
|
|
253
|
+
const post = getPostBySlug("my-article", "content/articles/");
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
---
|
|
257
|
+
|
|
258
|
+
## 從 v0.x 版本遷移
|
|
259
|
+
|
|
260
|
+
遷移過程很容易,因為大部分的 API 都保持兼容。
|
|
261
|
+
|
|
262
|
+
1. 變更套件名稱:
|
|
263
|
+
|
|
264
|
+
`next-posts` 過去稱為 `next-staticblog` ,你可以直接替換套件名稱並指向最新版本。舊的套件將棄用並不再進行維護。
|
|
265
|
+
|
|
266
|
+
2. 明確的型別:
|
|
267
|
+
|
|
268
|
+
在 `v0.x` 版本中使用 `any` 來定義 `metadata`,在 `v1.x` 版本中改為使用 `unknown` 來提升安全性。
|
|
269
|
+
請閱讀文檔瞭解如何傳入泛型,擁有安全的型別。
|
|
270
|
+
|
|
271
|
+
除此之外套件移除了 `gray-matter` 並改用 `@std/yaml` 進行解析。雖然變更通過了所有的測試,但仍然可能在部分非標準用法上有細微差異。
|
|
272
|
+
|
|
273
|
+
---
|
|
274
|
+
|
|
275
|
+
## 貢獻
|
|
276
|
+
|
|
277
|
+
你可以透過回報問題或提交新功能完善這個套件!
|
|
278
|
+
|
|
279
|
+
```bash
|
|
280
|
+
# 安裝依賴
|
|
281
|
+
npm install
|
|
282
|
+
|
|
283
|
+
# 建置
|
|
284
|
+
npm run build
|
|
285
|
+
|
|
286
|
+
# 執行測試
|
|
287
|
+
npm test
|
|
288
|
+
|
|
289
|
+
# 格式化程式碼
|
|
290
|
+
npm run format
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
---
|
|
294
|
+
|
|
295
|
+
## 授權
|
|
296
|
+
|
|
297
|
+
MIT © yd-tw
|
|
298
|
+
[https://github.com/yd-tw/next-posts](https://github.com/yd-tw/next-posts)
|
package/README.md
CHANGED
|
@@ -1,3 +1,260 @@
|
|
|
1
|
-
# next-staticblog
|
|
2
|
-
|
|
3
|
-
Quickly configure the markdown component in
|
|
1
|
+
# next-staticblog
|
|
2
|
+
|
|
3
|
+
> Quickly configure the markdown component in a Next.js project and create a blog page!
|
|
4
|
+
|
|
5
|
+
A lightweight, zero-runtime-dependency TypeScript library for building static blogs in Next.js. It parses markdown files with YAML frontmatter and provides simple utilities to retrieve posts for use with static site generation (SSG).
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- Zero runtime dependencies — uses Node.js built-ins only
|
|
10
|
+
- Full TypeScript support with generic metadata types
|
|
11
|
+
- Works with any directory structure
|
|
12
|
+
- Handles both `slug` and `slug.md` inputs transparently
|
|
13
|
+
- Compatible with Next.js App Router and Pages Router
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install next-staticblog
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
pnpm add next-staticblog
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
yarn add next-staticblog
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Quick Start
|
|
30
|
+
|
|
31
|
+
Place your markdown files in a `posts/` directory at the project root:
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
my-next-app/
|
|
35
|
+
└── posts/
|
|
36
|
+
├── hello-world.md
|
|
37
|
+
└── getting-started.md
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Each file should contain a YAML frontmatter block followed by the post content:
|
|
41
|
+
|
|
42
|
+
```markdown
|
|
43
|
+
---
|
|
44
|
+
title: Hello World
|
|
45
|
+
date: 2024-01-01
|
|
46
|
+
tags:
|
|
47
|
+
- blog
|
|
48
|
+
- intro
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
Welcome to my blog!
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Then use the library in your Next.js pages:
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
import { getAllPosts, getPostBySlug, getAllPostParams } from "next-staticblog";
|
|
58
|
+
|
|
59
|
+
interface PostMeta {
|
|
60
|
+
title: string;
|
|
61
|
+
date: string;
|
|
62
|
+
tags?: string[];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Get all posts
|
|
66
|
+
const posts = getAllPosts<PostMeta>();
|
|
67
|
+
|
|
68
|
+
// Get a single post
|
|
69
|
+
const post = getPostBySlug<PostMeta>("hello-world");
|
|
70
|
+
|
|
71
|
+
// Generate static paths (Next.js)
|
|
72
|
+
const paths = getAllPostParams();
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## API
|
|
76
|
+
|
|
77
|
+
### `getAllPosts<T>(directory?)`
|
|
78
|
+
|
|
79
|
+
Returns all posts from the specified directory, each with parsed frontmatter and content.
|
|
80
|
+
|
|
81
|
+
```typescript
|
|
82
|
+
const posts = getAllPosts<PostMeta>();
|
|
83
|
+
// [{ slug: 'hello-world', metadata: { title: '...' }, content: '...' }, ...]
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
| Parameter | Type | Default | Description |
|
|
87
|
+
| ----------- | -------- | ---------- | -------------------------------- |
|
|
88
|
+
| `directory` | `string` | `"posts/"` | Path relative to `process.cwd()` |
|
|
89
|
+
|
|
90
|
+
**Returns:** `Array<{ slug: string; metadata: T; content: string }>`
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
### `getPostBySlug<T>(slug, directory?)`
|
|
95
|
+
|
|
96
|
+
Returns a single post by slug. Accepts slugs with or without the `.md` extension.
|
|
97
|
+
|
|
98
|
+
```typescript
|
|
99
|
+
const post = getPostBySlug<PostMeta>("hello-world");
|
|
100
|
+
// { slug: 'hello-world', metadata: { title: 'Hello World', ... }, content: '...' }
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
| Parameter | Type | Default | Description |
|
|
104
|
+
| ----------- | -------- | ---------- | -------------------------------- |
|
|
105
|
+
| `slug` | `string` | — | Filename with or without `.md` |
|
|
106
|
+
| `directory` | `string` | `"posts/"` | Path relative to `process.cwd()` |
|
|
107
|
+
|
|
108
|
+
**Returns:** `{ slug: string; metadata: T; content: string }`
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
### `getAllPostSlugs(directory?)`
|
|
113
|
+
|
|
114
|
+
Returns the raw filenames (including `.md` extension) from the specified directory.
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
const slugs = getAllPostSlugs();
|
|
118
|
+
// ['hello-world.md', 'getting-started.md']
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
| Parameter | Type | Default | Description |
|
|
122
|
+
| ----------- | -------- | ---------- | -------------------------------- |
|
|
123
|
+
| `directory` | `string` | `"posts/"` | Path relative to `process.cwd()` |
|
|
124
|
+
|
|
125
|
+
**Returns:** `string[]`
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
### `getAllPostParams(directory?)`
|
|
130
|
+
|
|
131
|
+
Returns slug parameter objects suitable for use with Next.js `generateStaticParams` or `getStaticPaths`. The `.md` extension is stripped automatically.
|
|
132
|
+
|
|
133
|
+
```typescript
|
|
134
|
+
const params = getAllPostParams();
|
|
135
|
+
// [{ slug: 'hello-world' }, { slug: 'getting-started' }]
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
| Parameter | Type | Default | Description |
|
|
139
|
+
| ----------- | -------- | ---------- | -------------------------------- |
|
|
140
|
+
| `directory` | `string` | `"posts/"` | Path relative to `process.cwd()` |
|
|
141
|
+
|
|
142
|
+
**Returns:** `Array<{ slug: string }>`
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
### `parseFrontmatter(input)`
|
|
147
|
+
|
|
148
|
+
Parses a raw markdown string and extracts YAML frontmatter metadata. Useful when you have markdown content not loaded from the filesystem, or when you need lower-level parsing control.
|
|
149
|
+
|
|
150
|
+
```typescript
|
|
151
|
+
import { parseFrontmatter } from "next-staticblog";
|
|
152
|
+
|
|
153
|
+
const raw = `---
|
|
154
|
+
title: Hello World
|
|
155
|
+
date: 2024-01-01
|
|
156
|
+
tags:
|
|
157
|
+
- blog
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
Welcome to my blog!`;
|
|
161
|
+
|
|
162
|
+
const { data, content } = parseFrontmatter(raw);
|
|
163
|
+
// data: { title: 'Hello World', date: '2024-01-01', tags: ['blog'] }
|
|
164
|
+
// content: '\nWelcome to my blog!'
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
| Parameter | Type | Description |
|
|
168
|
+
| --------- | -------- | ------------------------------------ |
|
|
169
|
+
| `input` | `string` | Raw markdown string with frontmatter |
|
|
170
|
+
|
|
171
|
+
**Returns:** `{ data: Record<string, unknown>; content: string }`
|
|
172
|
+
|
|
173
|
+
- `data` — parsed YAML frontmatter as a plain object. Returns `{}` if no valid frontmatter is found.
|
|
174
|
+
- `content` — the markdown body after the frontmatter block.
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
## Usage with Next.js
|
|
179
|
+
|
|
180
|
+
### App Router (Next.js 13+)
|
|
181
|
+
|
|
182
|
+
```typescript
|
|
183
|
+
// app/blog/[slug]/page.tsx
|
|
184
|
+
import { getAllPostParams, getPostBySlug } from 'next-staticblog';
|
|
185
|
+
|
|
186
|
+
interface PostMeta {
|
|
187
|
+
title: string;
|
|
188
|
+
date: string;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
export function generateStaticParams() {
|
|
192
|
+
return getAllPostParams();
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
export default function BlogPost({ params }: { params: { slug: string } }) {
|
|
196
|
+
const { metadata, content } = getPostBySlug<PostMeta>(params.slug);
|
|
197
|
+
|
|
198
|
+
return (
|
|
199
|
+
<article>
|
|
200
|
+
<h1>{metadata.title}</h1>
|
|
201
|
+
<p>{metadata.date}</p>
|
|
202
|
+
{/* render content with your preferred markdown renderer */}
|
|
203
|
+
<div dangerouslySetInnerHTML={{ __html: content }} />
|
|
204
|
+
</article>
|
|
205
|
+
);
|
|
206
|
+
}
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### Pages Router
|
|
210
|
+
|
|
211
|
+
```typescript
|
|
212
|
+
// pages/blog/[slug].tsx
|
|
213
|
+
import { GetStaticPaths, GetStaticProps } from "next";
|
|
214
|
+
import { getAllPostParams, getPostBySlug } from "next-staticblog";
|
|
215
|
+
|
|
216
|
+
interface PostMeta {
|
|
217
|
+
title: string;
|
|
218
|
+
date: string;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
export const getStaticPaths: GetStaticPaths = () => ({
|
|
222
|
+
paths: getAllPostParams().map(({ slug }) => ({ params: { slug } })),
|
|
223
|
+
fallback: false,
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
export const getStaticProps: GetStaticProps = ({ params }) => {
|
|
227
|
+
const post = getPostBySlug<PostMeta>(params!.slug as string);
|
|
228
|
+
return { props: { post } };
|
|
229
|
+
};
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
### Custom Post Directory
|
|
233
|
+
|
|
234
|
+
All functions accept an optional `directory` parameter:
|
|
235
|
+
|
|
236
|
+
```typescript
|
|
237
|
+
// Use a custom directory
|
|
238
|
+
const posts = getAllPosts("content/articles/");
|
|
239
|
+
const post = getPostBySlug("my-article", "content/articles/");
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
## Development
|
|
243
|
+
|
|
244
|
+
```bash
|
|
245
|
+
# Install dependencies
|
|
246
|
+
npm install
|
|
247
|
+
|
|
248
|
+
# Build
|
|
249
|
+
npm run build
|
|
250
|
+
|
|
251
|
+
# Run tests
|
|
252
|
+
npm test
|
|
253
|
+
|
|
254
|
+
# Format code
|
|
255
|
+
npm run format
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
## License
|
|
259
|
+
|
|
260
|
+
MIT © [twyd](https://github.com/yd-tw/next-staticblog)
|
package/dist/index.d.ts
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
export declare function getAllPostSlugs(directory?: string): string[];
|
|
2
|
-
export declare function getAllPosts(directory?: string): {
|
|
2
|
+
export declare function getAllPosts<T extends Record<string, unknown> = Record<string, unknown>>(directory?: string): {
|
|
3
3
|
slug: string;
|
|
4
|
-
metadata:
|
|
4
|
+
metadata: T;
|
|
5
5
|
content: string;
|
|
6
6
|
}[];
|
|
7
7
|
export declare function getAllPostParams(directory?: string): {
|
|
8
8
|
slug: string;
|
|
9
9
|
}[];
|
|
10
|
-
export declare function getPostBySlug(slug: string, directory?: string): {
|
|
10
|
+
export declare function getPostBySlug<T extends Record<string, unknown> = Record<string, unknown>>(slug: string, directory?: string): {
|
|
11
11
|
slug: string;
|
|
12
|
-
metadata:
|
|
12
|
+
metadata: T;
|
|
13
13
|
content: string;
|
|
14
14
|
};
|