Javaな人向けクライアントサイドJavaScript開発入門

## はじめに
Java界隈でご飯を食べている私ですが、最近クライアントサイドJavaScriptでの開発(というかnpm)について勉強する機会があったので手順を整理して共有します。

この記事は次のような(ちょっと前の私みたいな)人に向けたチュートリアルです。

* 古めのJavaScriptの知識ならある人([旧石器時代](http://qiita.com/gaogao_9/items/ec2b867d6941173fd0b1)に生きている人)
 * jsは公式サイトからDL・配置してhtmlファイルにscriptタグを並べて読み込むものだと思っている(それ以外に何があるのだ？）
 * jQueryならある程度は書けるんだけど
* フロント界隈の記事を読むとサッパリ分からん な人
    * npmとかrequireとかよく見るけどよくわからん
* Java界隈を軸に活動している人

ここに書いてあることすらもはや古臭くなりつつある感じがしますが、旧石器時代よし少しは前に進めるのではないかと思います。

また、ここに書いてあるのは開発手法の1例であって、これがスタンダードなわけじゃないよ、ということは補足しておきます。

さらに、私も勉強始めたばかりなので、間違ってたり非推奨だったりベターな方法が他にあれば指摘していただけると嬉しいです。

## チュートリアル
### 必要なもの
* お気に入りのテキストエディタ
* 15分から20分程度

### Node.jsインストール
最近のフロントエンド開発はNode.jsなしにはありえません。Node.jsと言うとExpressなどに代表されるサーバサイドの実行環境としての情報も混じってくるので初めは混乱しやすいですが、クライアントサイド開発におけるNode.jsはコンパイラや周辺ツールを動かす開発環境です。JavaでいえばJDKの位置づけかな？

ということでNode.jsをインストールしましょう。Windowsなら以下からインストーラをダウンロードして実行してください。

* https://nodejs.org/ja/

他のOSはパッケージマネージャから導入するのが良いでしょう。

* https://nodejs.org/ja/download/package-manager/


### プロジェクト作成
アプリのプロジェクトを作成します。便宜的にfront-devという名前で説明します。

プロジェクト用のディレクトリを作成し、ターミナルから`npm init`コマンドを実行します。`gradle init`や`mvn archetype generate`のnodeバージョンだと思えばよいかと。

```sh:コマンド実行
cd 好きなディレクトリ
mkdir front-dev
cd front-dev
npm init
(色々聞かれるが、Enterキー連打)
```
※`npm`コマンドはNode.jsをインストールすると（特別に設定しない限り）一緒にインストールされます。

色々聞かれますがここでは適当に全部エンターを押してしまってください。

この時点で`front-dev`フォルダ配下に`package.json`が作成されます。依存パッケージなどは後々このファイルに書いていきます。Javaでいう`pom.xml`のようなものですね。

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

色々書いてありますが今回は`scripts`以外使わないので大胆に消してしまいましょう。

```json:front-dev/package.json
{
  "scripts": {
   }
}
```

### npm-scripts
`package.json`を以下のように書き換え、`npm run hoge`を実行してみてください。画面にHOGEHOGEと表示されるはずです。

```json:front-dev/package.json
{
  "scripts": {
    "hoge":"echo HOGEHOGE"
   }
}
```

```sh:コマンド実行
> npm run hoge

> @ hoge C:\Users\tatesuke\Desktop\front-dev
> echo HOGEHOGE

HOGEHOGE
```

このように、`package.json`の`scripts`にコマンドを定義しておくと`npm run 名前`でそのコマンドを実行することができます。ビルドスクリプトの起動などに使います。

ちなみに、`start`という名前のscriptは特別で、`npm start`のように`run`を省略して実行することができます。

### 依存モジュールのインストール
Javaでは依存モジュールのjarをダウンロードしてクラスパスに配置して・・・という作業はもはや時代遅れで、依存性管理はmavenやgradleに任せるようになりました。フロントエンドでも同様で、自分でjsファイルをダウンロードして利用するという方法はもはや時代遅れです。依存性解決はnpmに任せます[^1]。
[^1]: 今更ですが、npmはNode Package Managerの略でNode.jsのパッケージ管理システムです。JavaとMavenの関係に似てます。

`package.json`を以下のように変更してください。

```json:front-dev/package.json
{
  "scripts": {
    "hoge": "echo HOGEHOGE"
  },
  "dependencies": {
    "jquery": "^3.2.1"
  }
}
```

このように、`dependencys`ブロックに依存パッケージを定義することで、npmが依存性を管理してくれます。この例ではjQueryへの依存を定義しています。

依存モジュールをインストールするには`npm install`コマンドを実行します。

```sh:コマンド実行
npm install
```
※WARNINGが出ますがこのチュートリアルでは無視します。

`front-dev`フォルダ配下に`node-modules`というフォルダが作成され、その中にjQueryのソースなどがダウンロードされます。

```:ディレクトリ構成
front-dev
│  package.json
│
└─node_modules
    └─jquery
```

### 依存モジュールの使用(scriptタグ)
インストールしたパッケージを利用する最も簡単で原始的な方法は`script`タグを利用することです。

以下のようなhtml、jsファイルを作成してブラウザで開いてください。

```html:front-dev/index.html
<!doctype html>
<head>
	<meta charset="utf-8">
	<title>ハローフロントエンド</title>
</head>
<body>
	<div id="container"></div>
	
	<script src="node_modules/jquery/dist/jquery.js"></script>
	<script src="index.js"></script>
</html>
```

```js:front-dev/index.js
(function($){
	$("#container").text("jQuery is work!");
})(jQuery);
```

jQueryが利用できていることがわかると思います。

![image](https://qiita-image-store.s3.amazonaws.com/0/29682/b4b3f141-f822-b289-e07e-0626009cac5d.png)

### 依存モジュールの使用(require)
npmで管理するパッケージを利用するもっと最近っぽい方法は`require`を利用する方法です。`package.json`に定義した依存パッケージはcommon.jsのrequire関数で読み込む事ができるのです。

先程のhtml、jsを以下の通り変更してください。

```html:front-dev/index.html
<!doctype html>
<head>
	<meta charset="utf-8">
	<title>ハローフロントエンド</title>
</head>
<body>
	<div id="container"></div>

<!--	jqueryのjsを読み込むのをやめる
	<script src="node_modules/jquery/dist/jquery.js"></script>
-->
	<script src="index.js"></script>
</html>
```

```js:front-dev/index.js
var jQuery = require("jquery"); //requireでjqueryを読み込む

(function($){
	$("#container").text("require is work!");
})(jQuery);
```

これをブラウザで開くと無事にjQueryが利用でき・・・**ません**！！

![image](https://qiita-image-store.s3.amazonaws.com/0/29682/3552b6fe-5b04-46c1-19e2-361a5a3b5bcd.png)


### requireの使用
実はブラウザにはrequire関数が実装されていないので動かないのは当然です。ブラウザでrequireを利用できるようにしなければなりません。それにはいくつかのメジャーな方法があります。

* RequireJSを利用する
* Browserifyを利用する
* Webpackを利用する

ここではBrowserifyを使った方法を説明します。

Browserifyはrequireを使ったjsをブラウザで実行でるように変換するツールです。

Browserifyのような周辺ツールもnpmを使ってインストールできます。'package.json'を以下のように変更してください。

```json:front-dev/package.json
{
  "scripts": {
    "hoge": "echo HOGEHOGE"
  },
  "dependencies": {
    "jquery": "^3.2.1"
  },
  "devDependencies": {
    "browserify": "^14.1.0"
  }
}
```

実行時には使用しないけれどプロジェクトとして利用するツール類はこのように`devDependencies`ブロックに記述します。mavenで言う「test」や「provided」スコープ、gradleでいう「testCompile」に近いものですね。

続けて`mpn install`を実行します。

```:コマンド実行
npm install
```

これでnode_modules配下にBrowserify(と、Browserifyが依存するモジュール)がダウンロードされました。早速使ってみましょう。次のコマンドを実施してください。

```:コマンド実行
./node_modules/.bin/browserify index.js > out.js
```

これでrequireで参照されるモジュールをひとまとめにして使えるようにした`out.js`が出力されました。`index.html`を以下のように変更してブラウザで開いてください。

```html:front-dev/index.html
<!doctype html>
<head>
	<meta charset="utf-8">
	<title>ハローフロントエンド</title>
</head>
<body>
	<div id="container"></div>

<!--	Browserifyで生成したout.jsを読み込むようにする
	<script src="node_modules/jquery/dist/jquery.js"></script>
        <script src="index.js"></script>
-->
	<script src="out.js"></script>
</html>
```

無事にrequireで読み込んだjQueryが利用できたはずです。


![image](https://qiita-image-store.s3.amazonaws.com/0/29682/7c49e66d-7efb-ec73-622b-645d422a9121.png)

蛇足ですが、私はこのようにJavaScriptからJavaScriptに変換するという感覚をつかむのに時間がかかりました。やってみたらなんだそんなことかという感じなのですが



### npm-script
毎回先程のようなコマンドを打つのは面倒くさいので、npm-scriptとして記述してしまいましょう。

```json:front-dev/package.json
{
  "scripts": {
    "build": "browserify index.js > out.js"
  },
  (略)
}
```

`scripts`ブロックではdependencysやdevDependenciesに記述されたモジュールは`./node_modules/.bin/`を省いて記述できます。これで、`npm run build`でBrowserifyを実行できるようになります。試してみてください。

### ビルドスクリプト(Gulp)
実際の開発ではLint(構文チェック)をかけてBrowserifyかけてminify(圧縮)かけて、なんならCSSもSASSやLESSからコンパイルかけて・・・などと、手順が複雑になります。これを行うのにnpm-scriptだけでは役不足です。要するにフロント開発にもビルドスクリプトが必要なのです

JavaScript界隈のビルドツール・タスクランナーはたくさんありますが2大巨塔は以下です。

* Grant
* Gulp

ここではGulpの利用してみましょう。もし、**エディタでpackage.jsonを編集していたらそれを閉じてから**、次のコマンドを実行してください

```:コマンド実行
npm install --save-dev gulp
```

いままでは依存モジュールを利用するときに`package.json`に依存性を記述してから`npm install`を実施していましたが、このように`--save-dev`オプションを付けると`package.json`の`devDependencies`に追記＋`npm install`を一括で実施してくれます。`package.json`を見ると自動的にgulpが記述されているはずです。

```json:front-dev/package.json
{
  (略）
  "devDependencies": {
    "browserify": "^14.1.0",
    "gulp": "^3.9.1"         // ←ここが自動で追加されている
  }
}
```

補足ですが、`--save`オプションを付ければ同様にdependencies`に追記＋`npm install`を一括で実施してくれます。

```:AngularJSをインストールする例（例なので実施しなくてよい）
npm install --save angular
```


話を戻してビルドスクリプトに戻します。gulpのビルドファイル`gulpfile.js`を作成してください。

```js:front-dev/gulpfile.js
var gulp = require("gulp");
var browserify = require("browserify");
var fs = require("fs");

gulp.task("build", function() {
    var out = fs.createWriteStream('./out.js');

    browserify({
        entries: ['index.js']
    })
    .bundle()
    .pipe(out);
});
```

`build`というタスクでbrowserifyを呼び出しています。これをpackage.jsonで呼び出すようにします。

```json:front-dev/package.json
{
  "scripts": {
    "build": "gulp build"
  },
 (略）
}
```

これで`npm run build`でgulpを起動してビルドできるようになりました。試してみてください。

```:コマンド実行
npm run build
```

### 開発用サーバ
今やJavaScriptの開発でもWebサーバーが必須になってきます。例えばAngularJSのui.routerなんかはWebサーバがないと動きません。しかし、そんなに面倒臭がる必要もありません。開発用サーバもnpmで準備できるからです。

開発用サーバも山のようにありますが、ここではsuperstaticというモジュールを利用してみます。

```:コマンド実行
npm install --save-dev superstatic
```

ビルドスクリプトの末尾にサーバー起動用のスクリプトを追記してください。

```js:gulpfile.js
(略）
var superstatic = require('superstatic');
gulp.task("serve", 　["build"], function () {
	superstatic.server({
		port:3000
	}).listen();
});
```

npmから呼び出せるようにします。

```json:front-dev/package.json
{
  "scripts": {
    "build": "gulp build",
    "serve": "gulp serve"
  },
 (略）
}
```

これで`npm run serve`を実行するだけでソースコードをビルドしてhttpサーバ起動します。コマンドを実行したあと、以下URLにアクセスすると、index.htmlが表示できるはずです。

```:コマンド実行
npm run serve
```

http://localhost:3000/

#### watch
開発時には、修正→確認→修正→確認・・・というサイクルを繰り返す事になります。このとき、毎回手動でビルドコマンドを呼び出すの億劫です。そのため、大抵の場合、ソースに変更があったら自動的にビルドを実行する仕組みを導入することになるでしょう。

`grup.watch`を使うと指定ファイル・ディレクトリに変化があったときにタスクを自動的に実行できます。ビルドスクリプト末尾に以下を追記してください。

```js:gulpfile.js
(略）
gulp.task("watch", 　["serve"], function () {
	gulp.watch("./index.js", ["build"]);
});
```

例によって、package.jsonにも追記します。

```json:front-dev/package.json
{
  "scripts": {
    "build": "gulp build",
    "serve": "gulp serve",
    "watch": "gulp watch"
  },
  (略）
}
```

これで、`npm run watch`するとビルド→httpサーバ起動⇢index.jsに変更があると自動的に再ビルドを行ってくれます。

試しに`npm run watch`した状態で`index.js`を適当にいじってみてください。ブラウザを更新すると変更が反映されているはずです。

```:コマンド実行
npm run watch
```

チュートリアルは以上で終了です。

## 雑多に補足

### Bower
npmと同様にパッケージの依存解決を行うツールにBowerがあります。以前は流行っていたようですが、最近は失速気味？でもBowerを使ってるプロジェクトはまだまだあるので、bowerという単語を見ても慌てず「あー依存性管理のやつね」と思えばいいと思います。

###トランスパイラ、コンパイラ
最近、ES6(ES1025)やらTypeScriptという単語をよく聞きます。ES6は新しい仕様のJavaScriptで、TypeScriptはJavaScriptを拡張したプログラミング言語です。「ES6+Babel+Browserifyで開発」とか「TypeScript＋Webpack」とか見るとひどくややこしく感じます。が、どちらもブラウザで認識できない形式のコードで実装して、最終的にブラウザが実行できる形のjsに変換するという点を理解してしまえばそんなに難しい話ではありません。

ES6を使った開発では、ES6形式のコードをブラウザが実行できる形に変換（トランスパイル）します。

```
ES6で書いたコードを書く
↓
(Babel+Browserify)
↓
ブラウザで実行できるコード
```

TypeScriptを使った開発では、TypeScript形式のコードをブラウザが実行できる形に変換（コンパイル）します。

```
TypeScriptで書いたコード
↓
(TypeScriptコンパイラ)
↓
ブラウザで実行できるコード
```

ちなみに今回のチュートリアルで行った手順は

```
requireを使ったコード
↓
(Browserify)
↓
ブラウザで実行できるコード
```

同じことですね。

そしてトランスパイラもコンパイラもBrowserifyと同じようにもnpmで管理できるので気軽に試せます。そんなに恐れる必要もないなと思いました。

### ディレクトリ構成について
プロジェクトのディレクトリ構成について、これといったものが決まったものはないみたいです。今回は全部ルート配下で作業してしまいましたが、本来はJavaと同じようにsrcフォルダとbuildフォルダに分けて、ソースとビルド成果物を明確に分けるのが良い方法でしょう。

### グローバルインストール
`npm install -save`や`npm install --save-dev` のほかにも`npm install -g パッケージ名`というコマンドをたたくことができます。-gはグルーバルという意味で、グローバルに機能をインストールします。`npm install -g browserify`のように叩くとbrowserifyを普通にコマンドで直接叩くことができるようになります。

以下のコマンドを実行してください。

```
> browserify index.js > out.js
('browserify' は、内部コマンドまたは外部コマンド、
操作可能なプログラムまたはバッチ ファイルとして認識されていません。)
> npm install -g browserify`
> browserify index.js > out.js
```

`npm install -g`後はbrowserifyをコマンドとして叩けるようになっているのがわかると思います。


## 終わりに
チュートリアルはいかがだったでしょうか。
私は用語がわけわからな過ぎて無意識にフロント界隈を避けて通ってきましたが、今回このチュートリアル程度の内容を勉強して、なんだそれだけのことだったのかと思う部分が多かったです。
最先端のモダンJavaScriptとまではいきませんが、旧跡時代のJavaScriptからは一歩抜け出せたんじゃないかな、と思います。
この内容がどなたかの参考になればうれしいです。