１からwebpackでJSファイルをまとめてみるまで。

# はじめに

仕事以外のときは遊びたい自分はいろいろと情報社会から取り残されがちなのですが、そうしてアイドルにキンブレ振ってる間にも世間は無情にも時が進んでいます。
そのうち情報化社会の荒波は自社プロダクトにも影響してきて、知識がないといろいろ弊害が出て来るポイントがやってきます(経験者談)。それが僕の場合はwebpack(とかnpmとか)でした。

ミドルウェアなどの直接プロダクトなんかに影響する技術はしっかりと検証や実績が積まれないと怖くて投入できないのに対して、開発ツール系はアウトプットさえしっかり担保できていれば比較的現場に投入しやすいため、webpackやなんかはぱっぱと組み込まれいきました。

自分の開発範囲ではフロントエンドは普段あまりいじらないとは言え全く触らないわけでもなく、たまたまちょっとだけAPIのパラメータを調整するタスクがあったときに見てみたら、JSを読み込むのはlayoutに書かれた 

```html:
<script src="/js/bundle.js"></script>
```

の1行のみ。一体何が起こっているのか理解しようにも、すでに大小様々な思惑で膨れ上がった package.json や webpack.config.js を読み解けるはずもなく。

```text:天の声
「js更新したので `npm run build` してください〜」
```

とか言われてももはや詠唱にしか聞こえないのでそろそろ勉強しようかと立ち上がった次第です。

自分の勉強がてらやったことなので日記のようにお読みくださいませ。

# npmとwebpack環境を用意する

## 1. npmの実行環境を用意

npm や node, rubyなどは結構人によって環境がまちまちなので、まっさらサーバを想定します。すでに自分のマシンやサーバがnpmとnodeコマンドを打てる状態ならばこの部分には既読フラグが立っています。

自分のMacやレンタルサーバ等なんでもOKです。勉強用にいろいろいじるだけいじってあとでサクッとポイできるように自分は Docker 使います。

```bash
~$ docker pull ubuntu:16.04
~$ docker run -i -t -d ubuntu:16.04
~$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
130d4061ce59        ubuntu:16.04        "/bin/bash"         3 seconds ago       Up 2 seconds                            nostalgic_heisenberg
~$ docker exec -it nostalgic_heisenberg bash
root@130d4061ce59:/# 
```

ノスタルジックなハイゼンベルグさんが産まれました。dockerのランダム命名結構クセになる。

というわけでnpmをまずはインストールしましょう。

```bash
root@130d4061ce59:/# apt-get update
root@130d4061ce59:/# apt-get install npm
```

