본문 바로가기
Dot/Woowa-dots

React + Typescript + Webpack + Babel + ESLint + Prettier + Husky + Emotion

by jum0 2021. 8. 24.

프로젝트 boilerplate

기준은 깃허브에서 새로운 repository를 만들고, 로컬로 clone한 상태에서 시작하는 것을 기준으로 한다. (README.md 파일만 있다고 가정한다)

목차

  • 기본 폴더 및 파일 세팅
  • React, Typescript
  • Babel, Webpack
  • ESLint, Prettier
  • Husky, Lint-staged
  • Emotion

기본 폴더 및 파일 세팅

다음과 같이 폴더와 파일을 추가한다.

folder-structure

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>boilerplate</title>
  </head>
  <body>
    <div id="root"></div>
  </body>
</html>

.gitignore

build
node_modules
yarn-error.log

package.json

{
  "name": "dutch-dutch",
  "version": "0.0.1",
  "description": "dutch-dutch is dutch treat calculator application!",
  "main": "src/index.tsx",
  "repository": "https://github.com/jum0/dutch-dutch.git",
  "author": "jum0 <wnsah052@naver.com> (https://github.com/jum0)",
  "license": "MIT",
}

React, Typescript

yarn add react react-dom

react - 사용자 인터페이스를 만들기 위한 자바스크립트 라이브러리. 대표적인 웹 프레임워크.
react-dom - ReactDOM을 사용할 수 있도록 하는 패키지로 react 패키지와 한 세트. 우리에게 익숙한 API로 render()와 createPortal() 등이 포함된 패키지.

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

@types/react - react에 대한 타입 정의가 포함되어 있는 패키지.
@types/react-dom - react-dom에 대한 타입 정의가 포함되어 있는 패키지.

src 폴더 안에 App.tsxindex.tsx, assets.d.ts파일을 추가한다.

src/App.tsx

