[Docker] DockerでNode.js+express+webpackの環境を作る

# 概要
Dockerを使ってexpressとwebpackの入ったnode.jsの環境の構築をする手順をメモする。
(※初心者なので間違えているところや誤解している所があればコメントで教えてくださると助かります。)

# 準備

まず以下のコマンドをターミナルで打ってディレクトリとファイルを作成します。

```
mkdir myapp
cd myapp
touch Dockerfile docker-compose.yml package.json \
webpack.config.js
mkdir views public 
```

今、myappのフォルダの構成は以下のようになっている。

```
myapp
├── Dockerfile
├── docker-compose.yml
├── package.json
├── public
├── views
└── webpack.config.js
```

#1.package.jsonを作成する

まずはpackage,jsonを作成する。

package.jsonでは、アプリに必要なパッケージを予め記入しておくことも可能である。
`npm init -y`で作成することも可能だが、今回は予めパッケージの情報を書いておく方法を述べる。

私の環境ではpackage.jsonの構成は以下である。

```
{
  "name": "app",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "bootstrap": "^4.5.3",
    "ejs": "^3.1.5",
    "express": "^4.17.1",
    "jquery": "^3.5.1",
    "js": "^0.1.0",
    "popper.js": "^1.16.1",
    "node-sass": "^5.0.0",
    "postcss-loader": "^4.0.4",
    "sass": "^1.29.0",
    "sass-loader": "^10.0.5",
    "style-loader": "^2.0.0",
    "webpack": "^5.4.0",
    "webpack-cli": "^4.2.0",
    "css-loader": "^5.0.1",
    "extract-text-webpack-plugin": "^4.0.0-beta.0"
  },
  "devDependencies": {
    "autoprefixer": "^10.0.1",
    "fibers": "^5.0.0"
  }
}

```
ここで

```
npm install -D パッケージ　# devDependenciesに保存→開発環境
npm install -S パッケージ # 本番環境に保存
```
されることに注意が必要である。

# 2.Dockerfileを作成する

次にDockerfileを作成する。
Dockerfileを利用することで開発環境を差異なくかつ高速で作成することができる。
Dockerfileの中身は以下のように記述する。

```
#nodejsのバージョンを指定する。
FROM node:12.0

#os内で必要なパッケージをインストール(おまじない的に書いておくのがおすすめ)
RUN apt-get update && apt-get install -y \
    # root以外のユーザーがrootの権限を使うため
    sudo \
    # internetからツールを取得
    wget \
    # vim をエディタとして使用
    vim 


# アプリケーションディレクトリの作成
RUN mkdir /app
# appディレクトリを開発ディレクトリとして利用
WORKDIR /app

# コンテナにpackage.jsonとpackate-lock.jsonの２つがコピーされるようにする
COPY package*.json ./
# package.jsonに書いてあるパッケージをインストールする。
RUN npm i

# installされたnode_moduleなどのファイルをコンテナ側にコピーする。
COPY . .

CMD ["node","app.js"]
```

# 3.docker-compose.ymlを作成する
docker-compose.ymlを使うことでいくつかのdockerのコンテナを同時に立ち上げることができる。
今回はデータベースを使用しないため、node.jsのコンテナのみを立ち上げる。
docker-compose.yml配下のように記述する。

```
# docker-composeのバージョンを指定
version: "3"

services:
  app:
  # 同じディレクトリ内のDockerfileをbuildする
    build: .
  #  コンテナの名前をつける(任意)
    container_name: nodesam
    # コンテナを起動させ続けられる。
    tty: true
    # ディレクトリ内のファイルをコンテナ内のappディレクトリにマウントする
    volumes: 
      - .:/app
      # コンテナ側の1000番のポートをホスト側の8080番のポートにマウントする。
    ports:
      - "8080:8080"
```

# 4.webpack.config.jsを作成する
webpack.config.jsを作成することで、

