Next.jsの中でp5.jsを動かすとなると、最初に気になるところは二つでした:
- Next.jsの主な機能の一つであるSSG(サーバー側生成)の中ではp5.jsは動かせません
- Next.jsは今だとデフォルトがTypeScriptだけど、p5.jsはデフォルトでJavaScriptです
この二つが本題になりますが、よくみる組み合わせでもないと思いますのでNext.jsとp5.jsを軽く紹介したいと思います。
Next.jsを軽く紹介
Reactベースのフルスタックウェブ ウェブ フレームワーク(注:Reactだけだとフレームワークにはなりません)。サーバー側で動かせるAPI Routesや静的ページ生成などの機能は実装されています。
p5.jsを軽く紹介
ProcessingのJavaScriptバージョンの一つ。電子アートとビジュアルデザインのために開発されたライブラリです。
どういうのができるの?
まずは全体図が伝わったらフォローしやすいと思いますので、ここでまとめてみます。
- p5.jsを使うときに定義する
setup
関数、draw
関数をTypeScriptで書く - Next.jsでp5.jsが(ブラウザのみで)使えるモジュールを読み込む
- React上でp5.jsが動く
<Sketch>
コンポーネントにsetup
とdraw
をパス - Next.js上でp5.jsのcanvasが表示される(しかもコードがスッキリしている!)
この流れで多分直面するややこしい2箇所をこれから解説していきます。
react-p5をTypeScriptで読み込む
npmにp5というパッケージもありますが、Next.jsがReactベースですのでreact-p5の方が便利かと思います。それでも、Next.jsのページはサーバー側でも生成されるので、p5.jsが必要とするwindow
オブジェクトが存在しないハードルに遭ってしまうかもしれません。
react-p5
のドキュメントにJavaScriptでの動的インポートのやり方が載っていますが、TypeScriptで使えるインポートをここで共有します。
import dynamic from 'next/dynamic'
// `dynamic`に渡す関数をあらかじめ定義する
const importFunction = () => import('react-p5').then((mod) => mod.default)
// とりあえずSketchが存在するように
let Sketch: any = null
// `window`が存在する場合はp5が使えます
// さらにインポート時にSSR(サーバーサイドレンダリング)をfalseにすることで
// インポートされたSketchがクライアント側でのみ使うことを宣言
if (typeof window !== 'undefined') {
Sketch = dynamic(importFunction, { ssr: false })
}
こうインポートすると、<Sketch>
コンポーネントが生Reactの時とほぼ同様に使えるようになります。
{typeof window !== 'undefined' && (
<Sketch setup={setup} draw={draw} />
)}
TypeScriptでp5.jsを書く
実はNext.jsをTypeScriptで使っていても、p5.jsの部分だけをJavaScriptで別ファイルに書いてNext.jsから読み込むことも可能ですが、ここではあえてTypeScriptでの使い方を共有したいと思います。
-
pages
ディレクトリと同じレベルのp5js
などというフォルダーにp5.jsのコードが入るsketch.ts
などを置く(任意) -
sketch.ts
でp5Typesをインポートimport p5Types from 'p5'
-
sketch.ts
で定義された関数などを<Sketch>
コンポーネントを返すtsxファイルでインポートする// Module Path Aliasesを利用する設定ですが`sketch.ts`の相対パスなどでOKです import { setup, draw } from '@/p5js/sketch'
p5.jsとなるとsetup
関数が必須で、canvasを初期化する内容が期待されます。draw
関数はフレームごと呼び出される関数になります。
const setup = (sketch: p5Types) => {
sketch.createCanvas(640, 480)
}
const draw = (sketch: p5Types) => {
sketch.background('#ffffff')
}
また、TypeScriptだからではなくてネームスペースの関係でp5.jsのインスタンスモードを使うことになるため、p5.jsが提供する全ての関数・定数の前にsketch.
が付きます。
最後に
Next.jsとp5.jsは相性がいいと思いました。Next.jsでベクターグラフィック、文字などを動かしたい場合はp5.jsもあると思い出したいと思います。
また、p5.jsでできた作品などを公開するときもNext.jsがおすすめです。
ここで説明していることの他に、現代的なウェブ コンポーネントではどうやって<canvas>
要素の位置や大きさを制御すればいいかなど、謎が残っているかもしれません。用意したサンプルリポジトリをご参照いただければと思います。スター・フォーク・PR大歓迎です!
また、ご不明点などありましたらコメントやツイッターでご連絡いただければ嬉しいです。