SvelteKit 5 で構築した技術ブログです。articles/ と books/ の Markdown/YAML コンテンツをもとに、Cloudflare Workers 上で配信します。
| カテゴリ | 採用技術 |
|---|---|
| アプリ | Svelte 5, SvelteKit 2 |
| UI/スタイル | Tailwind CSS, bits-ui, melt-ui |
| コンテンツ | Markdown (gray-matter), YAML (config.yaml) |
| 検索 | Pagefind |
| デプロイ | Cloudflare Workers (@sveltejs/adapter-cloudflare, Wrangler) |
| テスト | Vitest, Playwright |
.
├─ articles/ # 記事Markdown
├─ books/ # 本コンテンツ(book単位のフォルダ)
├─ docs/ # ドキュメント(このREADMEを含む)
├─ scripts/ # ビルド補助スクリプト
├─ src/
│ ├─ lib/
│ │ ├─ getArticles.ts # 記事一覧の読み込み
│ │ ├─ getBooks.ts # 本/章データの読み込み
│ │ ├─ contributions.remote.ts # GitHub PR一覧取得(Remote Function)
│ │ └─ server/
│ │ ├─ github.ts # GitHub APIクライアント
│ │ └─ zennMarkdown.ts # zenn-markdown-htmlラッパー
│ ├─ routes/ # ルーティング
│ └─ service-worker.ts # PWAキャッシュ制御
├─ static/ # 画像・manifest・ads.txt など静的ファイル
└─ wrangler.jsonc # Cloudflare Workers設定flowchart LR
User[Browser]
subgraph CF[Cloudflare Workers]
App[SvelteKit App]
StaticRoutes[Prerendered routes\n/, /articles, /books, /tags, /articles/:articleId, /books/:bookId/:chapterId]
DynamicRoute[SSR route\n/contributions]
Search[Pagefind index]
PWA[service-worker.js + manifest.webmanifest]
end
subgraph Repo[Repository data]
Articles[articles/*.md]
Books[books/*/config.yaml + *.md]
StaticAssets[static/**]
end
subgraph External[External services]
GitHub[GitHub Search API / Issues API]
GA[Google Analytics]
AdSense[Google AdSense]
Zenn[zenn-markdown-html / zenn-embed-elements]
end
User --> App
App --> StaticRoutes
App --> DynamicRoute
App --> Search
App --> PWA
Articles --> App
Books --> App
StaticAssets --> App
DynamicRoute --> GitHub
App --> GitHub
App --> Zenn
User --> GA
User --> AdSense
npm install
npm run devpnpm を使う場合:
pnpm install
pnpm devnpm run dev # 開発サーバ
npm run check # 型/静的チェック
npm run lint # ESLint + Prettier check
npm run test # Playwright + Vitest
npm run build # build + postbuild(Pagefind/Sitemap生成含む)
npm run preview # ローカルプレビュー
npm run generate:og # OGP画像生成npm run build の後に postbuild で以下を実行します。
pagefind --site .svelte-kit/cloudflarenode scripts/update-pagefind-manifest.jssvelte-sitemap --domain $PUBLIC_BASE_URL --out-dir ./.svelte-kit/cloudflare
記事は frontmatter を持つ Markdown として管理します。
| キー | 型 | 説明 |
|---|---|---|
title |
string |
記事タイトル |
description |
string |
記事概要 |
date |
string (YYYY-MM-DD) |
公開日 |
topics |
string[] |
タグ |
blog_published |
boolean |
ブログで公開するか |
published |
boolean |
Zennで公開するか |
config.yaml と章Markdownを配置します。
| ファイル | 説明 |
|---|---|
books/<slug>/config.yaml |
本のメタデータ(title, summary, topics, published, price, chapters) |
books/<slug>/*.md |
各章。frontmatter で title, free を指定可能 |
章の表示順は次の優先順位で決まります。
config.yamlのchapters配列順01.introduction.mdのような数値プレフィックス順- ファイル名順
| 変数名 | 用途 | 必須 |
|---|---|---|
PUBLIC_BASE_URL |
sitemap/canonical/OG URL の生成 | 推奨 |
PUBLIC_ADSENSE_CLIENT_ID |
記事ページでの AdSense 読み込み (ca-pub-...) |
任意 |
GITHUB_TOKEN |
/contributions の取得と /form からの GitHub Issue 作成に利用 |
推奨 |
GITHUB_TOKEN は対象リポジトリ(yuu19/yusuke-blog)に対して、Issue 作成可能な権限を持つトークンを利用してください(Fine-grained token 推奨)。
Cloudflare Workers へデプロイします。
npm run build
npx wrangler deploywrangler.jsonc では .svelte-kit/cloudflare/_worker.js をエントリに設定しています。