doc.dev1x.org

react.js開発環境構築

1. 目的

2. 環境

$ uname -srvmpio
Linux 5.8.0-59-generic #66~20.04.1-Ubuntu SMP Thu Jun 17 11:14:10 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux

$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 20.04.2 LTS
Release:    20.04
Codename:   focal

$ docker -v
Docker version 20.10.7, build f0df350

$ docker-compose -v
docker-compose version 1.26.0, build d4451659

3. プロジェクト初期構成

.
├── .env
├── .gitignore
├── Dockerfile
├── docker-compose.yaml
└── package.json
$ touch .env .gitignore Dockerfile docker-compose.yaml package.json

4. 開発用のコンテナ(node.js)作成

Dockerfile

FROM node:16.14

WORKDIR /app

COPY . /app

RUN yarn install

CMD ["yarn", "start"]

docker-compose.yaml

version: '3.8'
services:
  app:
    build:
      context: .
      dockerfile: Dockerfile
    env_file:
      - .env
    ports:
      - ${PORT}:${PORT}
    volumes:
      - .:/app

.env

PORT=8080
NODE_MODE=development

.gitignore

node_modules
dist
.env

package.json

{
  "name": "react-example",
  "version": "1.0.0",
  "private": true,
  "scripts": {
    "test": "echo hello"
  }
}

コンテナの動作確認

$ docker-compose build
$ docker-compose run --rm app npm -v
$ docker-compose run --rm app yarn -v

5. プロジェクトセットアップ

ライブラリインストール

$ yarn add  react \
            react-dom \
            typescript \
            webpack \
            webpack-cli \
            webpack-dev-server \
            html-webpack-plugin \
            ts-loader \
            jest \
            eslint \
            prettier \
            @types/jest \
            @types/node \
            @types/react \
            @types/react-dom \
            @typescript-eslint/eslint-plugin \
            @typescript-eslint/parser

各種設定ファイル作成

$ touch webpack.config.js \
        tsconfig.json \
        jest.config.js \
        eslintrc.json \
        .eslingignore \
        .prettierrc

package.jsonのscriptsセクションを更新

  "scripts": {
    "test": "jest",
    "start": "webpack-dev-server",
    "build": "webpack",
    "fmt": "prettier --write ./src/*.{js,json,ts,tsx}"
  },

webpack.config.js

const path = require('path')

const HtmlWebpackPlugin = require('html-webpack-plugin')
const htmlPlugin = new HtmlWebpackPlugin({
    template: "./public/index.html",
    filename: "index.html",
})


module.exports = {
    mode: process.env.NODE_MODE,
    entry: path.join(__dirname, 'src/index.tsx'),
    output: {
        path: path.join(__dirname, 'dist'),
        filename: 'bundle.js'
    },
    devtool: 'inline-source-map',
    module: {
        rules: [
            {
                test: /\.tsx?$/,
                loader: 'ts-loader',
            }
        ]
    },
    resolve: {
        extensions: ['.ts', '.tsx', '.js' , '.json'],
    },
    devServer: {
        static: {
            directory: path.join(__dirname, "dist"),
        },
        open: true,
        port: process.env.PORT
    },
    plugins: [
        htmlPlugin
    ]
}

tsconfig.json

{
  "compilerOptions": {
    "baseUrl": "src",
    "target": "es5",
    "lib": [
      "dom",
      "dom.iterable",
      "esnext"
    ],
    "allowJs": true,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noFallthroughCasesInSwitch": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "react-jsx"
  },
  "exclude": ["node_modules"],
  "include": ["src/**/*.ts", "src/**/*.tsx"]
}

jest.config.js

/** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */

module.exports = {
  preset: 'ts-jest',
  testEnvironment: 'node',
  globals: {
    "ts-jest": {
      tsconfig: './tsconfig.test.json'
    }
  }
};

eslintrc.json

{
  "extends": "eslint:recommended",
  "rules": {
  }
}

.eslingignore

node_modules/

.prettierrc

{
  "arrowParens": "always",
  "bracketSpacing": true,
  "endOfLine": "lf",
  "htmlWhitespaceSensitivity": "css",
  "jsxBracketSameLine": false,
  "jsxSingleQuote": false,
  "printWidth": 120,
  "semi": false,
  "singleQuote": true,
  "tabWidth": 2,
  "useTabs": false
}

6. ソースコード配置

index.tsx配置

$ mkdir src
$ cd src
$ touch index.tsx
import React from 'react'
import ReactDOM from 'react-dom'

const App = () => {
  return <div>Hello World.</div>
}

ReactDOM.render(<App />, document.getElementById('app'))

index.html配置

$ mkdir public
$ cd public
$ touch index.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>react typescript app</title>
</head>
<body>
    <div id="app"></div>
</body>
</html>

7. 開発サーバ起動

$ docker-compose up

8. 補足

リポジトリからクローンしてきた場合に行うこと

$ docker-compose run --rm app yarn install
$ docker-compose up -d

ライブラリを追加したい場合

# コンテナが停止している場合
$ docker-compose run --rm app yarn add ${インストールしたいライブラリ}

# コンテナを起動している場合
$ docker-compose exec app yarn add ${インストールしたいライブラリ}