npm とか bower とか一体何なんだよ！Javascript 界隈の文脈を理解しよう

## 背景

Javascript で Web アプリを作ろうとすると、よくわからないことだらけで超混乱します。

* npm と bower の違いは？
    * npm はサーバーサイド用、bower はクライアントサイド用らしいよ
    * えっ、でもなんで bower のインストールに npm が必要なの？
        * サーバーサイドは Rails で書きたいから npm 要らないと思うんだけど・・・
* ていうかサーバーサイドJSとか node.js って何？ 
* よく見る browserify って何？

こういった疑問が沸き上がるのは、各ツールが生まれた文脈がよくわかっていないからです。いろいろ調べてやっとちょっとわかってきたのでメモします。間違いがあったらご指摘ください。

## 「CommonJS」誕生 - Javascript は汎用プログラミング言語へ

その昔、Javascript 大好きおじさんは言いました。

> Javascript 最高！ブラウザで使うだけではもったいない！汎用言語にしよう！

しかし、そうは言っても Javascript には足りないものがたくさんありました。その最たるものがモジュール機能です。C言語なら `#include`、ruby なら `require`、golang なら `import`。どんな言語でも用意されている、他のファイルを読み込んで使えるようにする機能が、なんと Javascript には用意されていませんでした。

そこで2009年ごろ、まったく新しい汎用言語としての Javascript の仕様を策定する動きが発足しました。こうして生まれたのが **CommonJS** です。

CommonJS はあくまで仕様であり、CommonJS というライブラリが存在するわけではありません。Common Lisp みたいなものです。CommonJS の仕様に則って実装された処理系のひとつが、かの有名な **node.js** です。Common Lisp に対する CLisp みたいなものです。こうして Javascript は、めでたく ruby のような汎用スクリプト言語の仲間入りを果たしました。実際、node.js は ruby と同じように `node` コマンドでスクリプトを実行できます。

```bash
$ node helloworld.js
```

### 追記（2015/10/01）

