Skip to main content
  1. Posts/

p5.jsをTypeScriptで書く方法

p5.jsをTypeScriptで使うセットアップをしてみたので、その流れをまとめてみます。

JavaScript、TypeScriptも業務で扱うものの、環境構築の経験はないので、もっと良い方法があれば書き直す

前提 #

手順 #

  1. スケッチを書いていくディレクトリを作る
  2. TypeScriptを使う準備
    1. ディレクトリに入り、 npm initを実行する
      (実際にはnpm init -yで色々とスキップした)
    2. npm install typescriptを実行する
    3. tsconfig.jsonを生成するためnpx tsc --initを実行する
      (実際には、ChatGPTが出力したtsconfig.jsonをコピペした)
  3. p5.jsを使う準備
    1. npm install p5を実行する
    2. p5.jsの型定義ファイルを使うためnpm install @types/p5を実行する
  4. webpackでバンドルする準備
    1. npm install --save-dev webpack webpack-cli ts-loaderを実行する
    2. webpack.config.jsを生成するためnpx webpack initを実行する
      (実際には、ChatGPTが出力したwebpack.config.jsをコピペした)
    3. ホットリロードを有効にするため、webpack.config.jsentrydevServerの設定を追加する
    4. package.jsonscriptswebpack serve --mode development --openを追加する
  5. スケッチを表示する
    1. index.htmlを作成し、webpackがバンドルしたjsファイルを読み込むようにする
      (今回は、ChatGPTが出力したHTMLをほぼそのまま使った) (index.htmlを置く場所は、webpack.config.jsのdevServerにも記載のある dist ディレクトリ)
    2. npm run startを実行する

tsconfig.json #

ChatGPTが出力したものをコピペした。コメントアウトも一緒に出力してくれた。 設定内容の細かいことは分かっていないので、詳細や必要最低限のセットアップがわかったら、随時更新するつもり。

{
    "compilerOptions": {
      "target": "es6",                     // 出力するJavaScriptのバージョンを指定
      "module": "es6",                     // モジュールシステムを指定
      "strict": true,                      // 厳格な型チェックを有効にする
      "esModuleInterop": true,             // ESモジュールとCommonJSの互換性を提供
      "forceConsistentCasingInFileNames": true, // ファイル名の大文字小文字の一貫性を強制
      "skipLibCheck": true,                // 型定義ファイルのチェックをスキップ
      "outDir": "./dist",                  // 出力ディレクトリを指定
      "rootDir": "./src",                  // ソースファイルのルートディレクトリを指定
      "moduleResolution": "node",          // Node.js のモジュール解決を使用
      "allowSyntheticDefaultImports": true, // デフォルトインポートのシンセティックを許可
      "allowJs": true,
    },
    "include": ["src/**/*"],               // コンパイル対象のファイルを指定
    "exclude": ["node_modules"]            // 除外するファイルを指定
}

webpackでも似たようなことを書くので、もしかしたらrootDirやoutDirは不要かもしれない。

webpack.config.js #

こちらは、ChatGPTが出力したものをベースにしつつ、dev.toのポストで見つけたコードを合体した。 細かな設定内容は理解していないので、わかってきたら更新したい。

const path = require('path');

module.exports = {
  entry: './src/main.ts',
  module: {
    rules: [
      {
        test: /\.tsx?$/,
        use: 'ts-loader',
        exclude: /node_modules/,
      },
    ],
  },
  resolve: {
    extensions: ['.tsx', '.ts', '.js'],
  },
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
  devServer: {
    static: './dist',
  },
};

package.json #

package.jsonは自動生成の部分が大半だけど、全体を載せておく。scriptsstartさえあれば良い。

{
  "name": "p5practice",
  "version": "1.0.0",
  "scripts": {
    "build": "webpack --mode development",
    "watch": "webpack --mode development --watch",
    "start": "webpack serve --mode development --open"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "description": "",
  "dependencies": {
    "@types/p5": "^1.7.6",
    "p5": "^1.10.0",
    "typescript": "^5.5.4"
  },
  "devDependencies": {
    "ts-loader": "^9.5.1",
    "webpack": "^5.93.0",
    "webpack-cli": "^5.1.4",
    "webpack-dev-server": "^5.0.4"
  }
}

src/main.ts #

main.tsに、スケッチを実装していく。 TypeScriptでp5.jsを使う場合、p5オブジェクトを経由して処理を呼び出すインスタンスモードで書く方が安全で、Java版やWeb版で見慣れた書き方(p5.jsではグローバルモードと呼ぶ)で書くには工夫が必要のようだった。 インスタンスモードでも見慣れた雰囲気にしたくてsetupdrawの定義と、p5オブジェクトにセットする処理を分けて書いたけど、即時関数や無名関数で直接渡しても大丈夫のはず。

import p5 from 'p5';

const sketch = (p: p5) => {
  function setup() {
    p.createCanvas(p.windowWidth, p.windowHeight);
  };

  function draw() {
    p.background(255);
    p.textSize(20);
    p.textAlign('center');
    p.text(new Date(), p.width/2, p.height/2);
  };

  function windowResized(event?: object) {
    p.resizeCanvas(p.windowWidth, p.windowHeight, false);
  };

  p.setup = setup;
  p.draw = draw;
  p.windowResized = windowResized;
};

new p5(sketch);

index.html #

bundle.jsを読み込むだけ。 bodyが初期スタイルなので、スタイルを直接調整した。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>P5 Project</title>
</head>
<body style="margin: 0px; overflow: hidden;">
    <script src="bundle.js"></script>
</body>
</html>

これでとりあえず表示はできるようになった。