프로젝트 초기 설정해보기 (Next.js + Typescript + RTK)

Seungrok Yoon (Lethe)·2023년 1월 30일
1

[FE] 프로젝트 세팅

목록 보기
3/6

프로젝트 생성 & 설치

직접 설정해보는 프론트엔드 프로젝트 초기 설정

프로젝트 환경설정이라는 것에 막연한 불안감을 가지고 있었다. 개발공부를 한 지 이제는 꽤 되었다고 생각했는데도 나는 아직 아무것도 모르는 말하는 감자같다는 생각이 문득문득 들어서 마음이 불편했습니다. 그래서 시간을 들여서 한 번 환경설정을 진행해 보았습니다.

프레임워크와 Prettier, Eslint 설치 및 초기설정

Next.js

리액트 서버사이드 렌더링을 활용해 개발하기 위해서, Next.js를 선택했습니다.

13버전의 app 디렉토리도 추가해서 설치했습니다.

// 
- yarn create next-app --typescript ./ (./경로를 통해 현재 디렉토리에 프로젝트를 설치하도록 명령)

Styled-Components

Tailwind CSS도 좋은 선택지이지만, 제게는 더 익숙한 Styled-Components를 선택했습니다.

아직 CSS를 깔끔하게 사용하지 못하는 것 같아 조금 더 연습을 해 보려고 합니다.

next.js
원하는 디렉토리로 이동 후,

styled-components
- yarn add styled-components

Prettier

자동 줄바꿈이라던지, 들여쓰기라던지 코드를 조금 더 예쁘게 포매팅할 때는 프리티어를 많이들 사용하기에, 프리티어를 설치합니다.

Install · Prettier

CLI로 일괄적으로 수정을 할 수 있겠지만, 우리는 저장할 때마다 자동으로 포매팅이 되기를 원하기에, 에디터(저는 VSCode를 사용중입니다)에서도 추가적인 설정을 해 줍니다.

이것도 공식문서로 들어가서 한 번 어떻게 하는지 따라해 봅시다.

GitHub - prettier/prettier-vscode: Visual Studio Code extension for Prettier

//prettier와 플러그인 설치
yarn add --dev --exact prettier
yarn add --dev eslint-config-prettier (eslint 와 prettier 충돌 방지를 위해서)

Eslint

Prettier 같은 경우는 eslint 와 함께 사용하면 중복되는 규칙들이 있어서 이를 별도로 처리해주는 설정을 추가해야 합니다. 조금 귀찮지만 그래도 처음에 설정해두면, 이후에는 거의 수정할 일이 없으니 미리미리 잘 설정해 두자구요.

Next.js에서는 프레임워크에서 기본적으로 제공하는 eslint 룰이 있습니다. 그렇지만, 실제로 협업하는 상황을 상정하여 더욱 엄격한 규칙을 적용하고 싶었습니다.

개발 도중에 린트 규칙을 추가하거나 수정하면 모든 파일들에 대해 대량으로 수정을 가해야 하는 상황이 생길 수도 있어서 초기에 엄격한 규칙을 설정해놓고 개발하는 것이 개인적으로는 더 좋다고 생각이 들었습니다. 그래서 처음부터 Airbnb 룰을 적용해서 개발을 해 보도록 하겠습니다.

Configuration Files - ESLint - Pluggable JavaScript Linter

Getting Started | typescript-eslint

Eslint와 Prettier를 Typescript에도 적용시키기

typescript 를 사용하여 개발할 예정이기에, Eslint 가 타입스트립트를 인식할 수 있도록 적절한 패키지들을 설치해 줍니다.

typescript-eslint

typescript-eslint를 추가로 설치하게 되면, package.json에 아래 코드블럭에 있는 2개의 패키지들이 추가되어 있을 겁니다.

yarn add --dev @typescript-eslint/eslint-plugin @typescript-eslint/parser
//package.json
...
"@typescript-eslint/eslint-plugin": "^5.49.0",
"@typescript-eslint/parser": "^5.49.0",

이것들을 ESLint가 사용할 수 있도록 .eslintrc.json에 추가하면 됩니다.

아래 .eslintrc.json 파일의 parser: "@typescript-eslint/parser"옵션은 ESLint로 하여금 내 소스 파일들을 파싱하는데 "@typescript-eslint/parser"를 사용하라고 알려주는 옵션인데요, 이것이 없으면 타입스크립트 코드를 마치 자바스크립트 코드인 것처럼 파싱하게 되니까 반드시 설정해주도록 합니다.

Airbnb 룰 적용

핵심 패키지는

eslint-config-airbnb

