[備忘録] Webpack で CreateJS（EaselJS） などを読み込むための設定（+ ES2015設定 & WebStorm設定）

*  Webpack 自体が初めてな人は、[ここ](http://c16e.com/1510161700/)	の React チュートリアルから始めてみるとスムーズに Webpack を使い始められるかも。

*  Webpack の基本的な使い方やローダーの概念については、[ここ](http://qiita.com/howdy39/items/48d85c430f90a21075cd) が役立ちました。

###  準備

*  作業ディレクトリの作成＆移動。
    -  `mkdir プロジェクト名`
    -  `cd プロジェクト名`

*  CreateJS は Bower　経由でインストールすることとします。
    -  `npm install -g bower`
    -  `bower init`
    -  `bower install --save EaselJS`
    
*  また、`webpack` のほかに、`exports-loader` と `imports-loader` が必要となります。
    -  `npm init -y`
    -  `npm install --save-dev webpack imports-loader exports-loader`

###  webpack.config.js

*  Webpack のコンフィグはこんなかんじ。
*  以下を参考にしました。
    -  <https://github.com/eskab/createjs-boilerplate>
    -  <https://github.com/CreateJS/EaselJS/issues/713>
    -  <https://github.com/CreateJS/PreloadJS/issues/85>

```js
var path = require('path');
var webpack = require('webpack');
var bowerResolver = new webpack.ResolverPlugin(new webpack.ResolverPlugin.DirectoryDescriptionFilePlugin('bower.json', ['main']));

module.exports = {
    entry: path.join(__dirname, 'src', 'main.js'),
    output: {
        path: path.join(__dirname, 'dist'),
        filename: 'bundle.js'
    },
    devtool: 'source-map',
    module: {
        loaders: [
            {
                // Webpack に CreateJS のライブラリでは `this` に `window` を参照させ、`window.createjs` を export するように設定
                test: /bower_components(\/|\\)(PreloadJS|SoundJS|EaselJS|TweenJS)(\/|\\).*\.js$/,
                loader: 'imports?this=>window!exports?window.createjs'
            },
        ]
    },
    plugins: [
        // Webpack に bower モジュールの main ファイルを発見させる
        bowerResolver
    ],
    resolve: {
        // bower_components をモジュールのルートディレクトリに追加
        modulesDirectories: ['node_modules', 'bower_components']
    }
};
```

###  src/main.js

*  EaselJS を利用する側ではこんな感じでコードを書けます。
    -  ※ 追記： ついうっかり ES2015 スタイルでコードを書いていたので、ES5 スタイルに修正しました。

```js
var createjs = require('EaselJS');

(function() {
    // CreateJS (EaselJS) の動作チェック
    console.log( createjs );

    var stage = new createjs.Stage(canvas);

    var circle = new createjs.Shape();
    circle.graphics.beginFill("DeepSkyBlue").drawCircle(0, 0, 50);
    circle.x = 100;
    circle.y = 100;
    stage.addChild(circle);
    stage.update();

} ());

```

*  これで `npm run build` すれば、すべてのJSコードが一つにパッキングされた `bundle.js` が生成されます！



###  babel を使って ES2015 スタイルで書きたい

*  まずはパッケージをインストール。
    -  `npm install --save-dev babel-loader babel-core babel-preset-es2015 babel-preset-stage-2`
    -  `babel-preset-stage-2` もインストールしておくと、さらに最近の追加仕様が使えるらしい （展開（スプレッド）演算子とか）。<http://stefan.magnuson.co/articles/frontend/using-es7-spread-operator-with-webpack/>
    
*  babel を使うので `.babelrc` を作成します。

```json
{
    'presets': ['es2015', 'stage-2']
}
```

*  `webpack.config.js` は以下のような形になる.

```js
var path = require('path');
var webpack = require('webpack');
var bowerResolver = new webpack.ResolverPlugin(new webpack.ResolverPlugin.DirectoryDescriptionFilePlugin('bower.json', ['main']));

module.exports = {
    entry: path.join(__dirname, 'src', 'main.js'),
    output: {
        path: path.join(__dirname, 'dist'),
        filename: 'bundle.js'
    },
    devtool: 'source-map',
    module: {
        loaders: [
            {
                // Babel で JS コードを ES6 -> ES5 変換
                test: /\.js$/,
                exclude: /node_modules|bower_components/,
                loader: 'babel-loader'
            },
            {
                // Webpack に CreateJS のライブラリでは `this` に `window` を参照させ、`window.createjs` を export するように設定
                test: /bower_components(\/|\\)(PreloadJS|SoundJS|EaselJS|TweenJS)(\/|\\).*\.js$/,
                loader: 'imports?this=>window!exports?window.createjs'
            },
        ]
    },
    plugins: [
        // Webpack に bower モジュールの main ファイルを発見させる
        bowerResolver
    ],
    resolve: {
        // bower_components をモジュールのルートディレクトリに追加
        modulesDirectories: ['node_modules', 'bower_components']
    }
};
```

*  ソースコード側は以下のようになる.
    -  参考： <http://blog.unshift.xyz/easeljs-custom-display-objects-in-es2015/>

*  `src/main.js`

```js
import * as createjs from 'EaselJS';

// 特定のオブジェクトだけ読み込むなら以下のように記述
// import { Stage, Ticker } from 'EaselJS';

{
    // CreateJS (EaselJS) の動作チェック
    console.log( createjs );

    const stage = new createjs.Stage(canvas);
    // const stage = new Stage(canvas);

    let circle = new createjs.Shape();
    circle.graphics.beginFill("DeepSkyBlue").drawCircle(0, 0, 50);
    circle.x = 100;
    circle.y = 100;
    stage.addChild(circle);
    stage.update();

    // CreateJS 継承テスト
    const btn1 = new CircleButton('Hi');
    btn1.x = 50;
    btn1.y = 50;
    stage.addChild(btn1);

    const btn2 = new CircleButton('Hello', 'purple', 50);
    btn2.x = 200;
    btn2.y = 50;
    stage.addChild(btn2);
    stage.update();

    console.log("OK");
}
```

*  `src/CircleButton.js`

```js
// CircleButton.js
// http://blog.unshift.xyz/easeljs-custom-display-objects-in-es2015/

import * as createjs from 'EaselJS';

class CircleButton extends createjs.Container {
    constructor(text = '', color = '#222', radius = 40) {
        // Container のコンストラクタ呼び出し
        super();

        // プロパティを設定する
        this.text = text;
        this.radius = radius;
        this.color = color;

        // コンポーネントの初期化
        this.setup();
    }

    setup() {
        // circle のシェイプを作成
        const circle = new createjs.Shape();
        circle.graphics.beginFill(this.color).drawCircle(0, 0, this.radius);
        this.addChild(circle);

        // テキストを作成
        const txt = new createjs.Text(this.text, "20px Arial", "white");
        this.addChild(txt);

        // circle 内の中央にテキストを配置
        txt.x = txt.getMeasuredWidth() / 2 * -1;
        txt.y = txt.getMeasuredHeight() / 2 * -1;
    }
}

export default createjs.promote(CircleButton, "Container");
```

###  Bootstrap 使いたい

*  jQuery や Bootstrap もインストールしましょう.
    -  `bower install --save jquery`
    -  `bower install --save bootstrap`

*  webpack.config.js はこんな感じ。

```js
var path = require('path');
var webpack = require('webpack');
var bowerResolver = new webpack.ResolverPlugin(new webpack.ResolverPlugin.DirectoryDescriptionFilePlugin('bower.json', ['main']));

module.exports = {
    entry: path.join(__dirname, 'src', 'main.js'),
    output: {
        path: path.join(__dirname, 'dist'),
        filename: 'bundle.js'
    },
    devtool: 'source-map',
    module: {
        loaders: [
            {
                // Babel で JS コードを ES6 -> ES5 変換
                test: /\.js$/,
                exclude: /node_modules|bower_components/,
                loader: 'babel-loader'
            },
            {
                // Webpack に CreateJS のライブラリでは `this` に `window` を参照させ、`window.createjs` を export するように設定
                test: /bower_components(\/|\\)(PreloadJS|SoundJS|EaselJS|TweenJS)(\/|\\).*\.js$/,
                loader: 'imports?this=>window!exports?window.createjs'
            },
            {
                // Webpack に Bootstrap を参照するときには jQuery が定義された状態としておく.
                test: /bower_components(\/|\\)(bootstrap)(\/|\\).*\.js$/,
                loader: 'imports?jQuery=jquery'
            }
        ]
    },
    plugins: [
        // Webpack に bower モジュールの main ファイルを発見させる
        bowerResolver
    ],
    resolve: {
        // bower_components をモジュールのルートディレクトリに追加
        modulesDirectories: ['node_modules', 'bower_components']
    }
};
```

*  ソースコード側はこんな感じ。

```js
import $ from 'jquery';
import * as createjs from 'EaselJS';

// 特定のオブジェクトだけ読み込むなら以下のように記述
// import { Stage, Ticker } from 'EaselJS';

// Bootstrap 動作用 import
import * as bootstrap from 'bootstrap';

// 外部ファイルから読み込み
import CircleButton from './CircleButton';

{
    // jQuery の動作チェック
    console.log( $ );

    // CreateJS (EaselJS) の動作チェック
    console.log( createjs );

    const stage = new createjs.Stage(canvas);
    // const stage = new Stage(canvas);

    let circle = new createjs.Shape();
    circle.graphics.beginFill("DeepSkyBlue").drawCircle(0, 0, 50);
    circle.x = 100;
    circle.y = 100;
    stage.addChild(circle);
    stage.update();

    // CreateJS 継承テスト
    const btn1 = new CircleButton('Hi');
    btn1.x = 50;
    btn1.y = 50;
    stage.addChild(btn1);

    const btn2 = new CircleButton('Hello', 'purple', 50);
    btn2.x = 200;
    btn2.y = 50;
    stage.addChild(btn2);
    stage.update();
}
```

### Webstorm  で開発したいんだけど...

*  （注意） Mac 版 での操作となっています！

*  まずは WebStorm で ES2015/ES6 開発ができるように設定しましょう。
    -  `WebStorm` -> `Preferences...` -> `Languages & Frameworks` -> `JavaScript` と開く。
    -  `JavaScript Language Version` を `ECMAScript6` に設定し、 `Prefer strict mode` を有効化する。
    -  ただし、ES2015 のコードは Webpack でコンパイルするため、WebStorm の Babel watcher は有効化しない点に注意。
    
*  Run/Debug するたびに `npm run build` を実行させ、実行前に `bundle.js` を更新させるようにしましょう。
    -  一度 HTML ファイルをそのまま実行させ、`Run` ->  `Edit Configurations...` の中の Edit Configuration の一覧に `JavaScript Debug` が表示されている状態にしておきます。
    -  `JavaScript Debug` -> `index.html` と選択し、`Before launch: Activate tool window` の `+` から `Run npm scrip` を選択。
    -  `package.json` の場所を選択し、`Command` を `run-script` に、さらに `Scripts` を `build` に設定する. (`npm run XXXX` の `XXXX` の文字列を入力してください)
    -  これにより、index.html を Run/Debug するときに自動的に Webpack が起動し、bundle.js を更新するようになります。

###  WebStorm でリモートデバッグしたい！

*  さらに、実は WebStorm では、**もともとの ES2015 のソースコードに対してブレークポイントを設定** し、ブラウザ上で Webpack によって変換されたコードが実行される際に、**対応する ES2015 コード上のブレークポイントで動作を停止させることができます！**
    -  ここではブラウザとして Chrome を使うことを想定しています
    
*  まずはブラウザにプラグインを追加します
    -  <https://chrome.google.com/webstore/detail/jetbrains-ide-support/hmhgeddbohgjknpmjagkdomcpobmllji>
    
*  次に、[ここ](https://blog.jetbrains.com/webstorm/2015/09/debugging-webpack-applications-in-webstorm/) を参考に、WebStorm の設定を行います
    -  まず、Webpack によるビルド後のディレクトリを Excluded に設定する必要がある.
        +  今回は `bundle.js` が `dist` ディレクトリに配置されることを想定していますので、`dist` ディレクトリのアイコン上で右クリック -> `Mark Directory As` -> `Excluded` を選択.
    -  WebStorm がデバッグ時に立ち上げるビルトインWebサーバのポート番号を確認する.
        +  `WebStorm` -> `Preferences` -> `Build, Execution, Deployment` -> `Debugger` -> `Port` の値を覚えておく.
    -  `Run` -> `Edit Configurations...` -> `JavaScript Debug` と順番に開く.
    -  この画面上で、プロジェクトの `RemoteURL` を `webpack:///.` に設定する.
    -  その後、`Excluded` に設定した `dist` ディレクトリの `Remote URL` を `http://localhost:ポート番号/debugging-webpack/dist` に設定する.
    -  設定後の画面は以下のようになります。
    
<img width="1376" alt="webstorm_debugging.png" src="https://qiita-image-store.s3.amazonaws.com/0/96400/1b3186fb-3880-945f-9fcb-0a07632456af.png">

*  この設定後、WebStorm 上で Debug を実行すると、ブレークポイント実行が行えるようになります！