리액트 프로젝트 셋업

리액트를 사용하는 프로젝트를 생성할 때 마다 create-react-app(이하 CRA)를 사용하게 되었었는데요, scratch 부터 자주 사용하는 구성을 템플릿으로 남겨두고 싶은 마음이 생겼습니다. 기본적으로 사용되는 React, typescript, webpack, babel, eslint, prettier 설정입니다.
2022.02.16

리액트를 사용하는 프로젝트를 생성할 때 마다 create-react-app(이하 CRA)를 사용하게 되었었는데요, scratch 부터 자주 사용하는 구성을 템플릿으로 남겨두고 싶은 마음이 생겼습니다. 기본적으로 사용되는 React, typescript, webpack, babel, eslint, prettier 설정입니다.

각각의 항목들에 대해서 자세하기 다루기 보다는 사용할 수 있는 형태의 코드를 제공하는게 목적입니다.

아래의 레포지토리에서 본 블로그의 코드 전체를 확인하실 수 있습니다.

https://github.com/Tolluset/react-pj-template

템플릿 개요

# 사용할 라이브러리 버전

react 17.0.2
typescript 4.5.5
webpack 5.68.0
babel 7.12.2
eslint 8.8.0
prettier 2.5.1

이번에 사용할 프로젝트 패키지입니다.

프로젝트 생성

mkdir react-pj-template
cd react-pj-template

yarn init -y // 초기 설정 스킵하여 디폴트 옵션으로 생성

프로젝트 생성할 디렉토리를 만들고 해당 디렉토리에서 yarn init 패키지 파일을 초기화해 줍니다.

디렉토리 및 index.html 생성

CRA에서 해주는 것처럼, public, src 디렉토리를 만들고 publicindex.html 을 추가 해줍시다.

mkdir public src
touch public/index.html
// public/index.html

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Title</title>
</head>
<body>
    <div id="root"></div>
</body>
</html>

<div id="root"><div> 부분이 우리의 리액트가 들어갈 자리가 되겠습니다.

React

yarn add react react-dom
yarn add -D @types/react @types/react-dom

@types 는 실제로 타입 모듈을 임포트해서 사용하면 dependencies 에 설치해야 하지만 이 템플릿에서는 사용하지 않기에 devDependencies에 설치합니다.

https://stackoverflow.com/questions/45176661/how-do-i-decide-whether-types-goes-into-dependencies-or-devdependencies

react-dom은 index.ts 에서 index.html 의 진입점에 렌더하기 위해 필요합니다.

// src/index.tsx

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';

ReactDOM.render(
  <React.StrictMode>
      <App />
  </React.StrictMode>,
  document.getElementById('root'),
);
// src/App.tsx

import React from 'react';

const App = () => {
  return <div>App</div>;
};

export default App;

이 템플릿에서는 Function Component 기준으로 생성하겠습니다.

리턴타입에는React.FC 를 사용하지 않고 추론적으로 사용하겠습니다.

https://github.com/facebook/create-react-app/pull/8177

Typescript

yarn add -D typescript

타입스크립트를 추가했으니 tsconfig.json 도 추가해주겠습니다.

// tsconfig.json

{
  "compilerOptions": {
    "target": "es5",
    "module": "es6",
    "strict": true,
    "jsx": "react",
    "moduleResolution": "node",
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "lib": ["es6","dom"],
    "outDir": "./dist",
  },
  "ts-node": {
    "compilerOptions": {
      "module": "CommonJs"
    }
  },
  "include": ["src/**/*", "tests/**/*"],
}

targetes5 로 하면 라이브러리들이 es6 를 쓰는 경우 컴파일 단계에서 에러가 날 수 있는데요, 이를 위해 lib에 es6 를 추가 해 둡니다. (targetes6로 써도 되고요, IE가 2022년 6월경 지원종료를 하는데 IE 이외의 대부분의 브라우저가 잘 지원하죠... https://caniuse.com/?search=es6 커버율 96.34% 👀)

moduleimport, export 로 사용하고 싶기 때문에 es6 로 설정합니다.

stricttrue 로 해두면 타입스크립트가 권장하는 여러 규칙들을 자동으로 추가해줍니다.

https://www.typescriptlang.org/tsconfig#strict

jsxreact 를 사용하기 때문에 그대로 사용합니다.

esModuleInteropimport * as A from Aimport A from A 같이 default import를 사용할 수 있게 해줍니다.

moduleResolution 는 모듈 import를 어떻게 할 것이냐 node 의 경우 nodejs 가 사용하는 방식을 사용합니다.

moduleResolution 에 대한 자세한 내용은 아래의 링크가 도움이 될 것 같습니다.

TypeScript 한글 문서

좀 더 tsconfig 를 세밀조정하고 싶다면, 레퍼런스를 참조해주세요.

https://www.typescriptlang.org/tsconfig

Webpack

# tl;dr
yarn add -D webpack webpack-cli webpack-dev-server babel-loader html-webpack-plugin clean-webpack-plugin ts-node @types/node @types/webpack @types/clean-webpack-plugin

# webpack
yarn add -D webpack webpack-cli webpack-dev-server

# loader
yarn add -D babel-loader

# plugins
yarn add -D html-webpack-plugin clean-webpack-plugin

# types
yarn add -D ts-node @types/node @types/webpack @types/clean-webpack-plugin

# webpack : 웹팩을 사용하기 위한 cli와 개발환경에서 필요한 dev-server를 추가해줍니다.

# loader : 코드에 대한 해석을 babel에게 맡깁니다.

# plugins : html을 가져다 쓰기 위한 html-webpack-plugin 과 빌드 시 마다 빌드된 파일을 저장하는 폴더를 초기화 시켜주는 clean-webpack-plugin 을 사용합니다.

# types : webpack.config.ts 를 사용하는게 🆒하다 생각하기 때문에 를 사용하기 위함입니다. (.js 로 해도되는데 github에 js를 사용하고 있다고 나오는게 묘하게 거슬려요, 저만 그런가요??? 🤔)

// webpack.config.ts

import path from "path";
import webpack from "webpack";
import HtmlWebpackPlugin from "html-webpack-plugin";
import { CleanWebpackPlugin } from "clean-webpack-plugin";
import ESLintPlugin from 'eslint-webpack-plugin';
import "webpack-dev-server";

const config: webpack.Configuration = {
  mode: "development",
  entry: "./src/index.tsx",
  module: {
    rules: [
      {
        test: /\.(ts|tsx)$/,
        include: path.resolve(__dirname, 'src'),
        use: {
          loader: "babel-loader",
        },
      },
    ],
  },
  resolve: {
    extensions: [".tsx", ".ts", ".js"],
  },
  output: {
    path: path.resolve(__dirname, "dist"),
    filename: "bundle.js",
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: "public/index.html",
    }),
    new CleanWebpackPlugin(),
    new ESLintPlugin({
      extensions: ['ts', 'tsx']
    })
  ],
};

