next/font/googleでビルドが止まったので、JetBrains Monoを同梱してnext/font/localで読み込んだ
本記事にはアフィリエイト広告(PR)を含みます。詳しくは広告・アフィリエイトについてをご確認ください。
このサイトでは、ラベルや見出しの記号に等幅フォントの JetBrains Mono を使っています。最初は Next.js の next/font/google で読み込んでいましたが、ビルドが終わらなくなる問題が起きました。この記事では、フォントファイルをリポジトリに入れて next/font/local で読み込む形に切り替えた手順を書きます。
何が起きたか
next/font/google は、ビルドのときに Google Fonts からフォントを取りにいきます。私の環境では、この取得が止まってしまい、5分待ってもビルドが終わりませんでした。
同じ環境から curl で Google Fonts の CSS を取りにいくと、普通に返ってきます。なので、ネットワークがまったくつながらないわけではありません。ビルドの中での取得だけが止まっていたので、ビルド環境のネットワーク設定(プロキシなど)との相性が原因だと考えています。
原因を突き詰めるより、ビルドがネットワークに頼らない形にしたほうが確実です。そこで、フォントファイルをリポジトリに同梱することにしました。
フォントファイルを用意する
Google Fonts の CSS から、ファイルの URL を調べる
Google Fonts の CSS を取得すると、文字の範囲(サブセット)ごとに、フォントファイルの URL が書かれています。ブラウザ風の User-Agent を付けると、woff2 形式の URL が返ってきます。
curl -A "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124 Safari/537.36" \
"https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;700&display=swap"
返ってきた CSS には、cyrillic、greek、latin などのコメントが付いた @font-face が並んでいます。このサイトで等幅フォントを使うのは、英数字と記号だけです。なので、/* latin */ の部分の URL だけを使いました。
太さ違いが同じファイルだった
wght@400;700 で2つの太さを指定したのに、latin の 400 と 700 の URL はまったく同じでした。JetBrains Mono は可変フォント(1つのファイルで太さを連続的に変えられるフォント)として配信されているからです。ファイルは1つあれば足ります。
ダウンロードしたファイルは src/fonts/JetBrainsMono-latin-variable.woff2 に置きました。
ライセンスの文書も一緒に置く
JetBrains Mono は SIL Open Font License(OFL)で公開されています。OFL では、フォントを同梱して配布することが認められていますが、ライセンスの文書を一緒に付ける必要があります。JetBrains Mono のリポジトリにある OFL.txt を取得して、フォントと同じ src/fonts/ に置きました。
next/font/local で読み込む
app/layout.tsx で、next/font/local を使って読み込みます。
import localFont from "next/font/local";
const jetBrainsMono = localFont({
src: "../fonts/JetBrainsMono-latin-variable.woff2",
weight: "100 800",
variable: "--font-jetbrains-mono",
display: "swap",
});
可変フォントなので、weight は「100 800」のように範囲で書きます。variable を指定すると、CSS 変数としてフォント名を参照できるようになります。
この CSS 変数を使うために、html 要素にクラスを付けます。
<html lang="ja" className={jetBrainsMono.variable}>
CSS 側では、この変数を先頭にしたフォントの指定を作っておきます。
:root {
--font-mono:
var(--font-jetbrains-mono), ui-monospace, "SFMono-Regular", Menlo, Consolas,
"Hiragino Sans", "Hiragino Kaku Gothic ProN", monospace;
}
latin のサブセットには日本語の文字が入っていません。日本語の部分は、後ろに並べた日本語フォントで表示されます。
これで、ビルドのときにネットワークへ取りにいくことがなくなり、ビルドが止まることもなくなりました。
おまけ、記事のコードでは合字を切る
JetBrains Mono には合字(リガチャ)があり、=> や === が1つの記号のように表示されます。エディタでは読みやすいのですが、記事のコードを書き写す人が「この記号はどう打つのか」と迷います。
そこで、記事の中のコードだけ、合字を切っています。
code {
font-variant-ligatures: none;
}
ロゴや見出しの記号のような飾りの部分は、合字のままにしています。