```
npx webpack
```
のコマンドを打つことでscssやtypescriptなどのファイルを一つのjsファイルにコンパイルする事ができる。
[webpackの公式サイト](https://webpack.js.org/)を見ることで概要を確認できるので確認していただきたい。
実際のファイルの構成は
[webpackを使ってcssとscssをコンパイルする](https://qiita.com/maru401/items/fe01a700d6a0faa06346)

```
const path = require('path');


module.exports = {
  // modeはproduction/developmentで記述
  // ""で囲むことに注意
  mode: "development",
  // どのファイルを読み込むか　default=> ./src/index.js
  entry: './public/index.js',
  //　entryで読み込んだファイルのコンパイルの吐き出し場所
  output: {
    path: path.resolve(__dirname, 'public'),
    // distにsample.jsというファイル名で吐き出し
    filename: 'sample.js',

  },

  module: {
    rules: [
      
      // Sassファイルの読み込みとコンパイル
      {
        // 拡張子がsassとscssのファイルを対象とする
        test: /\.s[ac]ss$/i,
        // ローダー名 
        use: [
          // linkタグに出力する機能
          "style-loader",
          // CSSをバンドルするための機能
          "css-loader",
          // sass2css
          "sass-loader",
        ],
      },
      {
        // 対象となるファイルの拡張子
        test: /\.(gif|png|jpg|eot|wof|woff|ttf|svg)$/,
        // 画像をBase64として取り込む
        type: "asset/inline",
      },
    ],
  },
  // ES5(IE11等)向けの指定（webpack 5以上で必要）
  target: ["web", "es5"],
};
```

#５．publicとviwesにファイルを追加する

以下のコマンドを実行してindex.ejsとstyle.scssを作成します。

```
touch public/style.scss views/index.ejs
touch app.js
```

とりあえずindex.ejsの中身は最小限に構成する。

```:index.ejs
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <h1>Hello world</h1>
    <script src="./sample.js"></script>
</body>

</html>
```

続いて、style.scssを以下のように記述する。

```
body{
    background: red;
}

h1{
    color: aqua;
}
```

最後にejsファイルをhttp通信で確認できるようにするために、app.jsを作成する。
構成は以下のようにする。

```
const express = require('express');
const path = require('path');
const app = express();
const ejs = require("ejs");


// host:port 0.0.0.0:8080
// ホストの0.0.0.0ポートを8080番のポートにマッピングする。
const PORT = 8080;
const HOST = '0.0.0.0';
// publicファイルを基準にする→これによりpublic内のcssやjavascriptが読み取れる
app.use(express.static("public"));
// ejsを読取り可能にする
app.set('ejs',ejs.renderFile)


app.get('/', (req, res) => {
  res.render("index.ejs")
});![スクリーンショット 2020-11-10 1.41.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/656158/83a6cdb6-1af6-dcca-7aa6-38977aa345fa.png)


app.listen(PORT, HOST);
console.log(`Running on http://${HOST}:${PORT}`);
```

#6.docker-composeでサーバーを立ち上げる
実際にdocker-composeでサーバーを立ち上げる。
コマンドは以下の順序で打つ。

```
docker-compose build
docker-compose up 
```

docker-compose build :　docker-compose.ymlをもとにコンテナを作成する
docker-compose up    : docker-compose buildで作成したコンテナを立ち上げる

以下のコマンドのあと,

```
nodesam | Running on http://0.0.0.0:8080
```

と表示されるので実際に`http://0.0.0.0:8080`にアクセスすると以下のようなbackgroundが白でHello Worldと出力されているシンプルなサイトを確認できる。


![スクリーンショット 2020-11-10 1.41.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/656158/dfb0b5d5-97b9-d1aa-368d-d71495c2cb7b.png)






#6.webpackのコンパイル

先ほど作成したstyle.scssはindex.ejs内で読込をしていないため動かない。
そこでwebpackでstyle.scss→sample.jsにコンパイルする。

まずはコンパイルに使用するjsファイルをpublic内に作成する。

```
touch public/index.js
```

今回はstyle.scssだけをコンパイルするのでindex.jsは以下のようになる。

```:index.js
import "./style.scss"
```

コンパイルには以下のコマンドを用いる。
まずはコンテナ内に以下のコマンドで移動して,

```:hostのターミナル
docker  exec -it nodesam bash
```

```:dockerコンテナ内のターミナル
npx webpack
```

これでstyle.scss→style.js→sample.jsとコンパイルされpublicディレクトリ内にsample.jsというファイルが吐き出される。

これで再び`http://0.0.0.0:8080`にアクセスすると、以下のようにstyle.scssの内容が反映されているのが確認できる。(色キモいが)
![スクリーンショット 2020-11-10 2.59.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/656158/b4cc0d3f-80fa-7226-75dd-55e3625994f5.png)

これで今回は以上にする。

今回作成したコードは以下のgithubに載せておくので参考までに。

[今回作成したファイル等](https://github.com/marumaru1019/docker-node-webpack)




# 参考記事
[・Dockerfileの書き方](https://nodejs.org/ja/docs/guides/nodejs-docker-webapp/)
[・docker-compose.ymlの説明](https://qiita.com/zembutsu/items/9e9d80e05e36e882caaa)
[・webpackの使用方法]()