DockerでReact+TypeScriptの環境構築

React, TypeScriptを使ったDocker環境を構築していく。今回はlocalhostでHello Worldを表示するプログラムを作成する。

ディレクトリは以下の構成
```
├── src
│   ├── index.html
│   └── Main.tsx
├── package.json
├── webpack.config.js
└── docker-compose.yml
```

それぞれのファイルの中身は以下：

まずTypeScript, ReactでHelloWorldを出力するプログラムを作成していく。
1. rootブロックのみのHTMLファイルを作成する
```html:index.html
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
</head>
<body>
  <div id="root"></div>
</body>
</html>
```
2 . Hello Worldを画面に表示するだけのTypeScriptのファイルを作成する
```typescript:Main.tsx
import React from 'react';
import ReactDOM from 'react-dom';

ReactDOM.render(
  <h1>Hello, world!</h1>,
  document.getElementById('root')
);
```
3 . package.jsonファイルは以下のように設定、
```json:package.json
{
  "name": "book-app",
  "version": "1.0.0",
  "description": "Book Application",
  "main": "./src/Main.tsx",
  "scripts": {
    "build": "webpack",
    "start": "webpack-dev-server"
  },
  "author": "hato",
  "dependencies": {
    "html-webpack-plugin": "^5.5.0",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "ts-node": "^10.9.1",
    "typescript": "^5.0.2"
  },
  "devDependencies": {
    "@babel/core": "^7.22.9",
    "@babel/preset-env": "^7.18.6",
    "@babel/preset-react": "^7.18.6",
    "@babel/preset-typescript": "^7.22.5",
    "@types/node": "^18.15.3",
    "@types/react": "^18.2.17",
    "@types/react-dom": "^18.2.7",
    "babel-loader": "^8.2.5",
    "webpack": "^5.73.0",
    "webpack-cli": "^4.10.0",
    "webpack-dev-server": "^4.9.3"
  },
  "babel": {
    "presets": [
      "@babel/preset-env",
      "@babel/preset-react",
      "@babel/preset-typescript"
    ]
  }
}

```
4 . webpack.config.jsでbuildの設定を記述する
```JavaScript:webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin'); //installed via npm
const webpack = require('webpack'); //to access built-in plugins
const path = require('path');

module.exports = {
  mode: 'development',
  entry: path.resolve(__dirname, './src/Main.tsx'),
  output: {
    path: path.resolve(__dirname, './dist'),
    filename: 'bundle.js'
  },
  devServer: {
    port: 3000,
    static: {
      directory: path.resolve(__dirname, "./dist"),
    }
  },
  resolve: {
    modules: [path.resolve(__dirname, "src"), "node_modules"],
    extensions: ['.js', '.jsx', ".ts", ".tsx"]
  },
  module: {
    rules: [
      {
        test: /\.tsx$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader'
        }
      },
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({ template: './src/index.html' })
  ]
};

```

#### Dockerの設定
Dockerのcomposeファイルは以下のように設定。
```yaml:docker-compose.yml
version: '3.8'
services:
  book_co_web:
    image: node:18-alpine
    container_name: book_co_web
    volumes:
      - ./:/app
    working_dir: /app
    command: >
      sh -c "npm install && npm start"
    ports:
      - "3000:3000"
```

### プログラムの実行
以下のコマンドをterminal上で実行する。
```terminal
docker compose up
```

実行結果が以下のようになったら成功。`localhost:3000`にアクセスすればHello Worldが表示されている画面が見れる。
```terminal
[+] Running 1/0
 ✔ Container book_co_web  Recreated                                                                                    0.1s 
Attaching to book_co_web
book_co_web  | 
book_co_web  | up to date in 11s
book_co_web  | 
book_co_web  | 55 packages are looking for funding
book_co_web  |   run `npm fund` for details
book_co_web  | 
book_co_web  | > book-app@1.0.0 start
book_co_web  | > webpack-dev-server
book_co_web  | 
book_co_web  | <i> [webpack-dev-server] Project is running at:
book_co_web  | <i> [webpack-dev-server] Loopback: http://localhost:3000/
book_co_web  | <i> [webpack-dev-server] On Your Network (IPv4): http://172.19.0.2:3000/
book_co_web  | <i> [webpack-dev-server] Content not from webpack is served from '/app/dist' directory
book_co_web  | asset bundle.js 1.37 MiB [emitted] (name: main)
book_co_web  | asset index.html 148 bytes [emitted]
book_co_web  | runtime modules 27.5 KiB 13 modules
book_co_web  | modules by path ./node_modules/ 1.25 MiB
book_co_web  |   modules by path ./node_modules/webpack-dev-server/client/ 71.8 KiB 16 modules
book_co_web  |   modules by path ./node_modules/webpack/hot/*.js 5.3 KiB 4 modules
book_co_web  |   modules by path ./node_modules/html-entities/lib/*.js 81.8 KiB 4 modules
book_co_web  |   modules by path ./node_modules/react/ 85.7 KiB 2 modules
book_co_web  |   modules by path ./node_modules/react-dom/ 1000 KiB 2 modules
book_co_web  |   modules by path ./node_modules/scheduler/ 17.3 KiB
book_co_web  |     ./node_modules/scheduler/index.js 198 bytes [built] [code generated]
book_co_web  |     ./node_modules/scheduler/cjs/scheduler.development.js 17.1 KiB [built] [code generated]
book_co_web  |   ./node_modules/ansi-html-community/index.js 4.16 KiB [built] [code generated]
book_co_web  |   ./node_modules/events/events.js 14.5 KiB [built] [code generated]
book_co_web  | ./src/Main.tsx 174 bytes [built] [code generated]
book_co_web  | webpack 5.88.2 compiled successfully in 2512 ms
```



## おまけ
YAMLファイルでなく、DockerFileを使って書くとこんな感じの記法になる
```Dockerfile:Dockerfile
FROM node:18-alpine
COPY . .
RUN npm install
EXPOSE 3000
CMD ["npm", "start"]
```
コマンドは以下のように実行
```terminal
docker build -t book-app:1.0 .
docker run -p 3000:3000 --name book <imagename>
```

## 参考

https://qiita.com/wangqijiangjun/items/54a949cd140b61dc7763

https://zenn.dev/spacemarket/articles/23e5401a074ccc