LoginSignup
10
7

[Next.js] TypeScriptだけを使ってNext.jsの中でp5.jsを動かしてみる

Posted at

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>コンポーネントにsetupdrawをパス
  • 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での使い方を共有したいと思います。

  1. pagesディレクトリと同じレベルのp5jsなどというフォルダーにp5.jsのコードが入るsketch.tsなどを置く(任意)
  2. sketch.tsでp5Typesをインポート
    import p5Types from 'p5'
    
  3. 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大歓迎です!

また、ご不明点などありましたらコメントやツイッターでご連絡いただければ嬉しいです。

10
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
7