Vue3+Express+Webpackの環境構築

Vue３ + express + webpackで開発環境を構築したときの備忘録。

##構成
最終的なフォルダとファイル構成は以下のとおり。

```
vue_app/
  ├  node_modules/
  ├  public/
  │　     └  bundle.js
　　　　│　     └  index.html
  ├  src/
  │　     └  App.vue
  │　     └  index.js
  ├  package.json
  ├  server.js
  └  webpack.config.jsoon
```

##1. 準備
てきとうなディレクトリを作成し、必要なモジュールをインストール。

```Bash
#プロジェクトのフォルダを作成
$ mkdir vue_app
$ cd vue_app

#package.jsonを作成
$ npm init -y

#expressをインストール
$ npm i -S express

#Vue3をインストール
$ npm i -S vue@next

#vueファイルを読み込むために必須
$ npm i -D vue-loader@next @vue/compiler-sfc

#vueファイルでcssを読み込むために必須
$ npm i -D css-loader vue-style-loader

#babelをインストール
$ npm i -D @babel/core @babel/preset-env babel-loader

#webpackをインストール
$ npm i -D webpack webpack-cli
```
- SFC を扱うために必要な基本ローダー
    - vue-loader@next (SFC を読み込む)
    - @vue/compiler-sfc(vue-loader を動かすのに必要)
    - css-loader (css を読み込む)
    - vue-style-loader (読み込んだ css を js に埋め込む)
- JS のトランスパイルに必要なローダー
    - @babel/core (Babel の本体)
    - @babel/preset-env (実行環境を自動で指定してトランスパイルするプリセット)
    - babel-loader (JS をトランスパイルする)
- Webpack
    - webpack (webpack本体)
    - webpack-cli (webpackコマンドを使うために必要なパッケージ)


##2. package.jsonの編集
ルートディレクトリのpackage.jsonを以下のように編集。
script.testを削除して、script.startとscirpt.buildを追加。

```diff:package.json
{
  "name": "sample",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
-   "test": "echo \"Error: no test specified\" && exit 1"
+   "start": "node server.js",
+   "build": "webpack"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "express": "^4.17.1",
    "vue": "^3.2.18"
  },
  "devDependencies": {
    "@babel/core": "^7.15.5",
    "@babel/preset-env": "^7.15.6",
    "@vue/compiler-sfc": "^3.2.18",
    "babel-loader": "^8.2.2",
    "css-loader": "^6.3.0",
    "vue-loader": "^16.8.1",
    "vue-style-loader": "^4.1.3",
    "webpack": "^5.54.0",
    "webpack-cli": "^4.8.0"
  }
}
```
##3. webpack.config.jsの作成
ルートディレクトリにwebpack.config.jsを作成。

```javascript:webpack.config.js
const path = require("path")
const {VueLoaderPlugin } = require("vue-loader")

module.exports = {
    //モードをdevelopment、production、noneから設定(必須)
    //development: 開発時のファイル出力モード(最適化より時間短縮、エラー表示を優先）
    //production: 本番時のファイル出力モード（最適化されて出力）
    mode:'development',

    //メインとなるjsファイル(エントリーポイント)
    entry: "./src/index.js",
    //ファイルの出力設定
    output: {
        //出力先のディレクトリ（絶対パスで指定）
        path: path.resolve(__dirname, "public"),
        //出力ファイル名
        filename: "bundle.js",
    },
    //ローダーの設定
    module: {
        rules: [
            {
                test: /\.css$/, //拡張子が.cssの場合
                use: ["vue-style-loader", "css-loader"] //vue-style-loader、css-loaderを使う
            },
            {
                test:/\.vue$/, //拡張子が.vueの場合
                loader: "vue-loader" //vue-loaderを使う
            },
            {
                test: /\.js$/, //拡張子が.jsの場合
                exclude: /node_modules/, //ローダーの処理から外すフォルダ
                loader: "babel-loader", //babel-loaderを使う
                //babelのオプションを指定
                options: {
                    //プリセットを指定することで、　ES2019　を　ES６　に変換
                    presets: [
                        "@babel/preset-env"
                    ]
                }
            }
        ]
    },
    plugins: [
        //Vueを読み込むために必要
        new VueLoaderPlugin()
    ],
}
```

##4. Vueアプリケーション（フロントエンド）
ルートディレクトリのsrcフォルダを作成して、その中にindex.jsとApp.vueを作成。

```javascript:src/index.js
//vueモジュールからcreateAppメソッドを取り込み
import { createApp } from 'vue'
//作成したコンポーネントファイルを取り込み
import App from './App.vue'

//Vue3のオブジェクトを生成
var app = createApp(App)
//#appの中に組み込み
app.mount('#app')
```

```vuejs:src/App.vue
<template>
    <div>
        {{ message }}
    </div>
</template>

<script>
export default {
    name: "App",
    data() {
        return {
            message: "Hello Vue!"
        }
    }
}
</script>
```

ルートディレクトリにpublicフォルダを作成して、index.htmlを作成。

```html:public/index.html
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>vue_app</title>
    </head>
    <body>
        <div id="app"></div>
        //webpackの出力ファイルを指定
        <script type="module" src="./bundle.js"></script> 
    </body>
</html>
```
##５. express(バックエンド)
ルートディレクトリにserver.jsを作成。

```javascript:server.js
//Expressのモジュールを取り込んで生成
const express = require('express')
const path = require('path')
const app = express()

//サーバーを起動
app.listen(3000, () => {
    console.log('sucsess!!')
})

//publicディレクトリ以下は自動で返す
app.use(express.static(path.join(__dirname, 'public')))
//トップへのアクセスを/publicへ流す
app.get('/', (req, res) => {
    res.redirect(302, '/public')
})
```

##６. webpackの実行&サーバーの起動
package.jsonで設定したscriptを実行。
npm run build とするとwebpackがpublic/bundle.jsを生成します。
npm run start を実行し、[http://localhost:3000](http'//localhost:3000)にアクセスすると'Hello Vue!'と表示されます。

```bash
$ npm run build #webpackの実行
$ npm run start #サーバーの起動
```

##参考
[webpack + Vue(webpack.config.js書き方の例)](https://qiita.com/ktnaoooo/items/c1687ea8668b72f71fb1)