이것이군요, 사용법을 읽어보니까 아래와같은 패키지들이 더 필요하다고 합니다.

  • eslint-config-airbnb
    • eslint-plugin-import
    • eslint-plugin-jsx-a11y
    • eslint-plugin-react
    • eslint-plugin-react-hooks

필요하다고 하니까 설치해 보도록 합시다. 명령문은 yarn 을 사용해서 필요한 패키지를 열거할 수도 있고, npm 5 버전 이상이라면 peer dependency를 한 번에 불러와서 yarn으로 설치할 수도 있습니다.

yarn add --dev eslint-config-airbnb eslint-plugin-import eslint-plugin-jsx-a11y eslint-plugin-react eslint-plugin-react-hooks

또는, npx install-peerdeps --dev eslint-config-airbnb && yarn

여기까지 수행하고 나면, 각 설정 파일들은 아래와 같이 수정하면 되겠습니다.

.eslintrc.json 의 각 프로퍼티들을 조금이라도 이해하려면 ESLint 공식문서를 읽어보면 좋더라구요. 한 번쯤은 가서 읽어보시는 것을 추천드립니다. 예전에는 그냥 블로그에서 이렇게 해라 저렇게 해라라고 알려주면 복사 붙여넣기로 프로젝트 환경설정을 했었는데, 어느 순간 ‘나는 아는게 하나도 없네’라는 생각이 들더라구요. 하나하나 공식문서를 읽어가면서 프로젝트 세팅을 하니까 보람도 있고 알아가는 것도 많은 느낌입니다.


//.prettierrc.json 작성
{
  "trailingComma": "es5",
  "tabWidth": 2,
  "semi": true,
  "singleQuote": true
}

//.eslintrc.json 작성
{
  "extends": ["airbnb", "airbnb/hooks", "next/core-web-vitals", "prettier"],
  "parser": "@typescript-eslint/parser",
  "plugins": ["@typescript-eslint"],
  "root": true,
  "overrides": [
    {
      "files": ["*.ts", "*.tsx"],
      "parserOptions": {
        "project": ["./tsconfig.json"]
      }
    }
  ]
}
// prettier를 vscode에 설정하기
// settings.json에 설정하기
{
  "typescript.tsdk": "node_modules/typescript/lib",
  "typescript.enablePromptUseWorkspaceTsdk": true,
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  "[javascript]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },
  "editor.formatOnSave": true, // 저장 시에 prettier 적용
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": true // 저장 시에 eslint 적용
  }
}

여기까지 하고 나서 lint가 잘 동작하는지 터미널에서 실행해봅니다.

yarn eslint .

몇 가지 에러들이 발생했군요

하나씩 해결해 보자구요.

먼저 JSX not allowed in files with extension ‘.tsx’

eslint-plugin-react/jsx-filename-extension.md at master · jsx-eslint/eslint-plugin-react

여기를 보니까 관련 rule을 수정하면 되는 것 같습니다.

우리는 파일확장자를 tsx를 사용하니까 extesnions 부분을 수정해서 .eslintrc.json 을 수정해 주면 되겠네요!

두 번째 에러인 'React' is not defined 에러는 React.CreateElement를 호출할 때 React를 호출하지 않아 생긴 린트 에러였습니다. react를 import 해주어 에러를 수정했습니다.

여러 줄의 Import 문에도 ESLint를 적용해보기

개발을 하다보면 import 구문의 규모가 커질 때가 있습니다.

import 문도 정렬을 하거나 그룹을 지어서 가독성을 올릴 수 있습니다. 구체적인 설정은 나중에 하더라도, 한 번 시도해 보죠.

Eslint 에서 기본적으로 제공하는 sort-imports 기능이 있습니다. 우리가 원하는 여러 import 구문을 정렬해줄 수 있을 지 한 번 확인해 봅시다.

sort-imports 규칙 검증

아래처럼 관련 규칙을 .eslintrc.json파일에 추가해주도록 합시다.

그랬더니 아래와 같은 린트 에러들이 다시 발생했습니다.

2:1 의 에러는 import 구분이 알파벳 순서가 아니기에 발생하는 이슈입니다.

The --fix
option on the command line automatically fixes some problems reported by this rule: multiple members on a single line are automatically sorted (e.g. import { b, a } from 'foo.js'
is corrected to import { a, b } from 'foo.js'
), but multiple lines are not reordered.

그런데, 기본 sort-imports 구문은 한 줄 내의 여러 import 만 알파벳 정렬을 하지 여러 줄을 정렬하지는 못하는 것을 발견했습니다.

그래서 sort-imports eslint 규칙은 제거했습니다.

