Next.js 13にしました
ようやくこのサイトをNext.js 13にできました。そのメモです。
## webpackローダーのESM対応
いきなりNext.jsではないのですが、webpack@5.80 でESMのLoaderが指定できるようになりました。これがいちばんありがたかったポイントです。
例えば *.ts
をTypeScriptでロードするために以下のような設定をしたとしましょう。MyTsLoader は{"type":"module"}
なパッケージとします。
webpack@5.79 と webpack@5.80 それぞれでの動作は以下で確認できます:
- webpack@5.79: CodeSandbox:repl-webpack-5-79-mjs-loader
- webpack@5.80: CodeSandbox:repl-webpack-5-80-mjs-loader
webpack@5.79 では以下のエラーになります:
そのため webpack@5.79 以前はCJSからESMを呼ぶなど回り道が必要でしたが、
- 2023/4/20に webpack@5.80 でそれが不要になり
- 2023/6/9に vercel/next.js#50992 で取り込まれ
- 2023/6/11に next@13.4.5 でリリースされたことで
Next.js環境でもESMのLoaderが使えるようになりました。
## MDXで書く
https://nextjs.org/docs/pages/building-your-application/configuring/mdx
ESMが楽に使えるようになったのでESMでリリースされている unified 関連のパッケージも楽に使えるようになりました。
### パッケージの追加
@next/mdx @mdx-js/loader をインストールします1。
### mdx-components.jsxの追加
何もしないのであればこれでOKです。
### next.config.mjsの変更
このサイトの実際の設定は next.config.mjs を参照してください。
- remark-gfm: GFM で書けるようにします
- remark-math: 数式ブロックを認識します
- rehype-highlight: コードブロックをハイライトします
- rehype-katex: 数式ブロックを KaTeX でレンダリングします
- rehype-slug: 見出しにidを付けます
### page.mdxを作って表示してみる
次の app/mdx-sample/page.mdx を追加して /mdx-sample でページが表示されればOKです。
## 記事やサイトの画像を生成する
satori というツールを利用して画像を生成できるようになったので、これを使っています。
/path/to/page というページの画像を /cover/path/to/page で生成します。
- 例えばこのページの画像はこちら: /cover/2023/next13
- 画像を生成しているコードはこちら: /app/cover/[[...path]]/route.tsx
- フォントは @fontsource/noto-sans-jp のフォルダから public フォルダに事前にコピーしておいたものを fetch します。
- 文字出力の際に提供したフォントにない文字があるとエラーになります。
- adobe-blankを渡しておけばエラーにはならなくなりそうです。
<meta>
に /cover/path/to/page を追加します。MDXでmetadataを設定するには page.tsx と同様に metadata を export します。参考: configuring/mdx#frontmatter
しかしこの openGraph の値はパスだけわかれば生成できるし、パスが変わったら修正が必要なのでこのような指定はしたくありません。layout.tsxで設定したいところですが現時点ではうまくできませんでした2。そのため後述のようにASTの時点で追加するようにしました。
## MDXのASTをいじる
以下の機能を追加しました。
- コード、画像、表、数式、を
<figure>
の中に入れる<figcaption>
をつける- それぞれリンクできる3
- コードブロックに行番号を追加
- 行番号にリンクできる
- Shift+クリックやCtrl+クリックで範囲指定できる
- 数式を
\begin{align}
と\end{align}
で囲む - 数式番号にリンクできる
- YouTube動画のタイトルとリンクをキャプションに追加する
export metadata = {...}
の中に openGraph を追加する- MDXの中の
export metadata = {...}
のブロックのnode.type
はmdxjsEsm
node.data.estree
にJavaScriptのASTがあるので metadata を export する ExportNamedDeclaration があればそれをいじるnode.value
にコードが文字列で入っていますがそちらを変更しても metadata は変更されません。- 今考えると
node.value
をいじって4node.data.estree
を更新する方が楽でした。
- MDXの中の
機能追加は以下のような関数を next.config.mjs
の remarkPlugins と rehypePlugins に追加すれば動きます。
## Footnotes
-
@mdx-js/react は
*.mdx
を import する必要があれば追加します。 ↩ -
middlewareでヘッダにパスを追加してheaders()でそれを読むなど言及されていますがうまくいきませんでした。 ↩
-
idを
position:absolute
で要素よりも上に表示した要素につけるとリンクから飛んできたときに対象がヘッダーで隠れません。 ↩ -
最初の
metadata = {
の直後にopenGraph:{...},
を入れます。 ↩