Vue + TypeScript + Babel + Bulma + webpackで作るSPAでレスポンシブなフロント開発2(開発ツール編)

# リンク
- [開発環境構築編](https://qiita.com/va034600/items/a62238666149bcd9e719)
- [開発ツール編](https://qiita.com/va034600/items/c968b9f524f5d3127b93)
- [JavaScript Framework編](https://qiita.com/va034600/items/f203ea7a423967d5023c)
- [CSS Framework編](https://qiita.com/va034600/items/8541a076a9d3d140162f)
- [ビルド編](https://qiita.com/va034600/items/919ce3fa330f87f2a277)

[前回](https://qiita.com/va034600/items/a62238666149bcd9e719)は
サンプルソースを落として開発環境を構築、起動までを確認しました。
今回は開発環境で使う開発ツールのパッケージマネージャ(npm) タスクランナー(gulp) モジュール管理(webpack)の説明をします。

ソースはこちら
[github](https://github.com/va034600/sample-html/tree/master/project-base3)

# パッケージマネージャ
## npm
ちょっと前まではbowerなどありましたが、今はこれが主流かなと。
npmで必要なファイルはpackage.jsonとなります。
package.jsonには開発、実行時に使用するライブラリが明記されていて、npm installを実行するときに使います。
実行するとnode_modulesにjsやscssなどのファイルをどこかしらからダウンロードします。package-lock.jsonも同時に生成されます。package-lock.jsonについてはとりあえず、なにかあるなぁくらい認識で。

```json:package.json
{
  "name": "project-base3",
  "version": "1.0.0",
  "description": "",
  "main": "main.js",
  "author": "",
  "license": "",
  "devDependencies": {
    "babel-core": "6.21.0",
    "babel-loader": "6.2.10",
    "babel-preset-es2015": "6.18.0",
    "css-loader": "^0.28.10",
    "del": "^2.2.2",
    "gulp": "3.9.1",
    "gulp-cssimport": "^5.0.0",
    "gulp-uglify": "2.0.0",
    "gulp-rename": "^1.2.2",
    "gulp-sass": "3.1.0",
    "gulp-minify-css": "^1.2.4",
    "require-dir": "0.3.0",
    "run-sequence": "1.2.2",
    "sass-loader": "^6.0.6",
    "style-loader": "^0.20.2",
    "ts-loader": "1.3.1",
    "typescript": "2.2.1",
    "vue-class-component": "5.0.1",
    "vue-loader": "12.0.4",
    "vue-template-compiler": "2.3.3",
    "vue-template-loader": "0.3.1",
    "webpack": "2.2.0",
    "webpack-dev-middleware": "1.9.0",
    "webpack-dev-server": "2.3.0",
    "webpack-hot-middleware": "2.15.0",
    "webpack-stream": "^3.2.0"
  },
  "dependencies": {
    "babel-polyfill": "6.23.0",
    "bulma": "0.6.1",
    "isomorphic-fetch": "2.2.1",
    "url-search-params-polyfill": "2.0.0",
    "vue": "2.3.3",
    "vue-router": "2.5.3",
    "vuex": "2.3.1",
    "vuex-router-sync": "4.2.0"
  }
}
```

devDependenciesは開発及びビルド時にdependenciesは実行時に必要となるファイルを明記します。

ライブラリを追加したい場合は以下のコマンドを実行します。

```sh
$ npm install bulma --save
$ npm install webpack --save-dev
```

--save,--save-dev(オプション)を追加するとpackage.jsonに追加されます。
--saveはdependenciesに、--save-devはdevDependenciesにそれぞれ追加されます。

# タスクランナー
## gulp
grunt、webpackでも代用ではありますが、今回はgulpで。

### gulpfile.jsファイル

タスクを記述していきます。
タスクにはwebpack dev serverの起動、ビルドなどがあります。

```javascript:gulpfile.js
var requireDir = require('require-dir');
var runSequence = require('run-sequence');

requireDir('./gulp/tasks', { recurse: true });

var gulp = require('gulp');

gulp.task('default', ['webpack-dev-server']);
```

### gulpのタスク

defaultしかないのでわかりにくいですが、
この例の場合、タスク(gulp)は以下のように指定できます。

```sh
$ gulp
$ gulp default
```

webpack dev serverが立ち上がります。

```
└── gulp
    └── tasks
        └── webpack-dev-server.js
```

### webpack dev serverの設定

設定はwebpack-dev-server.jsに記述していきます。

```javascript:webpack-dev-server.js
var gulp = require('gulp');
var webpack = require("webpack");
var WebpackDevServer = require("webpack-dev-server");

var webpackConfig = require('../../webpack.config.js');
var compiler = webpack(webpackConfig);

gulp.task('webpack-dev-server', function(callback) {
    new WebpackDevServer(compiler, {
        contentBase:"webRoot",
        publicPath: webpackConfig.output.publicPath,
        hot: true,
        historyApiFallback: true
    }).listen(3000, "localhost", function(err) {
        if(err) throw new gutil.PluginError("webpack-dev-server", err);
        callback();
    });
});
```

軽く説明すると、contentBaseでルートディレクトリ(今回はwebRoot)を指定します。
実装するソースはTypeScript、SASSとなりますが、そのままではブラウザでは判読できないので、
javascript、cssにコンパイルしてからブラウザで読ませます。
開発時はコンパイルされたファイル(javascript、css)をwebpack dev server内のメモリ上に作成されて、物理的には作成されません。
その際のwebpack dev serverからの出力先をpublicPathで指定します。
今回の場合は以下のように出力されます。
```
http://localhost:3000/public/main.min.js
http://localhost:3000/public/style.min.js
```
historyApiFallbackがポイントです。
この設定がSPA環境、vue-routerでHTML5 historyモードで動作させるために必要な設定です。
この設定をすることで
```
http://localhost:3000/
http://localhost:3000/sample-button/
```
でアクセスしても同じ`webRoot/index.html`を参照します。
本番環境ではwebpack dev serverを使わず、nginxやspring mvc等でfallbackの設定するかと思います。

nginxの場合は。
```conf:default.conf
location / {
    root   /usr/share/nginx;
    index  index.html index.htm;
    try_files $uri $uri/ /index.html;
}
```

spring mvcの場合は。

```java:StartController.java
@Controller
@RequestMapping(value="/**")
    public class StartController extends BaseController {
}
```

詳しくは[Vue Router HTML5 History モード](https://router.vuejs.org/ja/essentials/history-mode.html)を参照してください。

## webpack dev serverの設定

webpack dev serverの設定はwebpack.config.jsに記述しています。

```javascript:webpack.config.js
const webpack = require('webpack');
var path = require('path');

var config = {
    devtool: "source-map",

    output: {
        path: path.join(__dirname, 'dist'),
        filename: '[name].min.js',
        publicPath: "/public/"
    },
    resolve: {
        extensions: [".ts", ".vue", ".js"],
        modules: ['node_modules', 'src/main/html', 'src/main/js', 'src/lib/js', 'src/main/ts', 'src/lib/ts'],
        alias: {
            vue: 'vue/dist/vue.common.js'
        }
    },
    module: {
        rules: [
            {
                test: /\.vhtml$/,
                loader: 'vue-template-loader'
            },
            {
                test: /\.scss$/,

                use: [
                    {
                        loader: 'style-loader'
                    },
                    {
                        loader: 'css-loader'
                    },
                    {
                        loader: 'sass-loader'
                    }
                ]
            },
            {
                test: /\.ts$/,
                use: [
                    {
                        loader: 'babel-loader'
                    },
                    {
                        loader: 'ts-loader'
                    }
                ]
            }
        ]
    },
    plugins:[
        new webpack.LoaderOptionsPlugin({
            debug: true
        }),
        new webpack.HotModuleReplacementPlugin()
    ]
};

config.entry = {
    //mainファイルを作成する。複数作れば複数作られる。
    main: [
        'babel-polyfill',
        'isomorphic-fetch',
        'url-search-params-polyfill',
        "webpack-dev-server/client?http://localhost:3000",
        "webpack/hot/dev-server",
        "./src/main/ts/main.ts"
    ],
    style: "./src/main/ts/style.ts"
};

module.exports = config;
```

### source-map
source-mapは出力されたjavascriptからTypeScriptのファイルをデバッグするために使われます。
これでChromeやintellij(web storm)でTypeScriptファイルをデバッグできるようになります。

### entry
TypeScriptのルートファイルを指定したらそのファイルを元にJavaScriptを作成します。
今回はmainのみになります。

### test

testは一致したファイル（この場合は拡張子が.tsのもの）に各種loaderを当てていきます。

```
test: /\.ts$/,
use: [
{
    loader: 'babel-loader'
},
{
    loader: 'ts-loader'
}
]
```

ts-loader、次にbabel-loaderを使ってコンパイルします。
これでTypeScript->ES2015->ES5となります。

### HotModuleReplacementPlugin

HotModuleReplacementPlugin はファイルを保存するたびにリロードするかと思いますが、画面全体をリロードするのではなく、修正したファイルのみリロードするようになります。

ささっとタスクランナーの説明をしました。
ビルドについてはまた後で説明します。
とりあえず、開発用までです。

[jQueryから脱出したい人のためのなんとなくなフロント開発入門5(ビルド編)
](https://qiita.com/drafts/919ce3fa330f87f2a277)

# モジュール管理

JavaScriptのモジュール管理とはブラウザのJavaScript(ES5)ではJavaScriptから別のJavaScriptを呼ぶ仕組みがないので、その仕組みを補うのがモジュール管理かなと。
今回はモジュール管理はwebpackを使います。


# トランスパイル

## .babelrc
.babelrcはBabelの設定ファイルです。
es2015でjavascript(今回はTypeScript)を書きますよ。的なやつです。

```json:.babelrc
{
  "presets": ["es2015"]
}
```

## tsconfig.json

tsconfig.jsonはTypeScriptの設定ファイルです。

```json:tsconfig.json
{
  "compilerOptions": {
    "target": "es2015",

    "experimentalDecorators": true,

    "sourceMap": true,

    "allowSyntheticDefaultImports": true,
    "lib": [
      "dom",
      "es5",
      "es2015.promise"
    ],
    "module": "es2015",
    "moduleResolution": "node"
  }
}
```

TypeScriptをes2015で出力しますよかな。

TypeScriptでvueを使う場合の設定方法が[TypeScript のサポート](https://jp.vuejs.org/v2/guide/typescript.html)に書いてあります。

# 終わりに

開発ツール編はとりあえずここまでで。
まだ本題の実装に入っていません。
環境構築だけで相当な労力を使います。
初めての人はここまででも大変かと思います。

[github](https://github.com/va034600/sample-html/tree/master/project-base3)