hono-decks 0.1.0 → 0.2.0
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.ja.md +289 -0
- package/README.md +86 -78
- package/package.json +6 -5
package/README.ja.md
ADDED
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
# hono-decks
|
|
2
|
+
|
|
3
|
+
[English](https://github.com/ts-76/hono-decks/blob/main/packages/decks/README.md) | 日本語
|
|
4
|
+
|
|
5
|
+
Hono と Cloudflare Workers 上で MDX のスライドを配信するためのライブラリです。ビルド時に MDX を TypeScript module へ変換し、Worker runtime ではファイルシステムや compiler を読み込みません。
|
|
6
|
+
|
|
7
|
+
## Quick start
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
bun add hono hono-decks
|
|
11
|
+
bunx hono-decks init
|
|
12
|
+
bunx hono-decks compile
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
`init` は次の2ファイルを作ります。既存ファイルは上書きしません。
|
|
16
|
+
|
|
17
|
+
- `hono-decks.config.ts`: CLI と runtime が共有する唯一の設定
|
|
18
|
+
- `src/decks.ts`: generated module をアプリへ接続する編集可能な facade
|
|
19
|
+
|
|
20
|
+
```ts
|
|
21
|
+
// hono-decks.config.ts
|
|
22
|
+
import { defineDecksConfig } from "hono-decks";
|
|
23
|
+
|
|
24
|
+
export default defineDecksConfig({
|
|
25
|
+
mountPath: "/decks",
|
|
26
|
+
build: {
|
|
27
|
+
root: "decks",
|
|
28
|
+
outDir: "src/generated",
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
```ts
|
|
34
|
+
// src/decks.ts
|
|
35
|
+
import config from "../hono-decks.config";
|
|
36
|
+
import { createDecks } from "./generated/decks";
|
|
37
|
+
|
|
38
|
+
export const decks = createDecks(config);
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
// src/index.ts
|
|
43
|
+
import { Hono } from "hono";
|
|
44
|
+
import { decks } from "./decks";
|
|
45
|
+
|
|
46
|
+
const app = new Hono();
|
|
47
|
+
app.get("/", (c) => c.redirect(decks.paths("welcome").viewer));
|
|
48
|
+
app.route(decks.mountPath, decks.router());
|
|
49
|
+
export default app;
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
`decks/welcome/deck.mdx` を作り、`bunx hono-decks compile` を実行すると `src/generated/decks.ts` と slide modules が更新されます。generated directory は直接編集しません。
|
|
53
|
+
|
|
54
|
+
## One config, one runtime kit
|
|
55
|
+
|
|
56
|
+
以前のように compile option、`app.route()`、asset URL の mount path を別々に指定する必要はありません。`mountPath` は config に一度だけ書きます。generated module の `createDecks(config)` は次の configured kit を返します。
|
|
57
|
+
|
|
58
|
+
- `decks.mountPath`: `app.route()` に渡す正規化済みパス
|
|
59
|
+
- `decks.source`: config の `source()` が適用された `DeckSource`
|
|
60
|
+
- `decks.router(overrides?)`: config と呼び出し時 override を安全に深く合成した router
|
|
61
|
+
- `decks.context(overrides?)`: custom route 用 middleware
|
|
62
|
+
- `decks.paths(slug)`: viewer、render、print、presentation、presenter、embed、export、OGP image、assets の完全な route map
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
const paths = decks.paths("product");
|
|
66
|
+
paths.viewer; // /decks/product
|
|
67
|
+
paths.render; // /decks/product/render
|
|
68
|
+
paths.print; // /decks/product/print
|
|
69
|
+
paths.presentation; // /decks/product/presentation
|
|
70
|
+
paths.presenter; // /decks/product/presenter
|
|
71
|
+
paths.embed; // /decks/product/embed
|
|
72
|
+
paths.exportPdf; // /decks/product/export.pdf
|
|
73
|
+
paths.exportPng; // /decks/product/export.png
|
|
74
|
+
paths.ogImage; // /decks/product/og.png
|
|
75
|
+
paths.assets; // /decks/product/assets
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Viewer callbacks では同じ map を `input.meta.paths` から参照できます。文字列連結で route を再構築しないでください。
|
|
79
|
+
|
|
80
|
+
```ts
|
|
81
|
+
export default defineDecksConfig({
|
|
82
|
+
mountPath: "/decks",
|
|
83
|
+
router: {
|
|
84
|
+
viewer: {
|
|
85
|
+
controls: {
|
|
86
|
+
after: ({ meta }) => [
|
|
87
|
+
{ type: "link", href: `${meta.paths.viewer}/about`, label: "Details" },
|
|
88
|
+
],
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Development integration
|
|
96
|
+
|
|
97
|
+
Cloudflare Workersでは、deck compilerをWranglerのcustom buildへ登録します。
|
|
98
|
+
|
|
99
|
+
```jsonc
|
|
100
|
+
// wrangler.jsonc
|
|
101
|
+
{
|
|
102
|
+
"build": {
|
|
103
|
+
"command": "hono-decks compile",
|
|
104
|
+
"watch_dir": ["decks"]
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
`wrangler dev --live-reload`が初回compileとMDX、deck-local component、asset、theme CSSの変更監視、ブラウザ更新を担当します。deploy時にも同じbuild commandが実行されます。
|
|
110
|
+
|
|
111
|
+
HonoXまたはViteでは、既存のVite configへpluginを追加します。
|
|
112
|
+
|
|
113
|
+
```ts
|
|
114
|
+
import { honoDecks } from "hono-decks/vite";
|
|
115
|
+
import { defineConfig } from "vite";
|
|
116
|
+
|
|
117
|
+
export default defineConfig({
|
|
118
|
+
plugins: [honoDecks()],
|
|
119
|
+
});
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
pluginはVite起動前にcompileし、deck rootと`hono-decks.config.ts`をVite watcherへ登録します。再compileに成功するとfull reloadを通知するため、手動更新は不要です。どちらの構成でも通常の`bun run dev`だけでauthoringできます。
|
|
123
|
+
|
|
124
|
+
## Runtime configuration
|
|
125
|
+
|
|
126
|
+
すべての resolver は1個の object argument を受け取ります。引数の順序を覚える必要がなく、将来 input が増えても callback の意味が崩れません。
|
|
127
|
+
|
|
128
|
+
```ts
|
|
129
|
+
interface AppEnv {
|
|
130
|
+
Bindings: {
|
|
131
|
+
BROWSER?: DeckBrowserRunBinding;
|
|
132
|
+
DECK_EXPORT_TOKEN?: string;
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export default defineDecksConfig<AppEnv>({
|
|
137
|
+
mountPath: "/decks",
|
|
138
|
+
build: { root: "decks", outDir: "src/generated" },
|
|
139
|
+
router: {
|
|
140
|
+
presenter: {
|
|
141
|
+
enabled: ({ dev }) => dev,
|
|
142
|
+
viewerControl: true,
|
|
143
|
+
},
|
|
144
|
+
export: {
|
|
145
|
+
authorize: ({ c }) =>
|
|
146
|
+
c.req.header("authorization") === `Bearer ${c.env.DECK_EXPORT_TOKEN}`,
|
|
147
|
+
browser: ({ c }) => c.env.BROWSER,
|
|
148
|
+
pdf: true,
|
|
149
|
+
png: true,
|
|
150
|
+
},
|
|
151
|
+
},
|
|
152
|
+
});
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
`dev`を省略すると、ViteとWranglerが設定する`NODE_ENV`から判定します。標準設定では、`vite`と`wrangler dev`は開発モード、プロダクションビルドと`wrangler deploy`は本番モードになります。`dev: false`やresolverを指定した場合は明示値が優先され、判定できない環境では本番モードとして扱われます。
|
|
156
|
+
|
|
157
|
+
呼び出し元で一部だけ変える場合は `decks.router({ viewer: ... })` を使います。viewer controls、document surfaces、presenter、embed、export などの nested option は config を失わずに合成されます。機能を止めるときは `presenter: false`、`embed: false`、`export: false` のように明示できます。
|
|
158
|
+
|
|
159
|
+
## Custom application routes
|
|
160
|
+
|
|
161
|
+
```ts
|
|
162
|
+
import type { DeckContextVariables } from "hono-decks";
|
|
163
|
+
import { decks } from "./decks";
|
|
164
|
+
|
|
165
|
+
const app = new Hono<{ Variables: DeckContextVariables }>();
|
|
166
|
+
|
|
167
|
+
app.get(
|
|
168
|
+
`${decks.mountPath}/:slug/about`,
|
|
169
|
+
decks.context(),
|
|
170
|
+
(c) => c.json({
|
|
171
|
+
title: c.var.deckMeta.title,
|
|
172
|
+
viewer: c.var.deckMeta.paths.viewer,
|
|
173
|
+
slides: c.var.deckToc,
|
|
174
|
+
}),
|
|
175
|
+
);
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
`decks.context()` は configured source、mount path、dev policy、viewer controls を自動的に共有します。custom route と標準 viewer で draft 判定や URL がずれません。
|
|
179
|
+
|
|
180
|
+
標準ページ全体を差し替える場合は config の `viewer.render` を使います。callback には `frame`、`controls`、`toc`、`meta.paths` が渡るため、標準部品を再利用しながら app-owned layout を構築できます。
|
|
181
|
+
|
|
182
|
+
## Deck-local components and CSS
|
|
183
|
+
|
|
184
|
+
Directory deck は次の構造を使えます。
|
|
185
|
+
|
|
186
|
+
```text
|
|
187
|
+
decks/product/
|
|
188
|
+
deck.mdx
|
|
189
|
+
theme.css
|
|
190
|
+
assets/
|
|
191
|
+
diagram.svg
|
|
192
|
+
components/
|
|
193
|
+
index.tsx
|
|
194
|
+
client/
|
|
195
|
+
index.tsx
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
`components/index.tsx` は server-side JSX component、`components/client/index.tsx` は browser で hydrate する component です。`theme.css` はその deck だけに適用されます。画像は compile 時に検出され、`mountPath` と slug を使った public URL に書き換えられます。
|
|
199
|
+
|
|
200
|
+
## Embedding
|
|
201
|
+
|
|
202
|
+
同じdocumentへ複数配置する場合は `createDeckViewerEmbed()` を使えます。これは app が取得済みの `CompiledDeck` から iframe viewer、controls、TOC を組み立てる high-level helper です。
|
|
203
|
+
|
|
204
|
+
Embedding from an external blog では `router.embed` を有効にし、`frameAncestors` に許可する親 origin を明示してください。`iframe navigationにCORSは不要`ですが、CSP の `frame-ancestors` は必要です。
|
|
205
|
+
|
|
206
|
+
```ts
|
|
207
|
+
router: {
|
|
208
|
+
embed: {
|
|
209
|
+
frameAncestors: ["https://blog.example.com"],
|
|
210
|
+
robots: false,
|
|
211
|
+
},
|
|
212
|
+
}
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
```html
|
|
216
|
+
<iframe
|
|
217
|
+
src="https://slides.example.com/decks/product/embed"
|
|
218
|
+
title="Product deck"
|
|
219
|
+
allow="fullscreen"
|
|
220
|
+
></iframe>
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
## Browser export
|
|
224
|
+
|
|
225
|
+
PDF/PNG export は Cloudflare Browser Rendering binding を resolver から返すと有効になります。viewer に export control が表示されるのは、その request が `authorize` を通った場合だけです。token は `vars` ではなく Wrangler secret として管理してください。
|
|
226
|
+
|
|
227
|
+
`Cmd + P` / `Ctrl + P` は viewer から print route を開き、印刷用に全 slide を表示します。server-side export も同じ print route を Browser Rendering に渡します。
|
|
228
|
+
|
|
229
|
+
## Build-time OGP recipe
|
|
230
|
+
|
|
231
|
+
viewer の share image をビルド時に生成する場合は、`router.viewer.openGraph` を有効にします。既定の画像パスは `decks.paths(slug).ogImage` です。viewer は request origin から Open Graph / Twitter Card の絶対URLを生成します。
|
|
232
|
+
|
|
233
|
+
```ts
|
|
234
|
+
export default defineDecksConfig({
|
|
235
|
+
mountPath: "/decks",
|
|
236
|
+
router: {
|
|
237
|
+
viewer: { openGraph: true },
|
|
238
|
+
},
|
|
239
|
+
});
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
独自CDNを使う場合は `imagePath: ({ deck }) => \`https://cdn.example.com/${deck.slug}.png\`` のように resolver で上書きできます。`false` または未指定なら social metadata は出力しません。
|
|
243
|
+
|
|
244
|
+
生成処理は core に含まれません。`examples/ogp` では `hono-decks/node` の `compileDecks()` が返す manifest を Satori + resvg へ渡し、1200×630 PNG を Workers Static Assets へ保存します。Satori / resvg は example だけの依存で、Browser Rendering binding は不要です。Satori は TTF / OTF / WOFF を読み込めますが WOFF2 は扱えないため、対象言語の font file を build script から明示的に渡してください。
|
|
245
|
+
|
|
246
|
+
`build.ogpCacheFile` は `@[card](...)` が参照する外部サイトのメタデータキャッシュです。viewer 自身の share image とは別機能です。
|
|
247
|
+
|
|
248
|
+
## Public entries
|
|
249
|
+
|
|
250
|
+
- `hono-decks`: config、configured kit の型、deck authoring、viewer/embed customization、source decorator
|
|
251
|
+
- `hono-decks/advanced`: `defineDecks()`、`decksRouter()`、`deckContext()`、raw renderer など独自 pipeline 用
|
|
252
|
+
- `hono-decks/client`: browser hydration
|
|
253
|
+
- `hono-decks/node`: compiler と Node filesystem adapter
|
|
254
|
+
- `hono-decks/cli`: programmatic CLI runner
|
|
255
|
+
|
|
256
|
+
通常の generated workflow では root entry だけを import します。`hono-decks/advanced` は custom `DeckSource` や router をゼロから組み立てる場合に限定してください。
|
|
257
|
+
|
|
258
|
+
## Cloudflare Workers
|
|
259
|
+
|
|
260
|
+
Wrangler は JSONC config、current compatibility date、必要に応じた `nodejs_compat` を使います。binding types は `wrangler types` で生成し、hand-written binding interface と実際の config がずれないようにしてください。
|
|
261
|
+
|
|
262
|
+
```jsonc
|
|
263
|
+
{
|
|
264
|
+
"$schema": "node_modules/wrangler/config-schema.json",
|
|
265
|
+
"name": "my-decks",
|
|
266
|
+
"main": "src/index.ts",
|
|
267
|
+
"compatibility_date": "2026-07-14",
|
|
268
|
+
"compatibility_flags": ["nodejs_compat"]
|
|
269
|
+
}
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
## Advanced API
|
|
273
|
+
|
|
274
|
+
既存 manifest、database、remote object store から完全に独自の runtime を作る場合だけ advanced entry を使います。
|
|
275
|
+
|
|
276
|
+
```ts
|
|
277
|
+
import { decksRouter, manifestDeckSource } from "hono-decks/advanced";
|
|
278
|
+
|
|
279
|
+
const source = manifestDeckSource(manifest);
|
|
280
|
+
app.route("/internal-slides", decksRouter({ source, dev: true }));
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
このレベルでは mount path、source policy、option merge をアプリ側が管理します。通常の利用では generated `createDecks(config)` のほうが安全で短くなります。
|
|
284
|
+
|
|
285
|
+
## Examples
|
|
286
|
+
|
|
287
|
+
- `examples/minimal`: standalone Worker の最小構成
|
|
288
|
+
- `examples/basic`: R2、Browser Rendering、custom routes、client components
|
|
289
|
+
- `examples/honox`: HonoX integration
|
package/README.md
CHANGED
|
@@ -1,21 +1,25 @@
|
|
|
1
1
|
# hono-decks
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
English | [日本語](https://github.com/ts-76/hono-decks/blob/main/packages/decks/README.ja.md)
|
|
4
|
+
|
|
5
|
+
hono-decks serves MDX slide decks from Hono applications and Cloudflare Workers. It compiles MDX into TypeScript modules at build time, so the Worker runtime does not load the filesystem or the compiler.
|
|
4
6
|
|
|
5
7
|
## Quick start
|
|
6
8
|
|
|
7
|
-
|
|
9
|
+
The examples below use Bun. npm, pnpm, and Yarn are supported as well.
|
|
10
|
+
|
|
11
|
+
~~~bash
|
|
8
12
|
bun add hono hono-decks
|
|
9
13
|
bunx hono-decks init
|
|
10
14
|
bunx hono-decks compile
|
|
11
|
-
|
|
15
|
+
~~~
|
|
12
16
|
|
|
13
|
-
|
|
17
|
+
<code>init</code> creates two files without overwriting existing files:
|
|
14
18
|
|
|
15
|
-
-
|
|
16
|
-
-
|
|
19
|
+
- <code>hono-decks.config.ts</code>: the shared configuration for the CLI and runtime
|
|
20
|
+
- <code>src/decks.ts</code>: an editable facade that connects the generated modules to your application
|
|
17
21
|
|
|
18
|
-
|
|
22
|
+
~~~ts
|
|
19
23
|
// hono-decks.config.ts
|
|
20
24
|
import { defineDecksConfig } from "hono-decks";
|
|
21
25
|
|
|
@@ -26,17 +30,17 @@ export default defineDecksConfig({
|
|
|
26
30
|
outDir: "src/generated",
|
|
27
31
|
},
|
|
28
32
|
});
|
|
29
|
-
|
|
33
|
+
~~~
|
|
30
34
|
|
|
31
|
-
|
|
35
|
+
~~~ts
|
|
32
36
|
// src/decks.ts
|
|
33
37
|
import config from "../hono-decks.config";
|
|
34
38
|
import { createDecks } from "./generated/decks";
|
|
35
39
|
|
|
36
40
|
export const decks = createDecks(config);
|
|
37
|
-
|
|
41
|
+
~~~
|
|
38
42
|
|
|
39
|
-
|
|
43
|
+
~~~ts
|
|
40
44
|
// src/index.ts
|
|
41
45
|
import { Hono } from "hono";
|
|
42
46
|
import { decks } from "./decks";
|
|
@@ -45,21 +49,21 @@ const app = new Hono();
|
|
|
45
49
|
app.get("/", (c) => c.redirect(decks.paths("welcome").viewer));
|
|
46
50
|
app.route(decks.mountPath, decks.router());
|
|
47
51
|
export default app;
|
|
48
|
-
|
|
52
|
+
~~~
|
|
49
53
|
|
|
50
|
-
|
|
54
|
+
Create <code>decks/welcome/deck.mdx</code>, then run <code>bunx hono-decks compile</code>. The command updates <code>src/generated/decks.ts</code> and the generated slide modules. Do not edit the generated directory directly.
|
|
51
55
|
|
|
52
56
|
## One config, one runtime kit
|
|
53
57
|
|
|
54
|
-
|
|
58
|
+
You do not need to repeat the mount path across compiler options, <code>app.route()</code>, and asset URLs. Define <code>mountPath</code> once in the config. The generated <code>createDecks(config)</code> function returns a configured kit:
|
|
55
59
|
|
|
56
|
-
-
|
|
57
|
-
-
|
|
58
|
-
-
|
|
59
|
-
-
|
|
60
|
-
-
|
|
60
|
+
- <code>decks.mountPath</code>: the normalized path to pass to <code>app.route()</code>
|
|
61
|
+
- <code>decks.source</code>: the <code>DeckSource</code> after applying the config's <code>source()</code> decorator
|
|
62
|
+
- <code>decks.router(overrides?)</code>: a router that safely deep-merges config and call-site overrides
|
|
63
|
+
- <code>decks.context(overrides?)</code>: middleware for application-owned routes
|
|
64
|
+
- <code>decks.paths(slug)</code>: the complete route map for the viewer, renderer, print view, presentation views, embeds, exports, OGP image, and assets
|
|
61
65
|
|
|
62
|
-
|
|
66
|
+
~~~ts
|
|
63
67
|
const paths = decks.paths("product");
|
|
64
68
|
paths.viewer; // /decks/product
|
|
65
69
|
paths.render; // /decks/product/render
|
|
@@ -71,30 +75,34 @@ paths.exportPdf; // /decks/product/export.pdf
|
|
|
71
75
|
paths.exportPng; // /decks/product/export.png
|
|
72
76
|
paths.ogImage; // /decks/product/og.png
|
|
73
77
|
paths.assets; // /decks/product/assets
|
|
74
|
-
|
|
78
|
+
~~~
|
|
75
79
|
|
|
76
|
-
Viewer callbacks
|
|
80
|
+
Viewer callbacks receive the same map as <code>input.meta.paths</code>. Use it instead of rebuilding routes with string concatenation.
|
|
77
81
|
|
|
78
|
-
|
|
82
|
+
~~~ts
|
|
79
83
|
export default defineDecksConfig({
|
|
80
84
|
mountPath: "/decks",
|
|
81
85
|
router: {
|
|
82
86
|
viewer: {
|
|
83
87
|
controls: {
|
|
84
88
|
after: ({ meta }) => [
|
|
85
|
-
{
|
|
89
|
+
{
|
|
90
|
+
type: "link",
|
|
91
|
+
href: meta.paths.viewer + "/about",
|
|
92
|
+
label: "Details",
|
|
93
|
+
},
|
|
86
94
|
],
|
|
87
95
|
},
|
|
88
96
|
},
|
|
89
97
|
},
|
|
90
98
|
});
|
|
91
|
-
|
|
99
|
+
~~~
|
|
92
100
|
|
|
93
101
|
## Development integration
|
|
94
102
|
|
|
95
|
-
Cloudflare Workers
|
|
103
|
+
For Cloudflare Workers, register the deck compiler as a Wrangler custom build.
|
|
96
104
|
|
|
97
|
-
|
|
105
|
+
~~~jsonc
|
|
98
106
|
// wrangler.jsonc
|
|
99
107
|
{
|
|
100
108
|
"build": {
|
|
@@ -102,28 +110,28 @@ Cloudflare Workersでは、deck compilerをWranglerのcustom buildへ登録し
|
|
|
102
110
|
"watch_dir": ["decks"]
|
|
103
111
|
}
|
|
104
112
|
}
|
|
105
|
-
|
|
113
|
+
~~~
|
|
106
114
|
|
|
107
|
-
|
|
115
|
+
<code>wrangler dev --live-reload</code> performs the initial compile, watches MDX, deck-local components, assets, and theme CSS, and reloads the browser. Wrangler runs the same build command during deployment.
|
|
108
116
|
|
|
109
|
-
HonoX
|
|
117
|
+
For HonoX or another Vite application, add the plugin to the existing Vite config.
|
|
110
118
|
|
|
111
|
-
|
|
119
|
+
~~~ts
|
|
112
120
|
import { honoDecks } from "hono-decks/vite";
|
|
113
121
|
import { defineConfig } from "vite";
|
|
114
122
|
|
|
115
123
|
export default defineConfig({
|
|
116
124
|
plugins: [honoDecks()],
|
|
117
125
|
});
|
|
118
|
-
|
|
126
|
+
~~~
|
|
119
127
|
|
|
120
|
-
plugin
|
|
128
|
+
The plugin compiles before Vite starts and adds the deck root and <code>hono-decks.config.ts</code> to the Vite watcher. After a successful recompile, it requests a full browser reload. In both setups, the application's normal <code>dev</code> command is enough for authoring.
|
|
121
129
|
|
|
122
130
|
## Runtime configuration
|
|
123
131
|
|
|
124
|
-
|
|
132
|
+
Every resolver receives one object argument. Callbacks remain readable as inputs are added because their meaning does not depend on positional parameters.
|
|
125
133
|
|
|
126
|
-
|
|
134
|
+
~~~ts
|
|
127
135
|
interface AppEnv {
|
|
128
136
|
Bindings: {
|
|
129
137
|
BROWSER?: DeckBrowserRunBinding;
|
|
@@ -141,29 +149,29 @@ export default defineDecksConfig<AppEnv>({
|
|
|
141
149
|
},
|
|
142
150
|
export: {
|
|
143
151
|
authorize: ({ c }) =>
|
|
144
|
-
c.req.header("authorization") ===
|
|
152
|
+
c.req.header("authorization") === "Bearer " + c.env.DECK_EXPORT_TOKEN,
|
|
145
153
|
browser: ({ c }) => c.env.BROWSER,
|
|
146
154
|
pdf: true,
|
|
147
155
|
png: true,
|
|
148
156
|
},
|
|
149
157
|
},
|
|
150
158
|
});
|
|
151
|
-
|
|
159
|
+
~~~
|
|
152
160
|
|
|
153
|
-
|
|
161
|
+
When <code>dev</code> is omitted, hono-decks uses the <code>NODE_ENV</code> value supplied by Vite or Wrangler. The standard Vite and <code>wrangler dev</code> commands are treated as development, while production builds and <code>wrangler deploy</code> are treated as production. An explicit <code>dev: false</code> value or resolver takes precedence. Unknown environments fail closed as production.
|
|
154
162
|
|
|
155
|
-
|
|
163
|
+
Use <code>decks.router({ viewer: ... })</code> for call-site overrides. Nested options for viewer controls, document surfaces, the presenter, embeds, and exports are merged without discarding the config. Disable a feature explicitly with values such as <code>presenter: false</code>, <code>embed: false</code>, or <code>export: false</code>.
|
|
156
164
|
|
|
157
165
|
## Custom application routes
|
|
158
166
|
|
|
159
|
-
|
|
167
|
+
~~~ts
|
|
160
168
|
import type { DeckContextVariables } from "hono-decks";
|
|
161
169
|
import { decks } from "./decks";
|
|
162
170
|
|
|
163
171
|
const app = new Hono<{ Variables: DeckContextVariables }>();
|
|
164
172
|
|
|
165
173
|
app.get(
|
|
166
|
-
|
|
174
|
+
decks.mountPath + "/:slug/about",
|
|
167
175
|
decks.context(),
|
|
168
176
|
(c) => c.json({
|
|
169
177
|
title: c.var.deckMeta.title,
|
|
@@ -171,17 +179,17 @@ app.get(
|
|
|
171
179
|
slides: c.var.deckToc,
|
|
172
180
|
}),
|
|
173
181
|
);
|
|
174
|
-
|
|
182
|
+
~~~
|
|
175
183
|
|
|
176
|
-
|
|
184
|
+
<code>decks.context()</code> shares the configured source, mount path, development policy, and viewer controls. Application routes and the built-in viewer therefore use the same draft policy and URLs.
|
|
177
185
|
|
|
178
|
-
|
|
186
|
+
To replace a built-in page, configure <code>viewer.render</code>. The callback receives <code>frame</code>, <code>controls</code>, <code>toc</code>, and <code>meta.paths</code>, allowing an application-owned layout to reuse the standard parts.
|
|
179
187
|
|
|
180
188
|
## Deck-local components and CSS
|
|
181
189
|
|
|
182
|
-
|
|
190
|
+
A directory deck can use this structure:
|
|
183
191
|
|
|
184
|
-
|
|
192
|
+
~~~text
|
|
185
193
|
decks/product/
|
|
186
194
|
deck.mdx
|
|
187
195
|
theme.css
|
|
@@ -191,73 +199,73 @@ decks/product/
|
|
|
191
199
|
index.tsx
|
|
192
200
|
client/
|
|
193
201
|
index.tsx
|
|
194
|
-
|
|
202
|
+
~~~
|
|
195
203
|
|
|
196
|
-
|
|
204
|
+
<code>components/index.tsx</code> contains server-side JSX components. <code>components/client/index.tsx</code> contains components hydrated in the browser. <code>theme.css</code> applies only to that deck. Local images are detected during compilation and rewritten to public URLs based on the mount path and deck slug.
|
|
197
205
|
|
|
198
206
|
## Embedding
|
|
199
207
|
|
|
200
|
-
|
|
208
|
+
Use <code>createDeckViewerEmbed()</code> to embed multiple decks into the same document. This high-level helper builds an iframe viewer, controls, and a table of contents from a <code>CompiledDeck</code> already loaded by the application.
|
|
201
209
|
|
|
202
|
-
|
|
210
|
+
When embedding from an external blog, enable <code>router.embed</code> and list the allowed parent origins in <code>frameAncestors</code>. Iframe navigation does not require CORS, but it does require an appropriate CSP <code>frame-ancestors</code> directive.
|
|
203
211
|
|
|
204
|
-
|
|
212
|
+
~~~ts
|
|
205
213
|
router: {
|
|
206
214
|
embed: {
|
|
207
215
|
frameAncestors: ["https://blog.example.com"],
|
|
208
216
|
robots: false,
|
|
209
217
|
},
|
|
210
218
|
}
|
|
211
|
-
|
|
219
|
+
~~~
|
|
212
220
|
|
|
213
|
-
|
|
221
|
+
~~~html
|
|
214
222
|
<iframe
|
|
215
223
|
src="https://slides.example.com/decks/product/embed"
|
|
216
224
|
title="Product deck"
|
|
217
225
|
allow="fullscreen"
|
|
218
226
|
></iframe>
|
|
219
|
-
|
|
227
|
+
~~~
|
|
220
228
|
|
|
221
229
|
## Browser export
|
|
222
230
|
|
|
223
|
-
PDF
|
|
231
|
+
Enable PDF and PNG exports by returning a Cloudflare Browser Rendering binding from the resolver. The viewer displays export controls only for requests accepted by <code>authorize</code>. Store export tokens as Wrangler secrets rather than in <code>vars</code>.
|
|
224
232
|
|
|
225
|
-
|
|
233
|
+
<code>Cmd + P</code> and <code>Ctrl + P</code> open the viewer's print route, which renders every slide for printing. Server-side export sends the same print route to Browser Rendering.
|
|
226
234
|
|
|
227
235
|
## Build-time OGP recipe
|
|
228
236
|
|
|
229
|
-
viewer
|
|
237
|
+
Enable <code>router.viewer.openGraph</code> when generating share images at build time. The default image path is <code>decks.paths(slug).ogImage</code>. The viewer derives absolute Open Graph and Twitter Card URLs from the request origin.
|
|
230
238
|
|
|
231
|
-
|
|
239
|
+
~~~ts
|
|
232
240
|
export default defineDecksConfig({
|
|
233
241
|
mountPath: "/decks",
|
|
234
242
|
router: {
|
|
235
243
|
viewer: { openGraph: true },
|
|
236
244
|
},
|
|
237
245
|
});
|
|
238
|
-
|
|
246
|
+
~~~
|
|
239
247
|
|
|
240
|
-
|
|
248
|
+
Override <code>imagePath</code> with a resolver when images are served from a separate CDN. Set Open Graph configuration to <code>false</code>, or omit it, to suppress social metadata.
|
|
241
249
|
|
|
242
|
-
|
|
250
|
+
Image generation is intentionally not part of the core package. The <code>examples/ogp</code> recipe passes the manifest returned by <code>compileDecks()</code> from <code>hono-decks/node</code> to Satori and resvg, then stores 1200 by 630 PNG files in Workers Static Assets. Satori and resvg are example-only dependencies, and the recipe does not require Browser Rendering. Satori accepts TTF, OTF, and WOFF fonts but not WOFF2, so the build script must receive a font file that covers the target language.
|
|
243
251
|
|
|
244
|
-
|
|
252
|
+
<code>build.ogpCacheFile</code> stores external site metadata used by <code>@[card](...)</code>. It is separate from the viewer's share image.
|
|
245
253
|
|
|
246
254
|
## Public entries
|
|
247
255
|
|
|
248
|
-
-
|
|
249
|
-
-
|
|
250
|
-
-
|
|
251
|
-
-
|
|
252
|
-
-
|
|
256
|
+
- <code>hono-decks</code>: configuration, configured-kit types, deck authoring, viewer and embed customization, and source decorators
|
|
257
|
+
- <code>hono-decks/advanced</code>: <code>defineDecks()</code>, <code>decksRouter()</code>, <code>deckContext()</code>, raw renderers, and other low-level pipeline APIs
|
|
258
|
+
- <code>hono-decks/client</code>: browser hydration
|
|
259
|
+
- <code>hono-decks/node</code>: the compiler and Node filesystem adapter
|
|
260
|
+
- <code>hono-decks/cli</code>: the programmatic CLI runner
|
|
253
261
|
|
|
254
|
-
|
|
262
|
+
The generated workflow normally imports only the root entry. Use <code>hono-decks/advanced</code> only when assembling a custom <code>DeckSource</code> or router from the lower-level primitives.
|
|
255
263
|
|
|
256
264
|
## Cloudflare Workers
|
|
257
265
|
|
|
258
|
-
|
|
266
|
+
Use a JSONC Wrangler config, a current compatibility date, and <code>nodejs_compat</code> when required. Generate binding types with <code>wrangler types</code> so handwritten environment types cannot drift from the deployed configuration.
|
|
259
267
|
|
|
260
|
-
|
|
268
|
+
~~~jsonc
|
|
261
269
|
{
|
|
262
270
|
"$schema": "node_modules/wrangler/config-schema.json",
|
|
263
271
|
"name": "my-decks",
|
|
@@ -265,23 +273,23 @@ Wrangler は JSONC config、current compatibility date、必要に応じた `nod
|
|
|
265
273
|
"compatibility_date": "2026-07-14",
|
|
266
274
|
"compatibility_flags": ["nodejs_compat"]
|
|
267
275
|
}
|
|
268
|
-
|
|
276
|
+
~~~
|
|
269
277
|
|
|
270
278
|
## Advanced API
|
|
271
279
|
|
|
272
|
-
|
|
280
|
+
Use the advanced entry only when building a custom runtime from an existing manifest, database, or remote object store.
|
|
273
281
|
|
|
274
|
-
|
|
282
|
+
~~~ts
|
|
275
283
|
import { decksRouter, manifestDeckSource } from "hono-decks/advanced";
|
|
276
284
|
|
|
277
285
|
const source = manifestDeckSource(manifest);
|
|
278
286
|
app.route("/internal-slides", decksRouter({ source, dev: true }));
|
|
279
|
-
|
|
287
|
+
~~~
|
|
280
288
|
|
|
281
|
-
|
|
289
|
+
At this level, the application owns the mount path, source policy, and option merging. For normal use, the generated <code>createDecks(config)</code> API is shorter and safer.
|
|
282
290
|
|
|
283
291
|
## Examples
|
|
284
292
|
|
|
285
|
-
-
|
|
286
|
-
-
|
|
287
|
-
-
|
|
293
|
+
- <code>examples/minimal</code>: the smallest standalone Worker setup
|
|
294
|
+
- <code>examples/basic</code>: R2, Browser Rendering, custom routes, and client components
|
|
295
|
+
- <code>examples/honox</code>: HonoX integration
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hono-decks",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Slide decks for Hono and Cloudflare Workers",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cloudflare-workers",
|
|
@@ -8,15 +8,15 @@
|
|
|
8
8
|
"mdx",
|
|
9
9
|
"slides"
|
|
10
10
|
],
|
|
11
|
-
"homepage": "https://github.com/ts-76/hono-
|
|
11
|
+
"homepage": "https://github.com/ts-76/hono-decks#readme",
|
|
12
12
|
"bugs": {
|
|
13
|
-
"url": "https://github.com/ts-76/hono-
|
|
13
|
+
"url": "https://github.com/ts-76/hono-decks/issues"
|
|
14
14
|
},
|
|
15
15
|
"license": "MIT",
|
|
16
16
|
"author": "ts-76",
|
|
17
17
|
"repository": {
|
|
18
18
|
"type": "git",
|
|
19
|
-
"url": "git+https://github.com/ts-76/hono-
|
|
19
|
+
"url": "git+https://github.com/ts-76/hono-decks.git",
|
|
20
20
|
"directory": "packages/decks"
|
|
21
21
|
},
|
|
22
22
|
"bin": {
|
|
@@ -24,7 +24,8 @@
|
|
|
24
24
|
},
|
|
25
25
|
"files": [
|
|
26
26
|
"dist",
|
|
27
|
-
"README.md"
|
|
27
|
+
"README.md",
|
|
28
|
+
"README.ja.md"
|
|
28
29
|
],
|
|
29
30
|
"type": "module",
|
|
30
31
|
"sideEffects": false,
|