🦕

Next.js の App Router で FONTPLUS の Web フォントを読み込む

2023/12/14に公開

Next.js (App Router) で FONTPLUS の Web フォント読み込みを行う。

使用する Web フォントは FONTPLUS のスマートライセンス・プランのもの。
エンタープライズ・プランだと CSS 経由で読み込めるらしいので、予算規模が大きい場合はこちらを使おう。[1]

クライアントサイドで実行し、外部スクリプトの読み込み後に Web フォントを再度適用をするのがポイント。(後者はよりよい方法があるかもしれない)

Next.js のバージョンは 14.0.2

JSX 版のコンポーネント

/components/FontplusLoader.jsx
"use client"

import Script from 'next/script'

export default function FontplusLoader() {
  return (
    <Script
      src="https://webfont.fontplus.jp/accessor/script/fontplus.js?xxxxxxxxx"
      strategy="afterInteractive"
      onLoad={() => {
        if (FONTPLUS) {
          FONTPLUS.reload(false);
        }
      }}
    />
  )
}

TSX 版のコンポーネント

処理は変わらず型定義をちゃんとやる。

本体

/components/FontplusLoader.tsx
"use client"

import Script from 'next/script'

export default function FontplusLoader() {
  return (
    <Script
      src="https://webfont.fontplus.jp/accessor/script/fontplus.js?xxxxxxxxx"
      strategy="afterInteractive"
      onLoad={() => {
        if (FONTPLUS) {
          FONTPLUS.reload(false);
        }
      }}
    />
  )
}

型定義

/types/fontplus.d.ts
/**
 * FONTPLUS の型定義
 * JavaScript API: https://fontplus.jp/usage/javascript-api/method
 */

interface FONTPLUS {
  config: (options: ConfigOptions) => void;
  reload: (init?: boolean) => void;
  attachCompleteEvent: (callback: (result: { code: number }) => void) => void;
  targetSelector: (selector: string) => void;
  load: (
    fontdata: Array<{ fontname: string; nickname?: string; text: string }>,
    callback: (result: { code: number; time: number; [key: string]: any }) => void,
    tagid?: string
  ) => void;
  isloading: () => boolean;
  setFonts: (fontfamily: string[], mode?: string[]) => void;
  ontimeout: (callback: () => void) => void;
  async: () => void;
  start: () => void;
  size: (size: boolean) => void;
}

interface ConfigOptions {
  selector?: string;
  complete?: boolean;
  callbacks?: { [key: string]: () => void };
  timeoutfunc?: () => void;
  sync?: boolean;
  size?: boolean;
}

// グローバルスコープで FONTPLUS オブジェクトが存在することを明示
declare var FONTPLUS: FONTPLUS;

コンポーネントの読み込み

作成したコンポーネントを layout.tsx などで読み込む。

/app/layout.tsx
export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="ja">
      <head>
        <FontplusLoader />
      </head>
      <body>
        {children}
      </body>
    </html>
  )
}

FONTPLUS では </head> の直前でスクリプトの読み込みを推奨していたので、そのようにした。

Next.js のドキュメントには

You should not manually add <head> tags such as <title> and <meta> to root layouts. Instead, you should use the Metadata API which automatically handles advanced requirements such as streaming and de-duplicating <head> elements.

とあったけれど[2]、Metadata 関連ではないので多分大丈夫そう。

脚注
  1. エンタープライズ・プラン | Webフォント・サービス FONTPLUS ↩︎

  2. File Conventions: layout.js | Next.js ↩︎

Discussion