現在 node.js は独自の進化を遂げ、もはや CommonJS に準拠していません（[参考1](https://www.reddit.com/r/node/comments/h1m2o/i_am_ryan_dahl_creator_of_nodejs_ama/c1rxntv)）（[参考2](https://github.com/nodejs/node-v0.x-archive/issues/5132#issuecomment-15432598)）。node.js のことは「CommonJS みたいなやつ」だと思っておいてください。

## CommonJS 界のパッケージ管理ツール「npm」誕生

実のところ、CommonJS の仕様策定はまだ全然終わっていません。それでも前述のモジュール機能はすぐに策定されたようで、もう使うことができます。そうなれば必然的に生まれてくるのが、gem や pip のようなパッケージ管理ツールです。

node.js の世界では、**npm** というパッケージ管理ツールを使います。npm のリポジトリに、node.js という言語で書かれた便利ツール達がどんどん追加されていきます。ここで、node.js はもはやブラウザという檻から外れた汎用言語なので、作られるツールも「コマンドラインで使って開発を楽にするツール」という趣が強いです。例えば、

* http-server : 簡易webサーバー。
* grunt : タスクランナー。
* bower : パッケージ管理ツール。

ん？

## ブラウザ用JS のためのパッケージ管理ツール「bower」

いま名前のあがった bower は、node.js ではなく、ブラウザで動く昔ながらの Javascript のためのパッケージ管理ツールです。パッケージの例としては、

* JQuery
* AngularJS
* パララックス（かっこいいスクロール）を実装できる君

など。昔ながらの Javascript といえどもパッケージに依存性はあるし、インストールも簡単になるので、パッケージ管理ツールが存在することによるメリットは十分にあるのです。

そして、**bower 自体は node.js で実装されています**。これが、bower を使うために npm をインストールしないといけなかった理由です。実際のサーバーサイドの開発に ruby を使おうが php を使おうが、bower という node.js で書かれたプログラムを実行するために、node.js という処理系が必要なのです。

なおややこしいことに、AngularJS など一部のメジャーなパッケージは（たとえそれがブラウザ上で動くライブラリであろうと）bower でも npm でも配布されています。2014年の11月に、npm のブログ上で「npm が統一リポジトリになりますよ」宣言が[公開](http://blog.npmjs.org/post/101775448305/npm-and-front-end-packaging)されたそうですが、あんまりちゃんと片付いてはいないようです。

## 「Browserify」誕生 - 天界と地上を繋ぐ魔法

繰り返しになりますが、node.js はブラウザという枠を外れて独自に進化した言語です。逆に言うと、node.js として書かれた Javascript はそのままではブラウザで動きません。ところが、node.js の持つモジュール機能や npm 上にある無数の便利ツールにすっかり慣れてしまった node.jser 達は、もはや素の Javascript には戻れない体になってしまいました。

そこで生み出されたのが **browserify** です。browserify を使うと、まるでC言語を機械語にコンパイルするように、**node.js スタイルで書かれたコードをブラウザ上で動くものに変換** することができます。普段は node.js スタイルの高級言語を使ってコーディングして、作業の最後にブラウザで動く低級言語に変換すればよいのです。

## 実践

実践で復習しましょう。上記のことがらを踏まえて、

* node.js のインストール
* npm で browserify をインストール
* CommonJS スタイルでコーディング
* browserify でブラウザ向けにビルドして表示

をやってみます。今度こそ理解できるはず！

### node.js のインストール

やり方はいろいろあると思いますが、Mac なら homebrew を使うのが簡単です。処理系をインストールするわけですから、homebrew を使うのは自然なことです。

```bash
$ brew install node.js
```

### npm で browserify をインストール

node.js をインストールすると、もう npm も使えるようになっています。最初に初期設定を行います。

```bash
$ mkdir npm_test
$ cd npm_test
$ npm init

(いろいろ聞かれるけど全部エンターで OK)
```

終わったら browserify をインストールしてみましょう。

```
npm install -g browserify
```

ここで、`-g` オプションはパッケージのグローバルインストールを意味します。browserify はいつでも使う便利ツールなのでシステム全体にインストールします。開発中のプロジェクト固有のパッケージをインストールするときは、`-g` オプションを外せば、プロジェクトフォルダの `node_module` フォルダ配下にダウンロードされます。

browserify という node.js 製の便利ツールをインストールするので、npm を使いました。これも自然に理解できると思います。

### CommonJS スタイルでコーディング

`npm_test` 配下に `src` フォルダを作って、こんなコードを準備してみます。

```js:src/add.js
// たし算モジュールを定義
module.exports = function (a, b) {
  return a + b;
};
```

```js:src/main.js
// たし算モジュールを読み込み
var add = require('./add');

var txt = document.createTextNode(add(114, 514));
document.body.appendChild(txt);
```

モジュールの定義と読み込みをやっているあたりに CommonJS を感じましょう。このままではブラウザで実行できません。

あわせて、表示用の html を準備します。

```html:index.html
<!DOCTYPE html>
<html>
    <head>
        <title>test</title>
    </head>
    <body>
        <script src="dest/build.js"></script>
    </body>
</html>
```

最後に、browserify でビルドした JS を出力するフォルダだけ作っておきましょう。

```bash
$ mkdir dest
```

現在のファイル構成はこんな感じです。

```
npm_test
├── dest
├── index.html
├── package.json
└── src
    ├── add.js
    └── main.js
```

### browserify でブラウザ向けにビルドして表示

いよいよビルドしましょう。

```bash
$ browserify src/main.js -o dest/build.js
```

上記を実行すると、`dest` フォルダに build.js が生成されます。

```js:dest/build.js
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
module.exports = function (a, b) {
  return a + b;
};

},{}],2:[function(require,module,exports){
var add = require('./add');

var txt = document.createTextNode(add(114, 514));
document.body.appendChild(txt);

},{"./add":1}]},{},[2]);
```

元コードで書いた `require` が解決されて、禍々しいコードが吐き出されています。index.html を開けば、めでたく足し算の結果が表示されているはずです。

## おわりに

ここまで読んで、冒頭に書いた疑問に答えられるようになっていれば幸いです。

> * npm と bower の違いは？
    * npm はサーバーサイド用、bower はクライアントサイド用らしいよ
    * えっ、でもなんで bower のインストールに npm が必要なの？
        * サーバーサイドは Rails で書きたいから npm 要らないと思うんだけど・・・
* ていうかサーバーサイドJSとか node.js って何？ 
* よく見る browserify って何？

### その他

#### browserify を毎回実行するのがめんどくさい件について

gulp でできるらしいです。gulp とか grunt とか一体何なんだよ！

#### browserify の `-t` オプションについて

場合によっては、CommonJS → ふつうのJS 以外にも変換が必要なことがあります。例えば CoffeeScript の変換など。これらに関しても一気通貫で変換できるよう、browserify には transform module なるプラグインが存在します。あらかじめインストールのうえ、`-t` オプションで指定すると一緒に変換してくれるようです。

```bash
$ npm install reactify
$ browserify -t reactify src/aaa.jsx > dest/aaa.js
```

#### 結局 bower を使ってない件について

bower でインストールしたパッケージは `components/` フォルダの中にどんどん入っていくのですが、これをどうやってロードしたらいいのかわからなかったのでやめました。


## 参考

* [CommonJSの話](http://www.slideshare.net/terurou/common-js)
* [npmとbrowserifyを使ったクライアントサイドのウェブアプリ開発 | Web Scratch](http://efcl.info/2014/0120/res3605/)
* [npm とフロントエンドのパッケージ管理の未来 | havelog](http://havelog.ayumusato.com/develop/others/e630-npm_meets_frontend.html)
* [Browserifyの使い方について調べてみた | yutaponのブログ](http://yutapon.hatenablog.com/entry/2014/03/09/205231)
* [Node.jsとCommonJSについて - 自分の感受性くらい](http://meso.hatenablog.com/entry/20110626/1309082158)