const App = () => {
  return (
    <>
      <h1>hello-boilerplate</h1>
      {*/ Webpack 관련 패키지 추가하면 에러 사라짐 /*}
      <h1>mode: {process.env.NODE_ENV}</h1> 
    </>
  );
};

export default App;

src/index.tsx

import { StrictMode } from 'react';
import ReactDOM from 'react-dom';
import App from './App';

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

src/types/assets.d.ts

declare module '*.ico';
declare module '*.gif';
declare module '*.png';
declare module '*.jpg';
declare module '*.jpeg';
declare module '*.svg';

터미널에 npx tsc --init 명령어를 입력하여 tsconfig.json 파일을 추가한다.

npx tsc --init

tsconfig.json

지금까지 디렉터리 구조

React, Typescript 설치 후 디렉터리 구조

Babel, Webpack

지금까지 과정은 브라우저에서 코드가 렌더링 될 수 있지만, 브라우저가 리액트 코드를 이해할 수는 없는 상태이다. 그래서 브라우저가 코드를 해석할 수 있도록 리액트와 타입 스크립트 코드를 자바스크립트 코드로 변환해주는 Babel을 추가한다.

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

@babel/core - 바벨을 사용하는데 필요한 패키지.
@babel/preset-env - 브라우저 또는 런타임 환경에 따라 필요한 Babel 플러그인과 polyfill을 자동으로 관리하여 최신 javascript를 사용할 수 있도록 도와주는 패키지. (polyfill -웹 개발에서 어떤 기능을 지원하지 않는 브라우저 상의 기능을 구현하는데 필요한 코드)
@babel/preset-react - react 문법을 변환하는데 필요한 규칙을 정의한 패키지.
@babel/preset-typescript - typescript 문법을 변환하는데 필요한 규칙을 정의한 패키지.

yarn add -D @babel/runtime @babel/plugin-transform-runtime

@babel/runtime: Babel modular runtime helpers와 regenerator-runtime 버전을 포함하는 라이브러리이고 모듈러 방식으로 함수를 실행하는 것을 포함한다. @babel/plugin-transform-runtime과 함께 사용된다.
@babel/plugin-transform-runtime: 코드 크기를 줄이기 위해 바벨의 helper code를 재사용할 수 있도록 하는 패키지.

babel 설정 파일인 .babelrc를 추가한다.

.babelrc

{
  "presets": [
    "@babel/preset-env",
    [
      "@babel/preset-react",
      {
        "runtime": "automatic"
      }
    ],
    "@babel/preset-typescript"
  ],
  "plugins": [
    [
      "@babel/plugin-transform-runtime",
      {
        "regenerator": true
      }
    ]
  ]
}
  • "regenerator" 옵션은 리액트 애플리케이션에서 asyn와 await 특징을 사용할 수 있도록 도와준다.

webpack 관련 패키지를 추가한다.

yarn add -D webpack webpack-cli webpack-dev-server html-webpack-plugin

webpack - 여러 개의 파일을 하나의 파일로 합쳐주는 모듈 번들러.
webpack-cli - 웹팩을 터미널 명령어로 실행할 수 있도록 도와주는 패키지.
webpack-dev-server - 기본적인 웹 서버를 구동시킬 수 있고, live reloading 기능도 제공하는 패키지.
hltml-webpack-plugin - webpack 번들을 제공하는 HTML 파일 생성을 단순화하는 패키지. 웹팩으로 빌드한 JS파일을 자동으로 HTML 파일에 넣어주어, HTML 파일에 script 태그를 적어주지 않아도 된다.

yarn add -D @svgr/webpack

@svgr/webpack: svg 파일을 리액트 컴포넌트처럼 사용할 수 있도록 도와주는 패키지.

yarn add -D webpack-merge

webpack-merge - webpack 설정 파일들을 묶을 수 있는 패키지.

yarn add -D @pmmmwh/react-refresh-webpack-plugin@next react-refresh

@pmmmwh/react-refresh-webpack-plugin: React components를 위한 Fast Refresh(이전에 Hot Reloading이라고 불린) 웹팩 플러그인.
react-refresh: Fast Refresh를 번들로 통합하는데 필요한 패키지.

@next로 한 것은 v0.5.0-rc.5 버전부터 dev serve 관련 이슈가 고쳐졌는데, 깃허브에서 lataestv0.4.3라서. (210829 기준)

최신 버전이 v0.5.1 이므로 @next를 빼고 yarn add -D @pmmmwh/react-refresh-webpack-plugin으로 설치해도 된다. (211020 기준)

다음으로 babel-loader를 추가한다.

yarn add -D babel-loader

babel-loader: webpack과 babel을 사용해서 javascript 파일을 transpile하는 패키지.

yarn add -D webpack-bundle-analyzer

webpack-bundle-analyzer: 웹팩 output 파일의 크기를 시각화하여 보여주는 패키지.

webpack 설정 파일을 추가한다. 위치는 package.json 파일이 있는 root 위치로 webpack.common.js, webpack.dev.js, webpack.prod.js 파일을 추가한다.webpack.common.js 파일은 공통, webpack.dev.js 파일을 development 모드일 때, webpack.prod.js 파일은 production 모드일 때 파일이다.

webpack.common.js

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: path.resolve(__dirname, './src/index.tsx'),
  resolve: {
    extensions: ['.js', '.ts', '.tsx'],
  },
  output: {
    path: path.resolve(__dirname, './build'),
    filename: 'bundle.js',
  },
  module: {
    rules: [
      {
        test: /\.(ts|js)x?$/,
        exclude: /node_modules/,
        use: [
          {
            loader: 'babel-loader',
          },
        ],
      },
      {
        test: /\.(?:ico|gif|png|jpg|jpeg)$/i,
        type: 'asset/resource',
      },
      {
        test: /\.(woff(2)?|eot|ttf|otf)$/,
        type: 'asset/inline',
      },
      {
        test: /\.svg$/,
        type: 'javascript/auto',
        use: ['@svgr/webpack'],
      },
    ],
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, './public/index.html'),
    }),
  ],
};
  • rules에서 type 부분인 Asset Modules에 관한 자세한 내용은 포스트 참고.

webpack.dev.js

const { merge } = require('webpack-merge');
const common = require('./webpack.common');
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');

module.exports = merge(common, {
  mode: 'development',
  devServer: {
    open: true,
  },
  devtool: 'eval-source-map',
  plugins: [new ReactRefreshWebpackPlugin()],
});

webpack.prod.js

const { merge } = require('webpack-merge');
const common = require('./webpack.common');
// const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

module.exports = merge(common, {
  mode: 'production',
  devtool: false,
  // plugins: [new BundleAnalyzerPlugin()],
});
  • webpack-bundle-analyzer는 필요할 때만 주석 풀고 사용하면 된다.

ESLint, Prettier

ESLint 관련 패키지를 추가한다.

yarn add -D eslint eslint-plugin-react eslint-plugin-react-hooks eslint-plugin-import eslint-plugin-jsx-a11y

eslint: 자바스크립트 문법에서 에러를 표시해주는 패키지.
eslint-plugin-react: react에서 eslint가 동작하도록 하는 패키지.
eslint-plugin-react-hooks: react hook에서 eslint가 동작하도록 하는 패키지.
eslint-plugin-import: ES2015 이상 import, export 문법 linting을 지원하는데, import나 export 할 때 잘못된 파일 경로나 이름에 관한 이슈를 막는 것을 지원하는 패키지.
eslint-plugin-jsx-a11y: 실시간으로 JSX 요소에 대한 접근성 규칙 확인을 위한 정적 AST checker 패키지

yarn add -D @typescript-eslint/parser @typescript-eslint/eslint-plugin

@typescript-eslint/parser: typescript 코드가 lint 되도록 하는 패키지.
@typescript-eslint/eslint-plugin: typescript에 맞는 eslint 룰을 포함하는 패키지.

ESLint 환경 설정 파일인 .eslintrc.js 파일을 추가한다.

.eslintrc.js

module.exports = {
  parser: '@typescript-eslint/parser',
  parserOptions: {
    ecmaVersion: '2021',
    sourceType: 'module',
    ecmaFeatures: {
      jsx: true,
    },
  },
  settings: {
    react: {
      version: 'detect',
    },
  },
  extends: [
    'plugin:react/recommended',
    'plugin:react-hooks/recommended',
    'plugin:@typescript-eslint/recommended',
    'plugin:import/errors',
    'plugin:import/warnings',
    'plugin:import/typescript',
    'plugin:jsx-a11y/recommended',
    'prettier',
    'plugin:prettier/recommended',
  ],
  rules: {
    'no-unused-vars': 'off',
    'react/prop-types': 'off',
    'react/jsx-uses-react': 'off',
    'react/react-in-jsx-scope': 'off',
    '@typescript-eslint/explicit-module-boundary-types': 'off',
    '@typescript-eslint/no-unused-vars': ['error'],
    '@typescript-eslint/no-var-requires': 'off',
  },
};

Prettier 관련 패키지를 추가한다.

yarn add -D prettier eslint-config-prettier eslint-plugin-prettier

prettier: 일관성 있는 코드를 위한 코드 formatter 패키지.
eslint-config-prettier: 불필요하거나 prettier와 충돌이 발생할 수 있는 eslint rule을 disable하는 패키지 .
eslint-plugin-prettier: eslint rule로 prettier로 동작하도록 하느 패키지.

Prettier 환경 설정 파일인 .prettierrc.js 파일을 추가한다.

module.exports = {  singleQuote: true,  trailingComma: 'all',  printWidth: 100,};

Husky, Lint-staged

Husky의 동작 과정은 사용자가 코드를 커밋하면 git hook인 pre-commit hook이 동작하고, husky 설정에서 lint-staged에게 동작하라고 요청하는 방식으로 진행된다.

yarn add -D husky@4
yarn add -D husky lint-staged && npx husky install && npx husky add .husky/pre-commit "yarn lint-staged"

husky@4를 먼저 추가한 후 husky를 추가하는 이유는 때때로 husky에 의해 훅이 추가되지 않는 이슈가 있기 때문이다. husky@4는 훅이 제대로 설치되는 것을 보장해준다. npx husky install은 Git hook을 설치하는 명령어이고, npx husky add .husky/pre-commit "yarn lint-staged"은 husky 환경 설정 파일로 우리가 사용하고자 하는 lint-staged를 추가하는 명령어이다.

husky: Git hook을 쉽게 사용할 수 있는 패키지.
lint-staged: staged에 파일에 lint, format을 적용할 수 있도록 도와주는 패키지.

package.jsonlint-staged 설정을 추가한다.

package.json

{
  "name": "dutch-dutch",
  "version": "1.0.0",
  "description": "dutch-dutch is dutch treat calculator application!",
  "main": "src/index.tsx",
  "repository": "https://github.com/jum0/dutch-dutch.git",
  "author": "jum0 <wnsah052@naver.com> (https://github.com/jum0)",
  "license": "MIT",
  "scripts": {
    "start": "webpack serve --config webpack.dev.js --node-env development",
    "start:build": "webpack --config webpack.prod.js --node-env production && cd build && npx serve ",
    "build": "webpack --config webpack.prod.js --node-env production",
    "lint": "eslint --fix \"./src/**/*.{js,jsx,ts,tsx,json}\"",
    "format": "prettier --write \"./src/**/*.{js,jsx,ts,tsx,json,md}\""
  },
  "dependencies": {
    "react": "^17.0.2",
    "react-dom": "^17.0.2"
  },
  "devDependencies": {
    "@babel/core": "^7.15.0",
    "@babel/plugin-transform-runtime": "^7.15.0",
    "@babel/preset-env": "^7.15.0",
    "@babel/preset-react": "^7.14.5",
    "@babel/preset-typescript": "^7.15.0",
    "@babel/runtime": "^7.15.3",
    "@pmmmwh/react-refresh-webpack-plugin": "^0.5.0-rc.5",
    "@svgr/webpack": "^5.5.0",
    "@types/react": "^17.0.19",
    "@types/react-dom": "^17.0.9",
    "@typescript-eslint/eslint-plugin": "^4.29.3",
    "@typescript-eslint/parser": "^4.29.3",
    "babel-loader": "^8.2.2",
    "eslint": "^7.32.0",
    "eslint-config-prettier": "^8.3.0",
    "eslint-plugin-import": "^2.24.2",
    "eslint-plugin-jsx-a11y": "^6.4.1",
    "eslint-plugin-prettier": "^3.4.1",
    "eslint-plugin-react": "^7.24.0",
    "eslint-plugin-react-hooks": "^4.2.0",
    "html-webpack-plugin": "^5.3.2",
    "husky": "^7.0.2",
    "lint-staged": "^11.1.2",
    "prettier": "^2.3.2",
    "react-refresh": "^0.10.0",
    "typescript": "^4.3.5",
    "webpack": "^5.51.1",
    "webpack-bundle-analyzer": "^4.4.2",
    "webpack-cli": "^4.8.0",
    "webpack-dev-server": "^4.0.0",
    "webpack-merge": "^5.8.0"
  },
  "lint-staged": {
    "src/**/*.{js,jsx,ts,tsx,json}": [
      "eslint --fix"
    ],
    "src/**/*.{js,jsx,ts,tsx,json,css,scss,md}": [
      "prettier --write"
    ]
  }
}

Emotion

스타일 관련 패키지로 emotion 관련 패키지를 추가한다.

yarn add @emotion/react @emotion/styled emotion-normalize

@emotion/react: 해당 패키지는 React가 필요하지만, React 프레임워크 사용자에게 권장되는 패키지.

@emotion/styled: styled.div 형식으로 emotion을 사용할 수 있도록 하는 패키지.

emotion-normalize: normalize.css 를 emotion에서 사용할 수 있도록 하는 패키지.

Global Styles 추가

src/GlobalStyle.tsx

import { css, Global } from '@emotion/react';
import emotionNormalize from 'emotion-normalize';

const GlobalStyle = () => (
  <Global
    styles={css`
      ${emotionNormalize}

      * {
        box-sizing: border-box;
        padding: 0;
        margin: 0;
        border: 0;
      }

      html,
      body,
      #root {
        min-height: 100%;
        height: 100%;
        font-family: Helvetica, Arial, sans-serif;
        background-color: #efefef;
      }

      li {
        list-style: none;
      }
    `}
  />
);

export default GlobalStyle;

src/index.tsx

import { StrictMode } from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import GlobalStyle from './GlobalStyle';

ReactDOM.render(
  <StrictMode>
    <GlobalStyle />
    <App />
  </StrictMode>,
  document.getElementById('root'),
);
반응형

'Dot > Woowa-dots' 카테고리의 다른 글

Webpack) 잡다한 지식들  (0) 2021.08.26
Webpack) Asset Modules  (8) 2021.08.25
React에서 Cypress로 테스트하기  (0) 2021.07.28
[UX] 사례  (0) 2021.04.14
[우아한테크코스] 코드 리뷰 과정  (2) 2021.02.28

댓글