You: astroは独自のhtmlレンダーを使ってサイトを作れるか
ChatGPT: はい、Astroはかなり自由に独自HTMLレンダーを使えます。
Astro自体が:
「HTMLを生成する仕組み」
「コンポーネントを静的HTMLへ変換する仕組み」
なので、通常のMarkdown/MDXだけでなく、
独自テンプレート
独自レンダラー
独自DSL
JSON→HTML
EPUBメタデータ→HTML
みたいな用途に非常に向いています。
代表的な方法
1. 普通に .astro で独自HTML生成
一番簡単。
---
const book = Astro.props.book;
---
<html>
<body>
<article class="book">
<h1>{book.title}</h1>
<div class="author">
{book.author}
</div>
<a href={book.epub}>
Download
</a>
</article>
</body>
</html>
これはAstro独自レンダリングそのものです。
2. JSON → HTML
大量EPUBサイトではこれが最強です。
---
import books from "../data/books.json";
---
<ul>
{books.map((book) => (
<li>
<a href={`/books/${book.slug}`}>
{book.title}
</a>
</li>
))}
</ul>
データ駆動型。
3. 完全独自レンダラー
Node.jsコードでHTML文字列を生成可能。
exportfunctionrenderBook(book) {
return`
<article class="book">
<h1>${escape(book.title)}</h1>
<p>${escape(book.author)}</p>
</article>
`;
}
Astro側:
---
import { renderBook } from "../lib/render";
const html = renderBook(book);
---
<Fragment set:html={html} />
4. 独自マークアップ言語
たとえば:
#title: 吾輩は猫である #author: 夏目漱石 本文
をパースしてHTML化。
exportfunctionrenderNovel(text) {
returntext
.replace(/^#title:(.*)$/gm, "<h1>$1</h1>")
.replace(/^#author:(.*)$/gm, "<p>$1</p>");
}
5. rehype/remark系を差し替え
Astroは内部で:
remark
rehype
を使えるので、
Markdown変換処理を拡張できます。
たとえば:
《ルビ》 [#改ページ]
みたいな青空文庫記法を独自HTMLへ変換可能。
6. Astro Integrationで完全独自処理
かなり強力。
exportdefaultfunctionmyRenderer() {
return {
name: "my-renderer",
hooks: {
"astro:build:setup": () => {
}
}
};
}
これで:
ビルドフック
HTML変換
仮想ページ生成
などができます。
EPUBサイト用途なら特に強い構成
あなたの用途ならかなり相性が良いのは:
EPUB metadata ↓ 独自HTML renderer ↓ Astro page
です。
例えばこういうことができる
青空文庫風レンダー
[#ここから2字下げ]
↓
<divclass="indent-2">
EPUBメタデータ自動HTML
{
"title": "...",
"author": "...",
"toc": [...]
}
↓
<nav>
Astroの強み
Astroは:
ReactみたいなSPA前提ではない
HTML生成中心
SSG強い
Node.jsで前処理しやすい
ので、
「静的HTML生成器」
として非常に優秀です。
実はかなり自由
Astroは極端に言うと:
Node.js製静的サイトジェネレータ + HTMLテンプレートエンジン
として使えます。
なので:
Hugo
Jekyll
Eleventy
に近い使い方も可能です。
あなたの用途でおすすめ
大量EPUBサイトなら:
JSON ↓ 独自parser ↓ HTML component ↓ Astro build
がかなりおすすめです。
特に:
EPUB情報
著者分類
青空文庫記法
ルビ
目次
などを独自HTML化しやすいです。
情報源
ChatGPT:
Astroでは普通のNode.js/JavaScript関数をそのまま使えるので、
AozoraText2Html() を普通のJSモジュールとして切り出して import すれば使えます。
おすすめは:
src/lib/aozora/
以下に配置する構成です。
基本構成
src/ ├─ lib/ │ └─ aozora/ │ ├─ AozoraText2Html.js │ └─ parser.js │ ├─ pages/ │ └─ books/ │ └─ [slug].astro
AozoraText2Html.js
// src/lib/aozora/AozoraText2Html.js
exportfunctionAozoraText2Html(
text,
cur_command="title"
) {
lethtml=text;
// 改行
html=html.replace(/\n/g, "<br>");
// 見出し例
html=html.replace(
/^[#大見出し](.*?)$/gm,
"<h1>$1</h1>"
);
returnhtml;
}
Astroページから使う
---
import { AozoraText2Html }
from "../../lib/aozora/AozoraText2Html.js";
const text = `
[#大見出し]吾輩は猫である
名前はまだ無い。
`;
const html = AozoraText2Html(text);
---
<article>
<Fragment set:html={html} />
</article>
set:html が重要
Astroでは:
{html}
だとエスケープされます。
なので:
<Fragment set:html={html} />
を使います。
これは:
HTML innerHTML
相当です。
大量EPUBサイトならおすすめ構成
実際には:
青空テキスト ↓ AozoraText2Html ↓ Layout.astro ↓ 静的HTML
が良いです。
ページ単位生成
---
// src/pages/books/[slug].astro
import fs from "node:fs/promises";
import path from "node:path";
import { AozoraText2Html }
from "../../lib/aozora/AozoraText2Html.js";
export async function getStaticPaths() {
return [
{ params: { slug: "wagahai" } }
];
}
const { slug } = Astro.params;
const text = await fs.readFile(
path.resolve(`books/${slug}.txt`),
"utf-8"
);
const html = AozoraText2Html(text);
---
<html lang="ja">
<body>
<article class="aozora">
<Fragment set:html={html} />
</article>
</body>
</html>
Astroと相性が良い理由
Astroは:
ビルド時Node.js実行可能
SSR可能
SSG可能
なので、
TXT → HTML変換
を非常にやりやすいです。
これは青空文庫系とかなり相性が良いです。
さらにおすすめ
parser と renderer を分離
最終的には:
text ↓ tokenize ↓ AST ↓ render HTML
構成にすると強いです。
例
[
{
type: "heading",
level: 1,
text: "吾輩は猫である"
},
{
type: "paragraph",
text: "名前はまだ無い。"
}
]
↓
HTML <h1>吾輩は猫である</h1> <p>名前はまだ無い。</p>
特に重要
大量ページでは:
文字列replace連打
だけだと限界が来ます。
青空文庫は:
入れ子
注記
ルビ
傍点
画像
改ページ
があるので、
AST化すると管理しやすいです。
あなたの用途ならかなり良い構成
Aozora parser ↓ HTML renderer ↓ Astro static build ↓ Cloudflare Pages/GitHub Pages
がかなり強いです。
You:
小説サイトの場合は投稿日、章タイトル、タイトルなどフロントマッターをtxtファイルとしてあったほうがいいのか
ChatGPT:
はい、小説サイト用途なら
TXT本文とは別に「フロントマッター的メタデータ」を持たせたほうがかなり管理しやすいです。
特にAstroでは、
タイトル
投稿日
著者
章タイトル
タグ
あらすじ
などをビルド時に使うことが多いので、
本文だけのTXTより圧倒的に便利です。
おすすめ構成
一番おすすめなのは:
title: 吾輩は猫である
author: 夏目漱石
date: 1905-01-01
tags:
- 小説
- 青空文庫
chapter: 上巻
本文...
みたいなYAML frontmatter付きテキストです。
Astroとの相性
これは実質:
Markdown
MDX
Astro Content Collections
と同じ構造なので扱いやすいです。
おすすめファイル形式
1. .md
最もAstro向き。
src/content/novels/wagahai.md
Markdown
title: 吾輩は猫である
author: 夏目漱石
date: 1905-01-01
名前はまだ無い。
ただし:
青空文庫記法
独自記法
が混ざるなら微妙。
2. .txt + frontmatter
かなりおすすめ。
title: 吾輩は猫である
author: 夏目漱石
date: 1905-01-01
[#大見出し]吾輩は猫である
名前はまだ無い。
青空文庫系と相性が良いです。
3. JSON分離
大量データ向き。
wagahai/
├─ meta.json
└─ body.txt
これは超大規模サイト向け。
小説サイトで重要なメタデータ
かなり重要です。
必須級
YAML
title:
author:
date:
ほぼ欲しくなる
YAML
description:
tags:
series:
cover:
updated:
章管理なら重要
YAML
chapter:
episode:
arc:
sort:
実際かなり便利
例えば:
YAML
date: 2026-05-26
があると:
新着順
RSS
sitemap
OGP
SEO
全部やりやすくなります。
Astro Content Collections が強い
かなりおすすめ。
TypeScript
// src/content.config.ts
import { defineCollection, z }
from"astro:content";
constnovels=defineCollection({
type: "content",
schema: z.object({
title: z.string(),
author: z.string(),
date: z.date(),
tags: z.array(z.string()).optional(),
}),
});
exportconstcollections= {
novels,
};
するとこう使える
astro
import { getCollection }
from "astro:content";
const novels =
await getCollection("novels");
青空文庫パーサとの相性
かなり良いです。
frontmatter
↓
本文抽出
↓
Aozora parser
↓
HTML
構成にできます。
実装例
parser
JavaScript
importmatterfrom"gray-matter";
exportfunctionparseNovel(raw) {
const { data, content } =matter(raw);
return {
meta: data,
body: content,
};
}
Astroページ
astro
import fs from "node:fs/promises";
import matter from "gray-matter";
const raw = await fs.readFile(
"./novel.txt",
"utf-8"
);
const { data, content } =
matter(raw);
あなたの用途だと特におすすめ
かなり相性が良いのは:
frontmatter付きTXT
+
青空文庫記法
です。
理由:
Markdownと衝突しにくい
青空記法を保持可能
独自パーサを書きやすい
EPUB変換にも流用可能
最終的にかなり強い構成
novels/
├─ wagahai.txt
├─ sanshiro.txt
└─ ...
中身:
title:
author:
date:
tags:
青空文庫本文
↓
Astro build
↓
静的HTML小説サイト
↓
EPUB生成
この構成はかなり長期運用しやすいです。
You:
縦書き横書きなどを変更できる小説ビューワーとの組み合わせ方は
ChatGPT:
小説ビューワーとAstroを組み合わせる場合は、
Astroを「静的コンテンツ生成」、ビューワーを「クライアント側UI」に分離するとかなり綺麗に作れます。
特に:
縦書き/横書き切替
フォント変更
文字サイズ
行間
テーマ
ページ送り
などはクライアントJS側でやるのが相性良いです。
おすすめ構成
Astro
├─ 小説HTML生成
├─ SEO
├─ ページ生成
└─ metadata
Viewer(JS)
├─ 縦書き
├─ 横書き
├─ フォント変更
├─ テーマ
├─ 設定保存
└─ ページ送り
Astro側は「本文HTMLだけ作る」
例えば:
astro
const html = AozoraText2Html(content);
Viewer側でCSS切替
これが一番重要です。
縦書きCSS
CSS
.viewer.vertical {
writing-mode: vertical-rl;
text-orientation: mixed;
}
横書きCSS
CSS
.viewer.horizontal {
writing-mode: horizontal-tb;
}
JSで切替
JavaScript
constviewer=
document.querySelector("#viewer");
document
.querySelector("#toggle")
.onclick = () => {
viewer.classList.toggle("vertical");
viewer.classList.toggle("horizontal");
};
HTML構造おすすめ
HTML
<divid="viewer"class="viewer vertical">
<divclass="novel-container">
<articleid="novel-body">