eslint-plugin-import 도입

저는 일단 기본 설정을 복사해서 가져왔습니다. alias 설정 이후 재설정할 예정입니다.

eslint-plugin-import

eslint-plugin-import/order.md at main · import-js/eslint-plugin-import

[ESLint] imports/exports 구문의 순서 자동 정렬하기

[Error] React must be in scope when using JSX 에러 해결

  • import React from ‘react’ 를 하면 되긴 하지만, 번거롭습니다.
  • JSX tranform을 사용해서 JSX 구문을 정규 Javascript 문으로 바꾸는 과정이 필요한데요, Next.js도 동일합니다.
  • React 17부터는 Babel JSX transform 에 변화가 생겨서 이제는 React를 import 하지 않아도 JSX 구문을 사용할 수 있다고 합니다. 그러니 이 룰을 끄도록 하겠습니다.
  • 마침 공식문서에 eslint-plugin-react 를 사용하는 경우, 관련 룰을 끄면 된다고 친절히 안내가 되어 있군요.

Introducing the New JSX Transform - React Blog

Airbnb 룰 중에서, 당장은 필요하지 않은 기능 끄기

이제는 어느 정도 eslint 설정이 완료된 듯 합니다.

// .eslintrc.json
{
  "env": {
    "browser": true,
    "es2021": true,
    "node": true
  },
  "extends": ["next/core-web-vitals", "airbnb", "airbnb/hooks", "prettier"],
  "parser": "@typescript-eslint/parser",
  "plugins": ["@typescript-eslint", "import"],
  "root": true,
  "overrides": [
    {
      "files": ["*.ts", "*.tsx"],
      "parserOptions": {
        "project": ["./tsconfig.json"]
      }
    }
  ],
  "rules": {
    "react/jsx-filename-extension": [1, { "extensions": [".tsx"] }],
    "sort-imports": [
      "error",
      {
        "ignoreCase": false,
        "ignoreDeclarationSort": false,
        "ignoreMemberSort": false,
        "memberSyntaxSortOrder": ["none", "all", "multiple", "single"],
        "allowSeparatedGroups": false
      }
    ],
    "import/extensions": ["error", "never", { "svg": "always" }],
    "react/jsx-uses-react": "off",
    "react/react-in-jsx-scope": "off",
    "no-unused-vars": "off",
    "@typescript-eslint/no-unused-vars": "error",
    "react/prop-types": "off",
    "react/require-default-props": "off",
    "react/no-unused-prop-types": "off",
    "import/order": [
      "error",
      {
        "groups": [
          "index",
          "sibling",
          "parent",
          "internal",
          "external",
          "builtin",
          "object",
          "type"
        ],
        "alphabetize": {
          "order": "asc"
        }
      }
    ]
  }
}

상태관리 라이브러리 설치

redux-toolkit

다양한 상태관리 툴들이 존재합니다. 그 중에서 상태량이 많고, 상태가 복잡하고 자주 바뀌는 앱에서는 리덕스 툴킷이 강점이 있다하여 redux toolkit을 설치하도록 하겠습니다.

공식문서를 참고하여 설치해 보도록 하겠습니다.

Getting Started | Redux Toolkit

깃 브랜치 전략(Version Control Strategy)

Git-Flow

  • 특정 개인들이 메인 코드에 대한 변경을 승인할 수 있는 개발 모델
  • 과거에는 지배적으로 사용되었던 깃 전략, 그렇지만 지금은 Trunk-based development 가 지배적으로 사용되고 있음.
  • 개인 프로젝트에서는 main-development-feature의 간소화된 브랜치 운용을 진행할 예정

Trunk-based development 란?