export default config;

Babel

yarn add -D @babel/core @babel/preset-env @babel/preset-react @babel/preset-typescript

사용할 preset들은 es6를 위해 사용하는 env , 리액트를 위한 react , 타입스크립트를 위한 typescript 를 추가해 줍니다.

// .babelrc

{
  "presets": [
    "@babel/preset-env",
    "@babel/preset-react",
    "@babel/preset-typescript"
  ]
}

ESLint

yarn add -D @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint eslint-plugin-import eslint-plugin-react eslint-plugin-react-hooks eslint-import-resolver-typescript eslint-webpack-plugin

React, typescript와 관련된 ESlint를 추가해서 사용합니다.

plugins 에 사용할 플러그인들을 정의 해두고, extends 에서 플러그인들이 프리셋으로 제공하는 기능들을 지정하여 사용할 수 있습니다.

// .eslintrc.json

{
  "root": true,
  "env": { "browser": true, "es6": true },
  "parser": "@typescript-eslint/parser",
  "parserOptions": { "project": ["./tsconfig.json"] },
  "plugins": [
    "@typescript-eslint",
    "react",
    "react-hooks",
    "import",
    "jsx-a11y"
  ],
  "extends": [
    "eslint:recommended",
    "plugin:@typescript-eslint/recommended",
    "plugin:react/recommended",
    "plugin:import/recommended",
    "plugin:react-hooks/recommended",
    "plugin:jsx-a11y/recommended"
  ],
  "settings": {
    "import/parsers": {
      "@typescript-eslint/parser": [".ts", ".tsx"]
    },
    "import/resolver": {
      "typescript": {
        "project": "./tsconfig.json"
      }
    }
  },
  "rules": {
    "no-console": "warn",
    "import/order": [
      "error",
      {
        "groups": [
          "builtin",
          "external",
          "internal",
          "parent",
          "sibling",
          "index",
          "object",
          "type"
        ]
      }
    ]
  }
}

ESlint가 체크 할 필요 없는 파일은 .gitignore 처럼 아래와 같이 정의해주시면 됩니다.

// .eslintignore

node_modules
dist

위처럼 설정한 eslint를 webpack dev server에 연결하면

// webpack.cofing.ts

// ...omit

  plugins: [
    ...
    new ESLintPlugin({
      extensions: ['ts', 'tsx']
    })

터미널에서 바로 확인 하실 수 있게 됩니다.

Prettier

yarn add -D prettier eslint-config-prettier

eslint-plugin-prettier가 아닌 eslint-config-prettier 를 사용해줍니다.

ESlint 설정 파일의 extends 에 prettier 플러그인을 추가해줍니다.

// .eslintrc.json

// ...omit

{
  "extends": [
    ...
    "prettier"
  ]
}

extendsprettier 를 추가함으로써 eslint와 prettier가 충돌하지 않게 적절하게 이미 설정된 rule들을 꺼줍니다. 그러므로 extends 의 마지막에 추가해주세요!

https://github.com/prettier/eslint-config-prettier

// .prettierc

{
    "tabWidth": 2,
    "useTabs": false,
    "semi": true,
    "singleQuote": true,
    "trailingComma": "all",
    "bracketSpacing": true,
    "parser": "typescript",
    "arrowParens": "always"
}

singleQuote, tarilingComma, parser 이외의 설정은 기본값이지만 변경하지 않도록 주의하기 위해 의도적으로 표시해둡니다.

추가적인 옵션들은 아래의 링크를 참조해주세요.

Options · Prettier

// .prettierignore

dist
node_modules

포맷팅이 필요없는 파일은 적절하게 걸러줍니다.

에필로그

Webpack의 프로덕션 빌드, 환경 별 파일 분리 및 머지 같은 설정이나, https://webpack.kr/guides/production/

Husky, lint-staged를 이용해서 좀 더 영리하게 린팅, 포매팅,

환경변수 등등...

추가적인 설정을 더 해둬야 하긴 합니다 🤪


본 블로그 게시글을 보시고 문의 사항이 있으신 분들은 클래스메소드코리아 (info@classmethod.kr)로 연락 주시면 빠른 시일 내 담당자가 회신 드릴 수 있도록 하겠습니다 !