Next.js 13にしました
ようやくこのサイトをNext.js 13にできました。そのメモです。
webpackローダーのESM対応
いきなりNext.jsではないのですが、webpack@5.80
でESMのLoaderが指定できるようになりました。これがいちばんありがたかったポイントです。
例えば*.mts
をTypeScriptでロードするために以下のような設定をしたとしましょう。MyTsLoader
は{"type":"module"}
なパッケージとします。
webpack@5.79
とwebpack@5.80
それぞれでの動作は以下で確認できます:
webpack@5.79
: CodeSandbox:repl-webpack-5-79-mjs-loaderwebpack@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というNext.jsに含まれるツールを利用して画像を生成できるようになったので、これを使っています。
/path/to/page
というページの画像を/cover/path/to/page
で生成します。
- 例えばこのページの画像はこちら:
/cover/2023/next13
- 画像を生成しているコードはこちら:
/app/cover/[[...path]]/route.tsx
- フォントは @fontsource/noto-sans-jp のフォルダから
public
フォルダに事前にコピーしておいたものをfetch
します。 - 文字出力の際に提供したフォントにない文字があるとエラーになります。
- adobe-blankを渡しておけばエラーにはならなくなりそうです。
- フォントは @fontsource/noto-sans-jp のフォルダから
<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:{...},
を入れます。 ↩