ブラウザとサーバで全く同じjavascriptを動かそう。[gulpとbrowserify超入門]


# はじめに

この記事は、 **gulp**も **browserify**も知らない **初心者**を対象にしています。
最近になってnode.jsでプログラミングしていますよって人が対象です
あまりにも０ステップからで、それくらいわかるよって事もあるかもしれません。

  > node.jsについて、０から勉強したい人は[ドットインストール](http://dotinstall.com/lessons/basic_nodejs)とか便利かもね。

# gulpって？browserifyって？

まず、gulpもbrowserifyもなんのことだか、さっぱりわからないって！
**でも、まだ説明しません。**
なぜなら、 **なんで必要？**を説明していないから。

# 目的は

**ブラウザとサーバで全く同じjavascriptを動かそう**

最近は、node.jsでサーバサイドjavascriptも珍しくなくなってきました。
でも、微妙に違うサーバとブラウザでのjavascript！
特に、違うなーと感じるのは、記述する場所ですね。

> 本当はもっといろいろあるけど、長くなるし面倒なので省略。

簡単なブラウザで動作するjavascriptは次のような感じですね

```html:index.html
<!doctype html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>title</title>
  <script>
     var x = 1;
     var y = 2;
     console.log(x + y);
  </script>
</head>
<body>
  contents
</body>
<html>
```

まったく実用的ではないフザケたコード。でもちゃんと動きます
結果はページには表示されませんが、デバッグツールのコンソールで確認できます

さすがに、htmlファイルにjavascriptを記述することが少なくなってきて、最近は

```html:index.html
<!doctype html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>title</title>
  <script type="text/javascript" src="script.js"></script>
</head>
<body>
  contents
</body>
<html>
```

```js:scritp.js
var x = 1;
var y = 2;
console.log(x + y);
```

とファイルを分けることが一般的かつ推奨されています。(まあ常識なんでしょうけど一応)

一方、サーバ代表のnode.jsでも、上のscript.jsを実行するときちんとコンソールに表示することができます
「 **ブラウザとサーバで全く同じjavascriptを動かそう**」っっって問題ないじゃん！
てなるはずですよね。でも。。。
スクリプトファイルがひとつだけなら問題ないんだよ。

# require?なにそれ

node.jsでは、他のファイルやモジュールを利用する際に、普通に **require**を使いますよね。
複数のjsファイルでコードを書くなら常識！

```js:script.js
var tasu = require('./tasu');
var total = tasu(1, 2);
console.log(total);
```

```js:tasu.js
function tasu (x, y) {
  return x + y;
}
module.exports = tasu;
```

これって、超便利！
ファイルを分けてコード管理できるし、ほかの人が作ったモジュールを簡単に利用できるし。
サーバで動かす時も、tasu.jsの存在なんてしらなくってOK
`node script.js`で実行できます

**でもブラウザじゃ、そんな機能ないじゃんかー**

だからブラウザで動かす時は、こうなっちゃう

```html:index.html
<!doctype html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>title</title>
  <script type="text/javascript" src="tasu.js"></script>
  <script type="text/javascript" src="script.js"></script>
</head>
<body>
  contents
</body>
<html>
```

```js:script.js
var total = tasu(1, 2);
console.log(total);
```

```js:tasu.js
function tasu (x, y) {
  return x + y;
}
```

`script.js`や`tasu.js`から`require`や`module.exports`の記述がなくなったかわりに
気をつけなくてはいけない事がある。しかも、htmlで！

  + 関係しているファイルをすべて取り込まなくてはいけません。
  + 依存している関数が記述されている`tasu.js`は、それを使用する`script.js`より先に、取り込まなくてはいけません  

はっきりいって、ブラウザでjavascriptの重要度が増している昨今、ファイルが爆発的に増えてくると管理なんて無理無理。
依存関係とか、知らんし。ってなります

# 出番です。browserify

そこで、browserifyを使うと、こう書けちゃうよって事です。

  > それにしてもbrowserifyって、どう発音するんだろね。”ぶらうぜりふぁい”？

```html:index.html
<!doctype html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>title</title>
  <script type="text/javascript" src="script.js"></script>
</head>
<body>
  contents
</body>
<html>
```

```js:script.js
var tasu = require('./tasu');
var total = tasu(1, 2);
console.log(total);
```

```js:tasu.js
function tasu (x, y) {
  return x + y;
}
module.exports = tasu;
```

依存関係なんて、htmlで管理する必要はありませんし、なによりjavascriptのコードがサーバと一緒ってのが気持ちがいい

> もっと重要なのは、サーバ用とブラウザ用の２種類のコードを保守しなくていいってことだけどね

でもさ、 **これってどうすりゃ出来んの**

さて、まずはbrowserifyをインストール。-gを忘れないでね。

```
npm install -g browserify
```

すると、OSのコンソールで`browserify`コマンドが使えるようになるはず。

> たぶん。。。私の環境がMacオンリーなんでWindowsはわからんです。

さっそく、使ってみましょう

```
browserify script.js -o bundle.js
```

すると、`script.js`と`tasu.js`が結合された`bundle.js`ってファイルができました
実はbrowserifyがブラウザの機能を拡張するわけではなく、サーバで動作するファイルをブラウザで読み込む事のできるファイルに変換することしかしません。
でもhtmlでは、この`bundle.js`をひとつだけ読み込めばOKです。依存関係もコードを解析してくれるから知らなくて大丈夫。
依存しているファイル`tasu.js`の指定を、コマンドではしていないでしょ。
これで、htmlからサーバで動くファイル`script.js`と`tasu.js`とまったく同じjavascriptを動かしている事と同じなります。(結果的に)

> htmlのsrc="script.js"はbundle.jsに変えてね。

`bundle.js`の中身はこんな感じ。おまじないのコードがごちゃーとはいっていますが、`script.js`と`tasu.js`のコードがきっちり含まれていることがわかりますね。

```js:bundle.js
(function e(t,n,r){       /** (おまじないは省略) **/      })({1:[function(require,module,exports){

var tasu = require('./tasu');
var total = tasu(1, 2);
console.log(total);

},{"./tasu":2}],2:[function(require,module,exports){

function tasu (x, y) {
  return x + y;
}
module.exports = tasu;

},{}]},{},[1])
```

これで、今までサーバで動かしていたコードをブラウザ仕様にする必要がなくなりました

よかったー。
。
。
って。。。

jsファイルを書き換えるたびにコマンド打つのは **め・ん・ど・く・さ・く・ね**
だいたい`browserify`ってなげーし、スペル覚えらんない。

# 出番です。gulp

そこで、gulpを使うと、 **繰り返しのコマンド打つのが自動化できるかもよ！**ってことです。

> gulpもなんて発音？”がるぷ”でええのかなー。

gulpはタスクランナーって部類のモジュールです。毎回毎回毎回毎回、、おんなじコマンド打って実行している処理をまとめたり、自動化したりと何かと便利。
nodeで開発しているとやたらとお世話になります。

> タスクランナーにはgruntってのもあるけど、gulpのほうが後発で初心者向けだと思います。
> gruntはずっと使っていたわりに、すぐにやり方忘れちゃうんだよね。gulpにしよう！

なにはともあれインストールって前に、関係ファイルとディレクトリ構成を確認。
いまから、この構成にしていきます。
libディレクトリだけは手動で作成して、`script.js`と`tasu.js`を入れてください。
`index.html`は`src="public/script.js"`とします。
その他のファイル、ディレクトリはその都度説明します。

```text:file&directory
myapp/
  index.html
  gulpfile.js            あとで説明するよ
  lib/
    script.js
    tasu.js
  public/
    script.js            自動化で作成されるよ
  node_modules/
    browserify/          インストールするよ    
    gulp/                インストールするよ
    vinyl-source-stream/ インストールするよ
```

> コードを書くファイルはlibって名前のディレクトリに、変換後のファイルをpublicって名前のディレクトリにを入れるのは、慣例みたいなもので多数の人がそのルールで書いてたりします。ここは深く考えずに従うのが吉ですね。

さて、仕切り直しでgulpをインストール。こちらも-gを忘れないこと。(gulpコマンドがコンソールから使用できるようになるからね)

```
npm install -g gulp
```

さらに、ローカルインストールもします。(両方しないと動かないんだよね)

```
npm install gulp
```

そして、さらにさらに、gulpでbrowserifyを実行させるためにbrowserifyをインストールします。-gはつけないでね。

```
npm install browserify
```

あとひとつ、ファイルの取り扱いはstreamが欠かせないってことで、vinyl-source-streamをインストールします

```
npm install vinyl-source-stream
```

自動化は、ファイルを更新したときに`browserify lib/script.js -o public/script.js`が実行されるということで、よろしかったでしょうかー。
その自動化の処理を記述するファイル`gulpfile.js`を作成します
まずはコピペで作ってください。解説はのちほど。

```js:gulpfile.js
var gulp = require('gulp');
var browserify = require('browserify');
var source = require('vinyl-source-stream');

gulp.task('browserify', function () {
  browserify('lib/script.js')
    .bundle()
    .pipe(source('script.js'))
    .pipe(gulp.dest('public'));
});

gulp.task('watch', function() {
  gulp.watch('lib/**/*.js', ['browserify']);
});

gulp.task('default', ['browserify', 'watch']);
```   

このファイルを実行する方法は、コンソールで`gulp`と打つだけです。
`gulp`コマンドは`gulpfile.js`を探して実行してくれます
すると即座に、publicディレクトリとその下に`script.js`が作成されます
さらに、lib下のjsファイルを更新するたびに、`public/script.js`が更新されます

ひとつひとつ説明します
実際に、変換の処理を行っているのは、6-9行目のところです。

  + `browserify('lib/script.js')` : 対象のjsファイルを指定して読み込みます
  + `.bundle()` : ブラウザ用のコードを作成
  + `.pipe(source('script.js'))` : ファイルを出力するためのStream(データの塊みたいなもん)を出力
  + `.pipe(gulp.dest('public'));` : 受け取り側のディレクトリを指定します

でも、このファイルの先頭の行から変換処理が始まるわけではありません。

gulpを実行した際に、このファイルは奇妙なことですが、まず最後の行から変換処理を始めます
先ほどファイルの実行は **`gulp`と打ってください**といいましたが、正確には **`gulp default`が実行されます**
gulpの後にタスク名を指定する必要があるんですが、指定しないと`default`を指定したことになるんですね。
ということで、`gulp.task`はタスクの登録だけで **処理はしてくれないんです**。
このファイルでは`browserify`、`watch`、`default`の３つのタスクが登録されています。
実行は、 **コンソールコマンドから指定する**と理解してください。

そしてタスクで実行される処理内容は関数を記述します。
でも、`default`のようにタスク名を配列で指定した場合は、同名のタスクを実行します。
なので、最初に`browserify`を実行して、次に`watch`を実行します。
すぐに`public/script.js`が作成されるのは、そういうことですね。

ではlibディレクトリ内のファイルを更新するたびに`public/script.js`も更新されるのはなぜでしょう。
`gulp.watch`がファイルの更新を監視してくれるからですね。
ちょっと独特な記述方法の`lib/**/*.js`は、libディレクトリ以下で子ディレクトリも含むすべてのjsファイルの更新を監視します。
もし変更があったら、タスク`browserify`を実行します`。

これで、もう`browserify`というなかなか覚えられないスペルのコマンドを打つ必要がなくなりました。

**ばんざーーい**


# おわりに

いろいろ端折っていますが、最低限の説明でまったくbrowserifyとgulpを理解できるようにしたつもり。
案外、初心者向けな情報がなさそうだったのでまとめてみました。半分以上は忘れっぽい自分用のメモです。
(他の方の記事を参考にさせていただいたところあって感謝・感謝）
本当は、すごいメリットがあることを、説明したかったけどどんどん趣旨がずれるんで、そこらへんは端折りました。

> グローバル汚染が防げるとか、使用できるオブジェクトの制限とか、ファイル圧縮できるとか、coffeescriptとの併用とか、livereloadとかとか

間違いがあったらコメント下さいね。ではでは