ただ、無事入ったところで node のバージョンを見てみようとすると、node というコマンドが無く、nodejsというコマンドが代わりにあります。
いろいろ調べてみてもきっとおそらく一緒なんですが、困ったことにnpmやなんかで利用されるスクリプトのシェバン(← 一行目の#!のアレ)は `node` を利用しているので、symlinkでお茶を濁しておきます。

```bash
root@130d4061ce59:/# which nodejs
/usr/bin/nodejs
root@130d4061ce59:/# cd /usr/bin
root@130d4061ce59:/# ln -s nodejs node
```

## 2. プロジェクトを用意

一個ディレクトリ掘って簡単なそれっぽい構成を作りましょう。

```bash
root@130d4061ce59:~# mkdir test_pjt && cd !!^
root@130d4061ce59:~/test_pjt# mkdir -p public/js assets/javascript
```

こんな想定。

```text
test_pjt/
 + public/             ... DocumentRoot(を想定)
 |       + js/         ... 公開用jsファイル置き場
 + assets/             ... 生成元の開発コード置き場
         + javascript/ main.js
                       sub01.js
```

```javascript:main.js
document.write('Hello, I am Main.');
```

```javascript:sub01.js
document.write('Nullpo! We are sub01.');
```


## 3. npm 初期化

いよいよnpmを実行します。まずはinitで初期化宣言すると、そのディレクトリでのnpmの振る舞いやなんかを定義できる `package.json` が生成されます。

```bash:
root@130d4061ce59:~/test_pjt# npm init
:
: (いろいろ対話プロンプトがでてくるので全部そのままEnterでOK)
:
Is this ok? (yes) 
root@130d4061ce59:~/test_pjt# cat package.json 
{
  "name": "test_pjt",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}
```

だいぶスッキリしてます。
プロダクトのpackage.jsonのあのものすごい量はなんなんだろう


## 4. webpackのインストール

グローバルにコマンドとしてインストールすることもできますが、リポジトリによってnpmのバージョンが違うなどいろいろ大人の事情があったりして、こういうのはできるだけ環境で閉じた方がベターな気がするので、迷ったらとりあえずローカル(プロジェクト内)へインストールした方が外への影響はありません。

```bash:
root@130d4061ce59:~/test_pjt# npm install webpack
```

これで `node_modules/` というディレクトリが出来上がって、依存するパッケージ等もつられてなんかものすごく配置されます。webpackもグローバルへはインストールしていなくてパスが通っていないですが、直接実行して確認することはできます。

```bash:
root@130d4061ce59:~/test_pjt# ./node_modules/.bin/webpack            
webpack 1.13.2
:
```

# webpackを動かす

## 1. 引数で動かす

まずは直接動かしてみます。 (パス通ってないのでちょっと面倒ですが)

引数にはまとめるファイルを列挙した後、最後に出力するファイル名を渡します。

```bash:単一のファイルの場合
root@130d4061ce59:~/test_pjt# ./node_modules/.bin/webpack assets/javascript/main.js public/js/bundle.js
Hash: 53b52dfd2bb40f253491
Version: webpack 1.13.2
Time: 41ms
    Asset     Size  Chunks             Chunk Names
bundle.js  1.43 kB       0  [emitted]  main
   [0] ./assets/javascript/main.js 37 bytes {0} [built] 
```

```bash:複数のファイルの場合
root@130d4061ce59:~/test_pjt# ./node_modules/.bin/webpack assets/javascript/* public/js/bundle.js
```

これでbundle.jsを見てみると、最初にだばだばwebpackっぽいコードが並んだ後に最後にmain.jsやsub01.jsのコードが組み込まれているのが確認できると思います。おめでとうございます。あなたはwebpackのメダルを手に入れました。

## 2. webpack.config.jsにする

とはいえ毎回引数に指定するのは面倒なので、コンフィグファイルをおいてくことで引数を省略することができます。プロジェクトのrootへ `webpack.config.js` を配置しましょう。

```bash:
root@130d4061ce59:~/test_pjt# cat webpack.config.js
module.exports = {
  entry: [ // 入力ファイルリスト
    __dirname + '/assets/javascript/main.js',
    __dirname + '/assets/javascript/sub01.js',
  ],
  output: { // 出力ファイル
    path: __dirname + '/public/js',
    filename: 'bundle.js',
  }
};
```

これでこのディレクトリにいる状態で引数なしでwebpackを実行すれば先程と同様の結果が確認できます。

```bash:
root@130d4061ce59:~/test_pjt# ./node_modules/.bin/webpack 
Hash: 54edb83ebe38ab7697f4
Version: webpack 1.13.2
Time: 43ms
    Asset     Size  Chunks             Chunk Names
bundle.js  1.66 kB       0  [emitted]  main
   [0] multi main 40 bytes {0} [built]
   [1] ./assets/javascript/main.js 37 bytes {0} [built]
   [2] ./assets/javascript/sub01.js 41 bytes {0} [built]
```

## 3. npmのタスクにする

ここまで理解してから、webpackはそもそもnpm内のモジュールとしていれているので、npmのタスクにするまでが遠足だということを思い出しましょう。

npmのタスクをいじるには、 `package.json` を編集します。

```json:package.json
{
  "name": "test_pjt",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack"
  },
  "author": "",
  "license": "ISC"
}
```

`scripts` の部分がタスクのリストになっていて、キーが `npm run 〜` に入れる部分に対応していて、値が実行する内容になります。
ここでのコマンドはもちろんローカルにインストールしたコマンドも利用できます。 (コマンドが用意されているものは `npm install` すると `node_modules/.bin/` にsymlinkが貼られます。)

ここでやりがちなのは、package.jsonは融通が利いてくれないため、配列の最後の要素の行末にカンマ入れたままにするとエラーになります。webpack.config.jsは融通が利いてくれるみたいです。

これでやっと最初の境地にたどり着けました。

```bash:
root@130d4061ce59:~/test_pjt# npm run build


> test_pjt@1.0.0 build /root/test_pjt
> webpack

Hash: 54edb83ebe38ab7697f4
:
```

おめでとうございます。あなたはnpmのメダルを手に入れました。

# リポジトリでの共有

## package.jsonへ依存関係を保存する

ここまでで自分の環境でwebpackをお手軽に実行できるようになりましたが、実際はリポジトリ配下で作業して他の開発者とも状態を共有しないとなりません。

ということで何を `npm install` したのかリストみたいなものをnpmさんに教えてあげます。

```bash:
root@130d4061ce59:~/test_pjt# npm install --save-dev webpack
```

すでにinstallされているものでも大丈夫なので `--save-dev` つけて実行します。
ついでに、jqueryも取り込んでみたくなったので追加します。こっちは `--save` で。

```bash:
root@130d4061ce59:~/test_pjt# npm install --save jquery
```

こうすることで `package.json` に以下のように追加されているハズです。(バージョンはお気になさらず)

```json:package.json
{
  :
  "devDependencies": {
    "webpack": "^1.13.2"
  },
  "dependencies": {
    "jquery": "^3.1.1"
  }
}
```

`--save-dev` は開発環境において必要で、devDependencies に記述されます。
`--save` は本番環境のみにおいて必要で、dependencies に記述されます。ビルド時に必要なモジュールなどの本番環境で不要なものはdevの方へ置くと吉です。

これでnpmさんは自分が何をinstallすべきなのかわかるようになったので、一旦node_modules/ディレクトリを消してから `npm install` と引数にパッケージを指定しないで実行しても、package.jsonから自動で読み取って同様のものがすべてインストールされるでしょう。

## リポジトリの設定

node_modules/ 配下は `npm install` にて自動で生成されるものなので、ディレクトリごとコミットしないような設定 (.gitignore等) にしてあげましょう。
package.jsonのみコミットしておけば、他の開発者は `npm install` するだけで環境を揃えることができるようになります。

# おわりに

ここまでわかればあとは設定ファイルがどんなに複雑になっていても、「入力」と「出力」の間に何かいろいろしてるんだな、とかブラックボックスのままでもいいのである程度の予想が立てられるようになるのではないかなと思います。

プログラムも一緒で、基本的には「何をもらって」「何を返す」の繰り返しなので、大きな流れがよくわからなくなったら、１つ１つに分解して少しずつ理解するだけでもだいぶ理解度は上がると思います。

実際、開発を一人で切り盛りしているのでもなければ、会社やグループなどの中にそれぞれの方面へ精通しているメンバーがいて、そのメンバーの言うがままに導入すれば動くよ、っていうモジュールが増えてきて、気がついたらいろんなものが入り乱れてワケワカメになることも多々あるかと思いますし、お仕事で開発しているならば全員が全部理解するまでの時間が無いことも多かろうと思いますし、そもそも全員が理解する必要もないものもあるかと思います。

そういう部分こそnpmなどの「どの環境で実行しても設定ファイルと同じ状態にしてくれる」パワーが最大限に発揮される場面でしょうか。

それでも行き詰まったり知らないものを知りたくなったときは、一度最初から出直してみると意外なところに発見もあったりしてオススメです。

なんか思いついたことをさらさら書いてたらそれっぽいこと言ってる風でわりと普通のこと言ってる気がしてきた。