Trunk-based Development | Atlassian

  • core “trunk” 또는 메인 브랜치에 대해서 작은, 잦은 변경이 이루어지는 버전 컨트롤 관리 방법

  • CI/CD 를 좀 더 수월하게 할 수 있음.

  • 잦은 업데이트를 용이하게 함

  • 모든 개발자들이 메인 코드에 대한 접근방식이 가능함. 빠른 CI/CD 를 가능하게 함.

  • CI/CD가 요구됨

  • Gitflow는 특정 기능이 완성되기까지 규모가 큰 브랜치가 지속적으로 남아있는 특징. 이러한 특징은 협업시에, 기능 브랜치를 병합할 때 컨플릭트 규모도 커질 수 있어서 리스크가 크다.

  • Gitflow의 경우에는 몇 개의 primary branch들이 있는데,

    • development

    • hotfixes

    • features

    • release

      등이 그것들입니다. 그런데 각 primary branch마다 커밋을 병합하는 전략이 다르기에, 복잡하며, 팀에서 리뷰할 때 추가적인 계획이 필요합니다.

  • Trunk-based development는 fix와 release에 대한 base 브랜치를 main으로 하기에, 병합 절차가 간소합니다. main 브랜치는 항상 안정적이고, 이슈가 없으며, 항상 배포가 가능한 상태임을 전제로 합니다.

  • CI가 요구됩니다. 빌드와 테스트가 자동화 되었음에도 개발자의 규모가 큰 피처 브랜치가 main에 자주자주 병합되지 않는다면, CI의 장점을 살릴 수 없겠죠.

  • 기능 브랜치 규모가 크고, 다른 개발자들이 동시에 같은 코드를 수정할 때 코드 충돌의 가능성과 그 규모가 커집니다. 하지만 Trunk 방식의 개발에서는 빌드가 성공적으로 이루어지는 것이 확실해질 때까지 변화를 병합하지 않고, 커밋의 규모가 작기에, 이런 위험을 적게 만들 수 있습니다.

  • 규모가 작은 커밋들이기에, 코드 리뷰 또한 빠르고, 효율적으로 이루어질 수 있습니다.

  • Trunk based 개발에서 코드리뷰는 비동기적인 작업이 아닌 동기적으로 바로 수행되어야 하는 작업입니다. 이미 몇 번의 자동화된 테스트를 거쳤기 때문에, 리뷰어 또한 이 새로운 코드가 어느 수준의 요구사항을 만족시켰다고 확신할 수 있습니다. 리뷰어는 최적화에 대해서만 집중하면 될 것입니다.

  • 병합된 브랜치는 삭제하기

  • 하루에 한 번은 trunk에 브랜치 병합하기

Commit Convention

  • 브랜치명은 feat fix chore 세 가지로 나눠서 구분한다. 맨 끝에는 -#issue번호를 붙인다.

부가적인 사항들

Husky를 통해 자동으로 브랜치 이슈 번호를 커밋 메시지에 prepend하기

Git - githooks Documentation

//https://typicode.github.io/husky/#/?id=features
npx husky-init && yarn              # Yarn 1

Git Hook 은 깃의 라이프사이클에서 특정 이벤트가 실행될 시에 발동되도록 설정한 여러 동작들을 정의한 스크립트(프로그램)입니다. 사용자는 git 디렉토리 하위의 /hooks 디렉토리 내부, 또는 git config 를 통해서 별도로 지정한 경로에 깃의 특정 순간에 발동시킬 동작을 정의해놓을 수 있습니다.

재미있는 점은 기본적으로 깃이 hook을 호출하기 전에, working directory 가 변경된다는 점인데요, bare repository 내부의 깃 디렉토리 또는 bare repository 가 아닌 working tree의 루트경로 중 하나로 변경이 됩니다.

예외적으로 push 과정에서 트리거되는 훅들(pre-receive, update, post-receive, post-update, push-to-checkout )은 항상 bare repository의 git 디렉토리에서 시행이 됩니다.

수많은 hook들 중에서 지금 우리가 1차적으로 관심이 있는 것은 pre-commit, commit-msg 이라고 하는 녀석입니다.

저는 이걸 처음하기에, 관련 블로그를 검색해서 도움을 받았습니다. linux 구문도 조금 공부를 하게 되었네요.

Automatically prefix JIRA issue numbers to Git commit messages

Bash test: what does "=~" do?

느낀점

Airbnb 룰을 적용하면서 기존에 화살표 함수로 컴포넌트를 정의하던 습관에 대한 의문점이 생겼다.

Why is arrow syntax preferred over function declaration for functional React components?

위 스택오버플로우에서도 사람들마다 나름의 이유를 들며 어느 한 쪽이 더 좋다고 주장하지만, 결국에는 ‘취향차이’로 결론이 난 듯하다.

내 경험상, 화살표 함수로 컴포넌트를 정의해 사용하면 컴포넌트 로직 자체는 매우 간결해지는 느낌인데, 여러 함수들이 추가될수록 어떤 것이 컴포넌트 정의부이고, 어느 것이 기능함수인지 구분하는 것이 헷갈릴 때도 있긴 했다.

내 코드의 히스토리를 모르는 아주 낯선이가 처음 내 코드를 볼 때 어느 편이 더 좋겠냐고 하면 글쎄… 답하기가 어렵다.

이번 프로젝트에서는 컴포넌트정의는 function 키워드로 진행해보려 한다.

profile
안녕하세요 개발자 윤승록입니다. 내 성장을 가시적으로 기록하기 위해 블로그를 운영중입니다.

0개의 댓글