webpack + Vue(webpack.config.js書き方の例)

# webpack + Vue
自分用メモ

# はじめに

webpackはモジュールバンドラーである。エントリーポイントに設定したjsファイルを中心に、各モジュールのjsファイルを纏めてバンドル

- モジュール管理できるため機能ごとに開発ができ保守性が上がる
- 複数のjsファイル(cssや画像も)を一つのファイルにbundleできるためリクエスト数減少とパフォーマンス向上
※ ファイルサイズの増大によるパフォーマンス低下もありうる
- 依存関係の解消


# 1. webpack使用の下準備
## 1.1. webpackでの基本的なパッケージのインストール

```shell:
$ npm init -y
$ npm i -S vue

# .vueファイルを読み込むために必須
$ npm i -D vue-loader vue-template-compiler

$ npm i -D webpack webpack-cli 
$ npm i -D terser-webpack-plugin optimize-css-assets-webpack-plugin

# .vueファイルではCSSも扱うので必須
$ npm i -D node-sass css-loader
$ npm i -D babel-loader @babel/core @babel/preset-env 

# 分割したcssの読み込みをリロードしない(brouser-sinc代用)
$ npm i -D webpack-dev-server

# gulp使うとき
$ npm i -D gulp gulp-eslint gulp-notify gulp-plumber
```

## 1.2. package.jsonの編集

```diff:package.json
{
  "name": "webpack_test",
  "version": "1.0.0",
  "description": "",
- "main": "index.js",
  "scripts": {
-   "test": "echo \"Error: no test specified\" && exit 1"
    // sassも監視対象
+   "build:dev": "webpack --mode development --watch",
+   "build": "webpack --mode production",
    // dev-serverだけだとjsの監視はされるが、バンドルはされない
    // 保存すると自動リロードがかかるため更新はされるが、監視よりも遅いため二回目リロード時にバンドルが反映される
+   "start": "webpack --mode development --watch & webpack-dev-server",
  },
    "scripts": {
    },
+ "private": true,
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "jquery": "^3.4.1"
  },
  "devDependencies": {
    "@babel/core": "^7.4.5",
    "@babel/polyfill": "^7.4.4",
    "@babel/preset-env": "^7.4.5",
    "autoprefixer": "^9.6.0",
    "babel-loader": "^8.0.6",
    "css-loader": "^3.0.0",
    "mini-css-extract-plugin": "^0.7.0",
    "node-sass": "^4.12.0",
    "optimize-css-assets-webpack-plugin": "^5.0.3",
    "postcss-loader": "^3.0.0",
    "sass-loader": "^7.1.0",
    "style-loader": "^0.23.1",
    "terser-webpack-plugin": "^1.3.0",
    "webpack": "^4.35.2",
    "webpack-cli": "^3.3.5",
    "webpack-dev-server": "^3.7.2"
  }
}
```

## 1.2. webpack.config.jsの作成
webpackをインストールしたら`webpack.config.js`を手動で作成


```javascript:webpack.config.js
// 開発or本番モードの選択(development、production、noneのいずれか設定必須)
// development: 開発時のファイル出力のモード(最適化より時間短縮,エラー表示などを優先)
// production: 本番時のファイル出力のモード(最適化されて出力される)
const MODE = "development";
// ソースマップの利用有無(productionのときはソースマップを利用しない)
const enabledSourceMap = MODE === "development";

// ファイル出力時の絶対パス指定に使用
const path = require('path');

// プラグイン
// js最適化
const TerserPlugin = require('terser-webpack-plugin');


module.exports = {
  // エントリーポイント(メインのjsファイル)
  entry: './src/js/app.js',
  // ファイルの出力設定
  output: {
    // 出力先(絶対パスでの指定必須)
    path: path.resolve(__dirname, 'dist/js'),
    // 出力ファイル名
    filename: "bundle.js"
  },
  mode: MODE,
  // ソースマップ有効
  devtool: 'source-map',
  // ローダーの設定
  module: {
    rules: [
      {
        test: /\.css$/,
        use: ["vue-style-loader", "css-loader"]
      },
      {
        test: /\.vue$/,
        loader: "vue-loader"
      },
      {
        // ローダーの対象 // 拡張子 .js の場合
        test: /\.js$/,
        // ローダーの処理対象から外すディレクトリ
        exclude: /node_modules/,
        // Babel を利用する
        loader: "babel-loader",
        // Babel のオプションを指定する
        options: {
          presets: [
            // プリセットを指定することで、ES2019 を ES5 に変換
            "@babel/preset-env"
          ]
        }
      }
    ]
  },
  // import 文で .ts ファイルを解決するため
  resolve: {
    // Webpackで利用するときの設定
    alias: {
      vue$: "vue/dist/vue.esm.js"
    },
    extensions: ["*", ".js", ".vue", ".json"]
  },
  plugins: [
    // Vueを読み込めるようにするため
    new VueLoaderPlugin()
  ],
  // mode:puroductionでビルドした場合のファイル圧縮
  optimization: {
    minimizer: production
      ? []
      : [
        // jsファイルの最適化
        new TerserPlugin({
          // すべてのコメント削除
          extractComments: 'all',
          // console.logの出力除去
          terserOptions: {
            compress: { drop_console: true }
          },
        }),
      ]
  },
  // js, css, html更新時自動的にブラウザをリロード
  devServer: {
    // サーバーの起点ディレクトリ
    // contentBase: "dist",
    // バンドルされるファイルの監視 // パスがサーバー起点と異なる場合に設定
    publicPath: '/dist/js/',
    //コンテンツの変更監視をする
    watchContentBase: true,
    // 実行時(サーバー起動時)ブラウザ自動起動
    open: true,
    // 自動で指定したページを開く
    openPage: "index.html",
    //　同一network内からのアクセス可能に
    host: "0.0.0.0"
  }
};
```

# 2. webpackの処理対象となるjsファイルの書き方
エントリーポイントとなるjsファイルを`app.js`モジュールファイルを`module1.js`とすると次のように書く

jsファイル内で`Vue.component()`などのメソッドで作る場合と、`.vue`拡張子の単一ファイルコンポーネントで作る場合がある
以下はコンポーネントごとに`.vue`拡張子で作るときである


```javascript:app.js
import Vue from 'vue';
// コンポーネントファイルがある場合
import App from './components/App.vue';
```


```javascript:./components/App.vue
// 関数を定義。
```


```html:index.html
<!DOCTYPE html>
<html lang="ja" dir="ltr">
<head>
  <meta charset="utf-8">
  <title>webpack_sample</title>
  <link rel="stylesheet" href="./dist//css/main.css">
</head>
<body> 
  // 
  <script src="./dist/js/bundle.js"></script>
</body>

</html>

```

## 3. webpack実行
実行コマンド

`package.json`の`scripts`で設定した名称で実行

```sh
$ npm run build:dev  # バンドル(開発用)実行
$ npm run build  # バンドル(本番用)実行
$ npm run start  # バンドルと監視スタート
```