【Webpack, Vue CLI, Nuxt.js】の3パターンでカウントアップするだけのアプリを作成

手を動かしてみると違いがわかるはず。
## Webpack
###webpackを導入
```zsh
$ mkdir counter-webpack
$ cd counter-webpack
$ npm init -y
$ npm i -D webpack webpack-cli webpack-dev-server
$ touch webpack.config.js
```
```webpack.config.js
const path = require('path')

module.exports = {
  entry: './src/index.js',
  output: {
    path: path.resolve(__dirname, './dist'),
    filename: 'bundle.js'
  },
  devServer: {
    contentBase: path.resolve(__dirname, 'public')
  }
}
```
```package.json
"scripts": {
  "start": "webpack-dev-server",
  "build": "webpack -p"
}
```
```zsh
$ mkdir src
$ touch src/index.js
$ mkdir public
$ touch public/index.html
```
```src/index.js
console.log('Hello, World!')
```
```public/index.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Vue app</title>
  </head>
  <body>
    <div id="app"></div>
    <script src="bundle.js"></script>
  </body>
</html>
```
```zsh
$ npm start
```
http://localhost:8080/ を開いて一度動作確認。

###Vueと関連ツールをインストール
```zsh
$ npm i vue
$ npm i -D vue-loader vue-template-compiler css-loader style-loader
$ npm i -D babel-loader @babel/core @babel/preset-env
```
```diff:webpack.config.js
const path = require('path')
+ const VueLoaderPlugin = require('vue-loader/lib/plugin')

module.exports = {
  entry: './src/index.js',
  output: {
    path: path.resolve(__dirname, './dist'),
    filename: 'bundle.js'
  },
+  module: {
+    rules: [
+      {
+        test: /\.vue$/,
+        loader: 'vue-loader'
+      },
+      {
+        test: /\.js$/,
+        loader: 'babel-loader',
+      },
+      {
+        test: /\.css$/,
+        use: [
+          'vue-style-loader',
+          'css-loader'
+        ]
+      },
+    ]
+  },
+  resolve: {
+    extensions: ['.js', '.vue'],
+    alias: {
+      vue$: 'vue/dist/vue.esm.js',
+    }
+  },
+  plugins: [
+    new VueLoaderPlugin()
+  ],
  devServer: {
    contentBase: path.resolve(__dirname, './public')
  }
}
```
```package.json
{
  "babel": {
    "presets": ["@babel/preset-env"] 
  },
  "browserslist": "last 2 versions, not dead, not ie > 0",
}
```

###プログラムを記述
```zsh
$ mkdir src/components
$ touch src/components/App.vue
$ touch src/components/Counter.vue
```
```src/components/Counter.vue
<script>
export default {
  data() {
    return {
      count: 0,
    }
  },
  methods: {
    add: function() {
      this.count++
    },
    reduce: function() {
      this.count--
    }
  }
}
</script>

<template>
  <div>
    <p>Written in Counter.vue</p>
    <button @click='reduce'>-</button>
    <span>{{ count }}</span>
    <button @click='add'>+</button>
  </div>
</template>

<style scoped>
  div {
    color: blue;
  }
  button {
    width: 30px;
    height: 30px;
    border-radius: 50%;
  }
</style>
```
```src/components/App.vue
<script>
import Counter from './Counter'
export default {
  components: { Counter }
}
</script>

<template>
  <div>
    <p>Written in App.vue</p>
    <counter/>
  </div>
</template>

<style scoped>
  div {
    background: green;
  }
</style>
```
```src/index.js
import Vue from 'vue'
import App from './components/App'

new Vue({
  el: '#app',
  components: { App },
  template: '<app/>'
})
```
###ビルド時にpublicディレクトリ内のファイルを含める
```zsh
npm i -D copy-webpack-plugin
```
```webpack.config.js
const CopyPlugin = require('copy-webpack-plugin')

module.exports = {
  // ...
  plugins: [
    // ...
    new CopyPlugin([{ from: './public' }])
  ],
  // ...
}
```
完成！

##Vue CLI
###セットアップ
```zsh
$ npm install -g @vue/cli
$ vue create counter-vuecli
? Please pick a preset: default (babel, eslint) #defaultを選択
$ cd counter-vuecli
$ npm run serve
```
http://localhost:8080/ にアクセスして表示を確認

###プログラムを記述
```zsh
$ touch src/components/Counter.vue
```
```src/components/Counter.vue
<template>
  <div>
    <p>Written in Counter.vue</p>
    <button @click="reduce">-</button>
    <span>{{ count }}</span>
    <button @click="add">+</button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      count: 0
    };
  },
  methods: {
    add: function() {
      this.count++;
    },
    reduce: function() {
      this.count--;
    }
  }
};
</script>


<style scoped>
div {
  color: blue;
}
button {
  width: 30px;
  height: 3
0px;
  border-radius: 50%;
}
</style>
```
```src/App.vue
<template>
  <div>
    <p>Written in App.vue</p>
    <counter />
  </div>
</template>

<script>
import Counter from "./components/Counter";
export default {
  components: { Counter }
};
</script>

<style scoped>
div {
  background: green;
}
</style>
```
完成！

Vue CLIの内部でWebpackが動いていて、いろんな設定を自動でやってくれているようです。

`public/index.html`内に`<!-- built files will be auto injected -->`って書いてある通り、バンドルされたjsファイルが自動で挿入されます。

ビルド用に`copy-webpack-plugin`を手動で入れる必要もありません。

##Nuxt.js
###セットアップ
```zsh
$ npx create-nuxt-app counter-nuxt
# 以下を選択。他はデフォルト
# language: JavaScript
# package manager: npm
# mode: Single Page App
$ cd counter-nuxt
$ npm run dev
```
http://localhost:3000/ にアクセスして表示を確認

###プログラムを記述
```zsh
$ touch components/Counter.vue
```
```components/Counter.vue
<template>
  <div>
    <p>Written in Counter.vue</p>
    <button @click="reduce">-</button>
    <span>{{ count }}</span>
    <button @click="add">+</button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      count: 0
    };
  },
  methods: {
    add: function() {
      this.count++;
    },
    reduce: function() {
      this.count--;
    }
  }
};
</script>


<style scoped>
div {
  color: blue;
}
button {
  width: 30px;
  height: 30px;
  border-radius: 50%;
}
</style>
```
```pages/index.vue
<template>
  <div>
    <p>Written in index.vue</p>
    <counter />
  </div>
</template>

<script>
import Counter from "../components/Counter";
export default {
  components: { Counter }
};
</script>

<style scoped>
div {
  background: green;
}
</style>
```
```layouts/default.vue
<template>
  <div>
    <nuxt />
  </div>
</template>
```

##参考
- [Webpackで始めるVue.js - log.pocka.io](https://log.pocka.io/posts/vue-webpack-tutorial/)