Webpack の練習

時間を取って Webpack を勉強した。最近の Javascript について謎だらけで苦しんでいたが、謎な挙動のほとんどは Webpack だという事が分かった。Webpack は Javascript 界のリンカみたいなツールだが、色んな事が出来すぎて分かりにくかった。Webpack と npm だけで開発に必要な雑多なタスクはだいたい何でも揃うようになっている。Javascript 界特有の事情として、折角 Webpack を覚えてもすぐ他の技術にとって取って代わられるような気もするが、現状トランスパイラも Webpack から起動するようになってるので、Javascript 技術に追いつくスタート地点としては良いと思う。

開発環境構築方法の大まかな手順は、Webpack 設定ファイル (デフォルトで webpack.config.js) に好きな設定を書いて、package.json の scripts にコマンドラインを書き、npm run で実行する事になる。

とりあえずチュートリアル通り https://webpack.js.org/guides/get-started/ にやってみる。 以下作業ログです。

準備
----

    npm init -y
    npm install --save-dev webpack
    mkdir app

Webpack を使わない例
-------------------

* app/index.js を編集
* index.html を編集
    * index.html が https://unpkg.com/lodash@4.16.6 と app/index.js を読み込むようになっている。
* サンプルでは、lodash というライブラリを使って説明している。
    * lodash とは? https://lodash.com/ _ という名前に便利関数が入っている。最近あまり使われない?

チュートリアルでは、Webpack を使わない例から始めて Webpack で依存ファイルを一つにまとめてゆく。

Webpack を使った例
-----------------

* lodash をローカルに含める
    * npm install --save lodash
* index.html: https://unpkg.com/lodash@4.16.6 を script で参照する代わりに、index.js 内で import する。
    * import _ from 'lodash';
* index.html: app/index.js を参照する代わりに dist/bundle.js のようなファイルを指定する。

以下を実行すると Webpack は app/index.js の import 文を元に依存を解決して dist/bundle.js を作ってくれる。bundle.js は lodash と index.js を含んだ長いファイル。
Webpack は ES2015 の module import 文を使って依存を解決するが、module 文以外は何もしない。

    ./node_modules/.bin/webpack app/index.js dist/bundle.js

設定ファイル
----------

./node_modules/.bin/webpack を実行する代わりに設定ファイル webpack.config.js を使うと引数を指定しなくて良い。

また、

    "scripts": {
      "build": "webpack"
    },

を package.json に書くと npm run build でビルドできる。

大事なポイント: https://webpack.js.org/concepts/

* entry: 依存ツリーの最初
* output: 出力先
* loaders: js ファイル以外を import する方法を指定する
* plugins: TBD

bundle.js 内に画像を含める
------------------------
```
module: {
  rules: [
    {
      test: /\.(jpg|png)$/,
      loader: 'url-loader',
    }
  ]    
},
```
のようにすると、jpg と png が url としてロードされるのでそのまま img src に入れる事が出来る。
昔は module.loaders だったが　webpack2 で module.rules に変わった。

source-map
----------

 `devtool: 'source-map'` を webpack.config.js に含めるとブラウザの developer tools で bundle.js の代わりに元のファイルを参照出来るようになる。'source-map' は重いらしく、create-react-app では代わりに 'cheap-module-source-map' を指定している。
 
 source-map はそれ自体非常に面白い技術だが、代表的と言えるようなサイトが見つからなかった
 * https://github.com/ryanseddon/source-map/wiki/Source-maps:-languages,-tools-and-other-info
 * spec: https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/preview

webpack-dev-server
------------------

開発時に webpack を毎度実行すると遅いので、開発には webpack-dev-server を使う。

    npm install --save-dev webpack-dev-server 

./node_modules/.bin/webpack-dev-server を実行すると、デフォルトで http://localhost:8080/bundle.js に纏まった物が出来るが実際にファイルとしては書き込まない。
bundle.js の位置を変えるには publicPath: "/dist/" のようにパスを webpack.config.js に指定する。

npm で動かすには `"start": "webpack-dev-server"` を package.json に足すと `npm run start` で起動するようになる。

`--inline --hot` オプションが紹介されているが、無くてもちゃんとリロードされるし、目的が分からなかった。

Typescript
----------------
https://webpack.js.org/guides/webpack-and-typescript/

    npm install --save-dev typescript ts-loader
    touch tsconfig.json (このファイルは空でも動く)

webpack.config.js の module.rules と module.resolve に以下のような設定をすれば自動ビルド出来る。

```
module: {
  rules: [
    {
      test: /\.tsx?$/,
      loader: 'ts-loader',
      exclude: /node_modules/,
    },
  ],
},
resolve: {
 extensions: [".tsx", ".ts", ".js"]
},
```

resolve.extsnsions とは? import の from で拡張子を省略した場合に追加される拡張子。`import _ from 'lodash'` のように .js を付けなくても良いのは resolve.extensions で指定されているため。

webpack が module import 文をどう解決するか?
----------------

* ./ から始まると entry からの相対位置になる
* ./ 以外から始まると node_module にインストールされたものになる。
    * デフォルトのパス検索位置は resolve.modules で複数設定出来る。例: 
        ```
        resolve: {
          modules: [
            path.resolve(__dirname, 'app'),
            "node_modules"
          ],
          ```
    * https://webpack.js.org/configuration/resolve/#resolve-modules (これも webpack2 で変更)
    
エラーを HTML 画面に表示
---------------------
devServer.overlay 機能を使うと、エラーを HTML 画面に表示出来る。ちょっと create-react-app にもあるちょっと面白い機能。

    devServer: {
      overlay: true,
    }

引っかかったポイント
-----------------

* npm では、利用しているライブラリと同じ名前のプロジェクト名を付けられない。webpack という名前でテストプロジェクトを作っては駄目。

参考
----

* Webpack — The Confusing Parts
    * https://medium.com/@rajaraodv/webpack-the-confusing-parts-58712f8fcad9
    * 日本語訳: http://qiita.com/chuck0523/items/caacbf4137642cb175ec