| 1/24
next.js で自分のブログを作る
自分のブログとして mizchi.dev を作った話
at 隅田川.js #1(オンライン) - connpass
何を作ったか
このブログ自身(mizchi.dev)。スライドツールも突貫で自作
ソースコード mizchi/dev
Lighthouse
Full AMP
GA 対応
Git から編集ヒストリの生成
どんなブログがほしかったか
- Lighthouse で満点出したい
- 普通の Markdown じゃつまんないから MDX で書きたい
- サーバーの運用をしたくない
- next.js の最適化に乗りたい
作った
- どうせ動かないし CDN 上で静的サイト + Full AMP
- MDX コンパイラを自作 (amdx)
- netlify + 買ったまま忘れてたカスタムドメイン(mizchi.dev)
pages/*.tsx
が公開される仕組みを、そのまま採用
(本音
- next.js で静的サイト運用の知見を貯めたい
- AMP の知見を貯めたい
- React でガシガシ動く作例を置く場所を、自分のドメインで用意したい
next.js の SSG + AMP モードの採用
// pages/foo.tsx
export const config = { amp: true };
export default function Foo() {
return <div>foo</div>;
}
amp: true
で常に amp を生成- AMP canonical は常に自分自身を指す(のを next.js が勝手にやってくれる)
AMP の plugin を諸々突っ込む
amp-social-share
で twitter / facebook / hatena bookmark のシェアに対応amp-analytics
で GoogleAnalytics 対応- rollup + preact + amp-script で、AMP 上で動的なコンポーネントが作れる。後で何かに使う
AMP 用 Markdown Compiler を作ろう!
AMP 環境の Markdown に求められる仕様
- AMP の仕様を満たす
img
=>amp-img
かつ、 amp layout 仕様を満たす固定幅の要素に- 数式ブロック(
$$ ~ $$
) を amp-mathml に変換
- コードハイライト: ランタイムで構文解析できない ので、コードブロックのハイライトを、コンパイル時に済ませておく必要
MDX について
Markdown 中で import 構文が使える仕様
# Hello, MDX
import Doc from "./doc";
<Doc />
Markdown ドキュメントから、別の Markdown ドキュメントや、React.Component
を展開できる。
シンタックスハイライターなどのエコシステムの都合から、.mdx
拡張子をそのまま採用したい。
AMDX: Accelarated MDX
- mizchi/amdx: Accelarated MDX
- remark ベースで
@mdx-js/mdx
を元に拡張 (中で使ってる babel plugin はそのままなので、構文は互換) - refract(prismjs parser) で、コンパイル時にコードブロックをトークン化
- +色々 (toc, frontmatter や WebWorker で動くように等)
AMDXG: AMDX による静的サイト生成ツールキット
- amdx-loader: amdx の webpack 用のローダー
- amdxg-components: ブログ用のデフォルトコンポーネント集。使わなくてもいい
- amdxg-cli: ページの雛形や各種メタデータ生成用の CLI
- amdxg-boilerplate: ただのボイラープレート。(注意: まだ安定してない。頻繁に変わる)
ドキュメントの解析
docs/*.mdx
の frontmatter を解析
---
title: hello
created: 1589877769475
tags: [react, next, amp]
---
- タイトルを日付順に並べた
gen/pages.json
を生成 - タグで逆引きする用の
gen/tagmap.json
を生成 - git log のコミットログから
gen/*.history.json
を生成
Index
gen/pages.json
からページ一覧を表示gen/tagmap.json
からタグ一覧を表示
ドキュメントの表示
next.config.js
のwebpack
で.mdx
拡張子は amdx-loader (自作) を通すようにする- next.js の danymic routing で 対応する slug の component を動的に返す
// pages/[slug].tsx
export const getStaticProps: GetStaticProps = async (props) => {
const slug = props.params.slug;
const { default: Doc, toc, frontmatter } = await import(
`../docs/${slug}.mdx`
);
const { default: history } = await import(`../gen/${slug}.history.json`);
return {
props: {
slug,
toc,
history,
tags: frontmatter.tags || [],
frontmatter: frontmatter || { title: slug, created: 0, tags: [] },
html: ReactDOMServer.renderToStaticMarkup(<Doc amp />),
} as Props,
};
};
後は amdxg-components で用意したコンポーネントに突っ込んで表示
タグページ
gen/tagmap.json
から/tags/react
のようなページを生成して表示
// pages/tags/[tag].tsx
export function getStaticPaths() {
const paths = Object.keys(tagmap).map((tag) => {
return `/tags/${tag}`;
});
return {
paths,
fallback: false,
};
}
export const getStaticProps: GetStaticProps = async (props) => {
const tag = props.params.tag;
return {
props: {
tagName: tag,
pages: tagmap[tag as any],
} as Props,
};
};
自分の環境で遊ぶ
$ npx degit mizchi/mdxx/templates/blog myblog
$ cd myblog
$ git init && git commit -m "Init" # 編集履歴生成に git history を使う
$ edit amdxg.config.js # メタデータを編集
# 書く
$ npm i -g amdxg-cli
$ amdxg new:page new-article # docs/new-article.mdx に記事の雛形を生成
$ npx run dev # localhost:3000 でプレビューしながら記事を編集
# build / deploy
$ npx run build # out/ に静的サイトを生成
# 要: netlify account
$ npm i -g netlify-cli
$ netlify deploy -d out --prod
デモ
今後やること
- CSS が雑
- amxd のプレビュー環境 (mdbuf.netlify.com ベース)
- ドキュメントサイト
- vercel 上で任意のバックエンド(CMS)から Incremental SSG する例を作る
Incremental Static Regeneration で実現する次世代のサーバーアーキテクチャ - mizdev
おわり
Google 検索結果からの遷移が爆速 💪
(CSS が苦手なので助けて)