このサイトはnext exportされた静的ファイルのSPAで、各記事はファイル名が日付のJSXになってる。もしかすると「JSXをvalueとしてもつJavaScriptオブジェクト」という表現のほうが正しいかも。ここでは区別しない。
例えばsrc/2021/2021_0101.jsはこんな感じ。
(拡張子が.jsなのはNext.jsが賢いのに任せているだけで、拡張子を.jsxにしたくない派というわけでもない。)
export default {
title: '新年',
content: (
<p>
あけましておめでとうございます。<br/>
CSS何も分からん。
</p>
)
}ブログとか記事とかそういうのはデータとして扱いづらくて、どうするのがいいか悩ましいわけ。今、すごく雑なことを言っています。データとして扱いやすくすると、コンテンツとしての表現力が下がるか面倒になりそう。MDXという解決もあるけど、全然気に入らず。次に、markdownをそのままhtmlに変換するのはどうかと考えたら、
- markdownを書きたくない
- htmlをそのまま書きたい
という気持ちが出て、前者はよく分からないけど放置して、後者に向き合うことにした。そしたら目の前にJSXがあったので採用して、紆余曲折ありつつ、最近やっと当初の目論見がだいたい達成された雰囲気になってきてる。それでもデータフォーマットとしては名前付きexportがexport defaultになったぐらいで他は変わらず。
getStaticPropsとかgetStaticPathsであればnodeのfsが普通に使えるので、記事ファイル名の一覧(2021_0101.jsなど)を取得して、dynamic importで読み込んだJSXをごにょごにょして、サイトの組み立てと表示に使っている。
dynamic importを使って静的なSPAを出力してるのが楽しいところで、混乱するところ。実際にdynamic importしているのはgetStaticなんとかではなく各ページのコンポーネントのレンダリング時(つまりNext.jsではなくReactのライフサイクル内)で、グローバルに1つのPromiseが全記事をまとめてimportしている。このPromiseの裏には上述の「記事ファイル名の一覧」のキャッシュがあって、これは当然グローバルに1つなのだけど、getStaticなんとかのときと、ページコンポーネントがレンダリングされるときでは実行環境が違っていて、前者でキャッシュされていても後者で再取得される。そりゃそうかと思ったり、同じプロセスで実行できないんだっけと考えたり、まだ混乱は残ってるんだけど楽しい。
とはいえ現在はgetStaticPropsで取得したファイル名の一覧をページコンポーネントに渡していて、一度しか取得されない実装になっている。先に取得しておけばいいもんね。この「先に取得しておけばいいもんね」が曲者で、ファイル名の一覧はStringの配列だから渡せるんだけど、記事そのものはJSXなのでページコンポーネントに渡せない。シリアライズできないって理解でいいのかな。JSXはデータじゃないのだ。それはそう。
フェーズの境界を実用のためにゴリッと繋げている通路こそがNext.jsに興味を持った理由なので、このあたりで混乱したり納得したりできて僕は幸せです。