webpack + babelを使ってRPGツクールMVのプラグインを書いてみた その1

筆者はツクールシリーズは完全な初心者で、Javascriptは少し書いたことがある程度の趣味プログラマですので、誤りや不十分な点もあるかと思います。お気づきの点があればご指摘頂ければ幸いです。
尚、webpackやBabelやES2015、npmやgitなどの説明はしません。

# 作業環境
[RPGツクールMV 1.3.4](https://tkool.jp/mv/)
Windows10 64bit
Node.js 7.3.0
npm 3.10.10

# 問題意識
ツクールMVのプラグインを書くにあたって、ES5で書くのツライ。1プラグイン1ファイルだとでかすぎてツライ。

# やったこと
複数のES2015のソースをwebpack + BabelでツクールMVのプラグインにビルドできるようにした。
ついでにMocha ESLint ESDocも入れた。これらは次回書きます。（[書きました](http://qiita.com/betto/items/0b38ed2efe066c87621d)）

# 本題
## 作成するプラグイン
例として、猫が挨拶をするプラグインを作ることを考えます。
* 猫は「名前」と「メッセージ」を持っている
* 複数の猫のデータを登録しておく
* プラグインコマンドで`CatGreet id`とやるとid番目の猫の挨拶が表示される

本来なら猫のデータはjsonにしておいて読み込みこんだりするかと思いますが、簡単のためプラグイン内に直接書くことにします。

こんな感じで動くようにします。
![1.png](https://qiita-image-store.s3.amazonaws.com/0/162022/a15b629b-949d-9221-37b9-e85df2b79932.png)

## 普通に書く
通常の方法で書くと例えば次のようなコードになると思います。この程度の内容だとCatをクラス[^1]に切り出す意味はあまりないですが、ある程度複雑なことをやろうとすると自作のクラスをいくつも用意することもあるかと思います。

[^1]: 厳密にはJavascriptにクラスは存在しないので、クラスっぽく扱えるオブジェクト。

```javascript:CatGreetingPlugin.js
//=============================================================================
// CatGreetingPlugin.js
//=============================================================================

/*:
 * @plugindesc 猫が挨拶してくれるプラグイン
 * @author betto
 *
 * @help
 *
 * プラグインコマンド:
 *   CatGreet id # id番目の猫が挨拶する(idは1オリジン)
 */

(function() {
    //-----------------------------------------------------------------------------
    // Catクラス定義

    var Cat = function(name, message) {
        this.name = name
        this.message = message || 'にゃー'
    }

    // 挨拶用の文字列を返す
    Cat.prototype.greet = function() {
        return this.name + ": " + this.message
    }

    //-----------------------------------------------------------------------------
    // プラグイン本体

    // 猫のリスト
    var cats = [
        new Cat('たま'),
        new Cat('シロ', 'みゃ～'),
        new Cat('クロ', '……')
    ]

    // プラグインコマンドの登録
    var _Game_Interpreter_pluginCommand = Game_Interpreter.prototype.pluginCommand
    Game_Interpreter.prototype.pluginCommand = function (command, args) {
        _Game_Interpreter_pluginCommand.call(this, command, args)
        if (command === 'CatGreet') {
            $gameMessage.add(cats[args - 1].greet())
        }
    }
})()
```

## こう書きたい
Catクラスを別ファイルに分けて、更にES2015の機能を使うと次のように書けて幸せです。
いや、実際はこの分量だと大して幸せではないんですが、幸せな将来に繋がりそうです。

```javascript:CatGreetingPlugin.js
（コメント部分省略）
import Cat from './Cat'

// 猫のリスト
const cats = [
    new Cat('たま'),
    new Cat('シロ', 'みゃ～'),
    new Cat('クロ', '……')
]

// プラグインコマンドの登録
const _Game_Interpreter_pluginCommand = Game_Interpreter.prototype.pluginCommand
Game_Interpreter.prototype.pluginCommand = (command, args) => {
    _Game_Interpreter_pluginCommand.call(this, command, args)
    if (command === 'CatGreet') {
        $gameMessage.add(cats[args - 1].greet())
    }
}

```

```javascript:Cat.js
export default class Cat {
    constructor(name, message = 'にゃー') {
        this.name = name
        this.message = message
    }

    // 挨拶を文字列で返す
    greet() {
        return `${this.name}: ${this.message}`
    }
}
```

##ビルド環境を作る
ここからツールを入れていきますが、ツクールMVで触るディレクトリは通常の状態を維持して、その一つ外側にいろいろと置くことにします。

まずcat-greetingというディレクトリを作って、その中にツクールMVのプロジェクトをmvという名前で作成します。（既存のものを移動してリネームしても大丈夫です。たぶん。）

cat-greeting/src/CatGreetingPluginというディレクトリを作って、先ほどのCat.jsとCatGreetingPlugin.jsを入れます。

コマンドプロンプトないしはpowershellを起動して、cat-greetingディレクトリで以下のコマンドを実行します。[^2]

[^2]: ちなみに、エクスプローラのアドレスバーにcmdやpowershellと打つと、そのディレクトリをカレントディレクトリにして開けるので便利です。

```
npm init -y
npm i -D babel-core babel-loader babel-preset-es2015 webpack
```

webpackの設定ファイルを書きます。

```webpack.config.js
/*
 * src以下のディレクトリがそれぞれプラグインにあたるものとしてビルドする
 * 各ディレクトリの下にある同名のファイルをエントリーポイントとする
 * 例)
 * src
 * ├ HogePlugin
 * │ ├ HogePlugin.js
 * │ └（HogePluginからimportされるファイルなど）
 * └ HugaPlugin
 * 　 ├ HugaPlugin.js
 *  　└（HugaPluginからimportされるファイルなど）
 */
const fs = require("fs");
const inputPath = __dirname + "/src/";
const outputPath = __dirname + "/mv/js/plugins/";

const entries = {};
const fileNames = fs.readdirSync(inputPath);
fileNames.forEach(function(name) {
  const path = inputPath + name;
  if(fs.statSync(path).isDirectory()) {
    entries[name] = path + "/" + name;
  }
});

module.exports = {
  entry: entries,
  output: {
    path: outputPath,
    filename: '[name].js'
  },
  module: {
    loaders: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: 'babel-loader',
      }
    ],
  },
  resolve: {
    extensions: ['', '.js']
  }
}
```

簡単にwebpackを実行できるようにしておきます。

```diff:package.json（差分）
   "scripts": {
-     "test": "echo \"Error: no test specified\" && exit 1"
+     "build": "webpack"
   },
```

ここまでのディレクトリ構成はこんな感じです。

```
cat-greeting
├ mv
│ ├ Game.rpgproject
│ └ （その他、いつものMVのやつ）
├ node_modules
│ └ （略）
├ src
│ └ CatGreetingPlugin
│ 　├ Cat.js
│　 └ CatGreetingPlugin.js
├ package.json
└ webpack.config.js
```

いざ、

```
npm run build
```
cat-greeting/mv/js/plugins/CatGreetingPlugin.jsを確認すると、なんだかぐちゃぐちゃしていますが二つのファイルの内容が含まれることがなんとなくわかるかと思います。

MVのメニューからテストプレイをしてみると、初めの場合と同じように動作することが確認できます。やり遂げました。

# 課題
最終的に完成するjsファイルは機械的な変換を経ているので読み辛いです。本来的には改良などは変換前のソースで行えば良いので問題にならないしそれこそminifyしてしまってもいいんでしょうが、ツクールのプラグインとして配布する場合にはユーザーが改造したい場合もあると思うので問題です。

関連してですが、プラグインコメントが真ん中のほうに埋もれてしまいます。ツクールMVのプラグイン管理から見ると認識はしてくれるものの説明やヘルプに無駄な*が表示されてしまいますね（タブが挿入されるのが問題なのかな）。

[その2](http://qiita.com/betto/items/0b38ed2efe066c87621d)として、プラグインコメントの改善と、Mocha ESLint ESDocの利用について書きました。