React をかじった後で svelte を見てみるとわかりみがある。 やってみる。

tutorial

Part1 Basic Svelte にさらっと目を通す。

vitesvelete 初期化。 markdown の posts を収集して表示する方法が解らぬ。 adapter-static が関係しそうだという感じがする。

Part3 Basic Svelte Kit も見る。 こっちの先に読んだほうがいいかも。重要。 まさに blog の例も書いてあった。

nvim

  • language-server
  • tree-sitter

入れた。

作業

Terminal window
mv src src.bak # 退避
npm init svelte # current に展開
# src, vite.config.ts, svelte.config.ts あたりが出現

原型

5つ作った。 普通に async load 関数で動くようなので中身作れば動きそう。

+ src/
+ lib/
+ getPosts.ts
+ routes/
+ posts/
+page.svelte
+page.server.ts
[slut]/
+page.svelte
+page.server.ts
+ posts/ # getPosts でここを glob する
+ **/*.md
+ **/*.jpg # 未解決
  • src/lib/getPosts.ts : dummy のロジック
export type PostType = {
slug: string;
title: string;
};
const posts: PostType[] = [
{
slug: "hoge",
title: "Hoge",
},
{
slug: "fuga",
title: "Fuga",
},
];
export async function getPosts(): Promise<PostType[]> {
return Promise.resolve(posts);
}
export async function getContent(slug: string): Promise<string> {
return Promise.resolve(`Hello "${slug}" !`);
}
  • src/routes/posts/page.svelte : 投稿一覧
<script>
export let data;
</script>
<h1>blog</h1>
<ul>
{#each data.summaries as { slug, title }}
<li><a href="/posts/{slug}">{title}</a></li>
{/each}
</ul>

local directory から getPosts する実装

素直に書いたら動いた。

Terminal window
> npm i -D glob front-matter
import path from "node:path";
import fs from "node:fs/promises";
import * as glob from "glob";
import fm from "front-matter";
export type PostType = {
title: string;
slug: string;
ext: string;
date: Date;
tags?: string[];
};
export async function getPosts(): Promise<PostType[]> {
const dir = ".";
const pattern = "posts/**/*.{md,mdx}";
const posts: PostType[] = [];
const matches = await glob.glob(pattern, { cwd: dir });
for (const m of matches) {
const res = await fs.readFile(path.join(dir, m), { encoding: "utf-8" });
const post = fm(res).attributes as PostType;
const matched = m.match(/^posts[\\\/](.*)(\.mdx?)$/);
if (!matched) {
throw new Error("not match: md|mdx");
}
post.slug = matched[1].replace(/\\/g, "/");
post.ext = matched[2]; //match.substring(6, match.length - 3);
if (post.tags) {
post.tags = post.tags.map((tag) => tag.toLowerCase());
}
posts.push(post);
}
posts.sort((a, b) => {
return b.date.getTime() - a.date.getTime();
});
return posts;
}

で、slug20XX/hoge とか 20XX/01/hoge とかが混在しているのに対処。

【SvelteKit 入門】ルーティング - Qiita
本記事で扱うファイル+page.svelte +server.jsシリーズまとめ(随時追加・更新)慣れている方は読むだけで大丈夫かと思います。手を動かしながら検証したい方は、空プロジェクトを…
【SvelteKit 入門】ルーティング - Qiita favicon https://qiita.com/jwnr/items/8932978ca2f50f102e3d#ex-カスタム404
【SvelteKit 入門】ルーティング - Qiita

[...slug] という記法があるらしい。

markdown の rendering

src/lib/getPosts.ts

export async function getContent(slug: string): Promise<string> {
const path = `posts/${slug}.md`;
console.log(path);
const content = await fs.readFile(path, "utf8");
return content;
}
svelte-exmarkdown
svelte-exmarkdown. Svelte component to render markdown.
svelte-exmarkdown favicon https://ssssota.github.io/svelte-exmarkdown/
<script>
import Markdown from "svelte-exmarkdown";
export let data;
</script>
<h1>{data.post.title}</h1>
<Markdown md="{data.post.content}" />

Gfm と rehype-highlight はドキュメント通りでさくっとできた。

SSG build

Static site generation • Docs • SvelteKit
Static site generation • Docs • SvelteKit favicon https://kit.svelte.dev/docs/adapter-static
Static site generation • Docs • SvelteKit

markdown からの内部リンクと画像リンクにエラーが出るが、 後回しにして握りつぶした。

Downloading assets at build time causes errors · sveltejs kit · Discussion #9723
Describe the bug I want to download posters in .jpg format and transform them to .webp at build time. The new .webp files should be stored under static/posters and shown using <img src="poster/foo....
Downloading assets at build time causes errors · sveltejs kit · Discussion #9723 favicon https://github.com/sveltejs/kit/discussions/9723
Downloading assets at build time causes errors · sveltejs kit · Discussion #9723
![image](./image.jpg)

という記法を解決する必要がある。

tailwind

Install Tailwind CSS with SvelteKit - Tailwind CSS
Setting up Tailwind CSS in a SvelteKit project.
Install Tailwind CSS with SvelteKit - Tailwind CSS favicon https://tailwindcss.com/docs/guides/sveltekit
Install Tailwind CSS with SvelteKit - Tailwind CSS

react-daisyui に頼っていたので、素の tailwind が良くわかっていないことが判明。