webpack + Vue.js で公開用ファイルを出力した時のメモ

# 背景

学習目的でwebpackとVue.jsを利用して簡単なプロジェクトを開発した。開発時はチュートリアルに従いwebpack-dev-serverを利用しているが、公開サーバではwebpack-dev-serverは利用しない。webpackを用いて必要なJSファイルを纏め出力し、それらのファイルを公開済のウェブサーバに設置すれば良い。

この文書では、上記の通りwebpackを用いて開発したプロジェクトのファイル群を公開用ファイルに纏める為に施した手順を記すことにする。

## 注意
残念ながらまだ勉強中の身であり、その記録を残した文書です。間違えも多々あると思いますが、参考になれば幸いです。

# 前提
* webpack-dev-serverを用いて開発している。
* vue.jsを用いて開発してる。

<!--
```shell-session:プロジェクトを作る際に実施したコマンド
$ mkdir projdir
$ cd projdir
$ npm init
$ npm i -D webpack
$ npm i -D webpack-cli
$ npm i -D webpack-dev-server
$ npm i vue-cli
$ emacs webpack.config.js ## webpack.config.jsを作成する
$ 
```
-->

# 手順
プロジェクトを始める際にwebpack.config.jsを自身で作成しているはず。このファイルを3つのファイルに分割し、実行したいモードによってマージして使うように変更する。ポイントは__分割__と__マージ__と__モード__となる。

1. webpack.config.jsを分割する。webpack.common.js(共通設定) / webpack.prod.js(公開設定) / webpack.dev.js(開発設定)
2. webpack.prod.jsとwebpack.dev.jsに(webpack.common.jsとの)マージ処理を追記する。
3. package.jsonを修正して、モード別に読み込むファイルを指定する。

## webpack.config.jsを分割する
まずは、既存のwebpack.config.jsを以下の3つのファイルに分割する。

* webpack.common.js(共通用設定) 
* webpack.prod.js(公開用設定)
* webpack.dev.js(開発用設定)

元となるwebpack.config.jsを載せておく。

```javascript:webpack.config.js
const path = require('path')
const webpack = require('webpack')
const VueLoaderPlugin = require('vue-loader/lib/plugin')

module.exports = {
    module:{
        rules: [
            {
                test: /\.vue$/,
                loader: 'vue-loader'
            },
            {
                test: /\.css$/,
                use:[
                    "style-loader",
                    "css-loader"
                ]
            }
        ]
    },
    entry: './src/index.js',
    output: {
        path: path.resolve(__dirname,'./dist'),
        filename: 'bundle.js'
    },
    resolve: {
        extensions: ['.js','.vue'],
        alias: {
            vue$: 'vue/dist/vue.esm.js',
            '@': path.resolve(__dirname,'src'),
        },
    },
    devServer: {
        contentBase: path.resolve(__dirname, 'public'),
        historyApiFallback: true,
        watchOptions:{
            poll: true
        }
    },
    plugins: [
        new VueLoaderPlugin(),
        new webpack.ProvidePlugin({
             $:"jquery",
         }),
    ],
}
```

しかし、正直、現スキルではどの記述が開発環境に必要で、どの記述が公開に不要なのかわからないので、とりあえず、ファイルだけは作成する。ファイルの作成はwebpack.config.jsを複製して同一内容のファイルを作成すれば良い。

さて、webpack.dev.jsの内容を確認してみると気になる記述があった。`devServer:{...}`の記述である。「dev」と付いている以上開発環境でのみ必要なのでは？という雑な考えに至ったわけである。とりあえず__webpack.common.jsから`devServer:{...}`を削除__し、__webpack.dev.jsは`devServer:{...}`以外の設定を削除__。そして、本番用にのみ必要な記述は不明だったので、__webpack.prod.jsから設定は全て削除__した。

```javascript:webpack.common.js
const path = require('path')
const webpack = require('webpack')
const VueLoaderPlugin = require('vue-loader/lib/plugin')

module.exports = {
    module:{
        rules: [
            {
                test: /\.vue$/,
                loader: 'vue-loader'
            },
            {
                test: /\.css$/,
                use:[
                    "style-loader",
                    "css-loader"
                ]
            }
        ]
    },
    entry: './src/index.js',
    output: {
        path: path.resolve(__dirname,'./dist'),
        filename: 'bundle.js'
    },
    resolve: {
        extensions: ['.js','.vue'],
        alias: {
            vue$: 'vue/dist/vue.esm.js',
            '@': path.resolve(__dirname,'src'),
        },
    },
/*
    ココにdevServer:{...}の記述があった
*/
    plugins: [
        new VueLoaderPlugin(),
        new webpack.ProvidePlugin({
             $:"jquery",
         }),
    ],
}
```

```javascript:webpack.dev.js
const path = require('path')

module.exports = {
    devServer: {
        contentBase: path.resolve(__dirname, 'public'),
        historyApiFallback: true,
        watchOptions:{
            poll: true
        }
    }
}
```

```javascript:webpack.prod.js
const path = require('path')

module.exports = {
}
```
## 分割されたwebpack.***.jsをマージする
分割された状態のファイルはこのままでは使えない。設定を読み込む際に必要な設定ファイルをマージして一つの設定として読み込む必要がある。

* 開発環境で稼働させる際はwebpack.common.js + webpack.dev.js。
* 本番環境に設置するためのファイルを生成する際はwebpack.common.js + webpack.prod.js。

という感じ。

### webpack-mergeをインストール
どうやら、分割された設定ファイルをマージするにはwebpack-mergeが必要らしいのでインストール。

```shell-session:webpack-mergeのインストール
npm i -D webpack-merge
```

### マージの記述を追加 

webpack.dev.jsとwebpack.prod.jsにwebpack.common.jsをマージする為の記述を追加する。

```javascript:webpack.dev.js
const merge = require('webpack-merge');
const common = require('./webpack.common.js');
const path = require('path')

module.exports = merge(common,{                     //追記
    mode: 'development',
    devServer: {
        contentBase: path.resolve(__dirname, 'public'),
        historyApiFallback: true,
        watchOptions:{
            poll: true
        }

    },
})
```

```javascript:webpack.prod.js
const merge = require('webpack-merge');
const common = require('./webpack.common.js');
const path = require('path')

module.exports = merge(common,{
    mode: 'production',
})
```

## package.jsonを修正する

現状では`npm start`でwebpack-dev-serverを稼働させているが、それに加えて`npm run build`で本番公開用ファイルを生成する処理をpackage.jsonに追記する。

```javascript:package.json
{
  ...
  "scripts": {
    "start": "webpack-dev-server --hot --config webpack.dev.js",
    "build": "webpack --config webpack.prod.js"
  },
  ...
}

```

## 実行

### npm start
開発環境でwebpack-dev-serverを実行したいときに実行するコマンド。

```shell-session
$ npm start
```
どうやらpackage.jsonの`"start":"~~~~"`に登録しておいたコマンドが実行されるらしい。

### npm run build
公開環境に設置するためのJSファイルを生成するコマンド。

```shell-session
$ npm run build
```

上記コマンドを実行すると、webpack.common.jsに設定した出力先にファイルが出力される。

```javascript:webpack.common.js(一部)
...
    output: {
        path: path.resolve(__dirname,'./dist'),
        filename: 'bundle.js'
    },
...
```
この場合はプロジェクトのディレクトリの__dist__にbundle.jsが出力された。
package.jsonの`"build":"~~~~"`に登録しておいたコマンドが実行されるらしい。こちらは`run`が必要らしい。