How-to

개츠비(Gatsby) 프로젝트에 타입스크립트(TypeScript) 세팅하기

타입스크립트(TypeScript)를 사용할 수 있도록 개츠비(Gatsby) 프로젝트를 설정했다. 바벨(Babel)로 컴파일하도록 했고, 타입 검사, 품질 검사, 형식 자동변환을 위해서 각각 타입스크립트 컴파일러, 이에스린트(ESLint), 프리티어(Prettier)를 사용했다.

개츠비(Gatsby) 프로젝트에 타입스크립트(TypeScript) 세팅하기

남자가 헤드폰을 끼고 컴퓨터로 일하는 뒷모습

들어가며

개츠비(Gatsby) 프로젝트, 바로 지금 보고 있는 이 블로그에 타입스크립트(TypeScript)를 도입하기로 했다. 이 글은 개츠비 프로젝트를 타입스크립트로 작성하고 실행할 수 있는 환경을 만들기 위해 단계별로 수행한 일들의 기록이다. 타입스크립트 컴파일, 타입 검사, 그리고 린팅/포맷팅과 에디터 설정이 포함되었다. 개츠비 프로젝트에서는 공식 플러그인을 이용해서 타입스크립트를 사용할 수 있는데, 주의할 점은 타입스크립트 공식 컴파일러가 아니라 바벨로 트랜스파일한다는 것이다. 타입 검사를 할 수 없고 언어 기능 몇 가지가 지원되지 않는 등 제한이 있지만 이 프로젝트에는 아무런 지장이 없을 것으로 보고 진행했다.

트랜스파일(Transpile)

개츠비 프로젝트에 타입스크립트를 도입하는 것은 생각보다 간단했다. 개츠비의 공식 플러그인 중 하나인 gatsby-plugin-typescript를 설정하고, 프로젝트 루트에 tsconfig.json 파일을 생성하면 일단 자바스크립트 파일을 타입스크립트 파일(.ts, .tsx)로 변환하기 시작할 수 있다.

npm i gatsby-plugin-typescript
/gatsby-config.js
plugins: [
  'gatsby-plugin-typescript',
  // …
/tsconfig.json
{
  "compilerOptions": {
    "target": "esnext",
    "module": "commonjs",
    "jsx": "preserve",
    "lib": [
      "dom",
      "esnext"
    ],
    "strict": true,
    "isolatedModules": true,
    "esModuleInterop": true,
    "allowJs": true
  },
  "include": ["./src/**/*"],
  "exclude": ["node_modules", "public", ".cache"]
}

이것만으로도 타입스크립트 코드를 실행할 수 있는 상태가 되었고, 비주얼 스튜디오 코드(Visual Studio Code)에서는 빨간 줄로 타입 오류도 확인할 수 있었다.

타입 체크

비주얼 스튜디오 코드에서 타입 오류를 바로 확인할 수 있다. 하지만 그 외에도 터미널 명령어로 타입을 검사하고 하고 오류를 뱉는 기능이 필요하다. 타입 오류가 있으면 빌드를 중단하거나 하는 용도로 쓰기 위해서다. 바벨로는 트랜스파일만 하지 타입 검사를 할 수 없으므로 타입스크립트의 공식 컴파일러를 설치해야 했다.

npm i -D typescript

package.json 파일의 scripts 필드에 타입 검사를 실행하는 명령어를 추가해주었다. --noEmit 플래그로 컴파일 출력 없이 오류만 확인할 수 있도록 했다.

/package.json
"scripts": {
  "typecheck": "tsc --noEmit",
  "prebuild": "npm run typecheck",

린트(Lint) & 포맷(Format)

다음으로는 린트 기능과 코드 자동 포맷 기능을 설정할 차례다. 코드 포매터로는 프리티어(Prettier)를 사용하기로 했다. 타입스크립트 프로젝트를 새로 만들 때면 하게 되는 고민인데, 이에스린트(ESLint)티에스린트(TSLint) 두 개의 린터 선택지가 있다. 티에스린트가 사실상 표준적인 린터였지만 2019년 내로 지원을 종료하고, 그 역할은 이에스린트로 이양하기로 결정이 내려졌었다. 몇 개월 전에 새 프로젝트를 시작할 때, 이 소식을 보고 바로 이에스린트를 선택했었는데 그닥 좋은 경험은 아니었다. 아직 구현이 안 된 건지 문서가 없는 건지 모르겠지만 원하는 기능을 찾기가 어려웠고, 전반적으로 무르익지 않은 느낌이었다.

린팅이나 코드 포맷과 관련된 도구는 프로젝트의 본질에 비하면 사실 하찮은 잡일에 불과하다. 하지만 이런 도구들은 새 프로젝트를 설정할 때마다 항상 발목을 잡고 늘어져 그 중요도에 비해서 우리에게 주는 스트레스가 크다. 자주 하는 작업이 아니라 잊을 때가 되면 한번씩 하는 식이라 더 그런 것 같다. 린터를 설정하면 프리티어와 충돌이 일어나고, 그 뒤에는 IDE나 에디터가 문제를 일으키는 식이다. 린터-프리티어-에디터 이 셋을 달랠 생각을 하면 머리가 아프다.

어쨌든, 마지막으로 사용해 본 지 몇 개월이나 지났으니 다시 이에스린트를 쓰기로 했다.

개츠비(Gatsby) 프로젝트에 이에스린트(ESLint) 사용자 설정 추가하기

개츠비 프로젝트는 기본적으로 이에스린트 설정을 내장하고 있다. 문서에는 웬만한 케이스는 기본 설정으로 커버가 가능하다고 되어있고, 실제로도 그랬지만 타입스크립트를 위해 사용자 설정을 추가해야만 하는 상황이 되었다. 사용자 설정을 추가하려면 먼저 개츠비의 기본 설정을 직접 재현해 줄 필요가 있다. 먼저 개츠비의 「이에스린트 사용하기(Using ESLint)」 문서를 참고해서 관련 패키지들을 설치하고, 프로젝트 루트에 .eslintrc.js 파일을 만들었다.

npm i -D eslint eslint-plugin-react-hooks eslint-config-react-app
/.eslintrc.js
module.exports = {
  globals: {
    __PATH_PREFIX__: true,
  },
  extends: 'react-app',
}

이에스린트(ESLint) 설정하기

이에스린트(ESLint) 관련 패키지 설치하기

이제 본격적으로 타입스크립트를 위한 설정을 추가할 수 있는 상태가 되었다. 먼저 패키지들을 설치해주었다.

npm i -D eslint @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint-plugin-react eslint-config-prettier eslint-plugin-prettier

위의 명령어에서 앞의 두 패키지, @typescript-esslint/parser@typescript-eslint/eslint-plugin는 이에스린트가 타입스크립트를 지원하도록 하는 역할을 한다. 주의할 점은 이 둘의 버전이 같아야 한다.

뒤의 두 패키지는 이에스린트와 프리티어를 함께 사용할 수 있도록 한다. 린터는 코드의 형식과 품질 두 가지를 모두 검사하는데, 이 중 전자는 프리티어의 역할과 겹치기 때문에 문제가 될 수 있다. eslint-config-prettier는 프리티어의 규칙과 충돌할 수 있는 이에스린트 규칙을 끄는 일을 한다. 예를 들면 프리티어는 세미콜론을 없애고 있는데 이에스린트는 세미콜론이 없다고 에러를 보여주는 상황을 피할 수 있게 해준다. eslint-plugin-prettier는 프리티어 규칙을 이에스린트에서 갖다 쓰고 이슈를 보고하도록 만들어준다.

이에스린트(ESLint) 설정 파일 만들기

앞서 만들었던 .eslintrc.js 파일에 아래와 같이 설정을 추가해주었다.

/.eslintrc.js
module.exports = {
  globals: {
    __PATH_PREFIX__: true,
  },
  parser: '@typescript-eslint/parser',
  extends: [
    'eslint:recommended',
    'react-app',
    'plugin:@typescript-eslint/recommended',
    'plugin:react/recommended',
    'plugin:prettier/recommended',
    'prettier',
    'prettier/@typescript-eslint',
    'prettier/react',
  ],
  settings: {
    react: {
      version: 'detect',
    },
  },
  env: {
    browser: true,
    node: true,
    es6: true,
  },
  plugins: ['@typescript-eslint', 'prettier', 'react'],
  parserOptions: {
    ecmaFeatures: {
      jsx: true,
    },
    ecmaVersion: 2018,
    sourceType: 'module',
  },
  rules: {
    'react/prop-types': 'off'
  },
  overrides: [],
}

비주얼 스튜디오 코드(Visual Studio Code) 설정하기

이에스린트 설정은 다 됐는데 비주얼 스튜디오 코드에 아무런 신호가 없어 한참 헤맨 적이 있었다. 어떤 종류의 파일을 이에스린트로 검사할지를 에디터 설정 파일의 eslint.validate 필드에 명시해줘야 한다. 아무 설정이 없으면 디폴트로 자바스크립트(JavaScript) 파일을 검사하게 되는데, 타입스크립트 파일을 검사해야 하므로 아래와 같이 명시해주었다.

settings.json
"eslint.validate": [
  "typescript",
  "typescriptreact",
  "javascript",
  "javascriptreact"
],

프리 커밋 훅(Pre-commit Hook)

코드 형식을 자동으로 편집할 수 있는 상태가 되었지만 이 형식을 강제할 수 없다면 사실 그동안 들인 노력이 별 의미가 없다. 허스키(Husky)린트-스테이지드(lint-staged)를 이용해서 커밋 직전에 프리티어가 실행되도록 할 수 있다. 엠알엠(Mrm)을 이용해서 두 패키지를 설치하고 기본 설정까지 생성할 수 있다.

npx mrm lint-staged

위 명령어 실행의 결과로 package.json 파일에 아래와 같이 필드가 만들어졌다.

/package.json
"husky": {
    "hooks": {
      "pre-commit": "lint-staged"
    }
  },
"lint-staged": {
  "*.{js,ts,tsx}": [
    "eslint --fix",
    "git add"
  ]
}

지금까지 허스키와 린트-스테이지드를 설치해서 커밋 훅이 한 번에 성공한 적이 없다. 나만 그런 건진 모르곘는데 언제나 훅이 설정되지 않아서 허스키를 삭제하고 .git/hooks/pre-commit 파일을 지워야 했다. 그리고 나서 허스키를 다시 설치하면 프리-커밋 훅이 제대로 설정되어 실행되는 것을 확인할 수 있다.

$ git commit -m "style: add unnecessary semicolon"
husky > pre-commit (node v10.16.3)
  ↓ Stashing changes... [skipped]
    → No partially staged files found...
  ✔ Running tasks...
[feature/ok 13fa6aa] style: add unnecessary semicolon

나가는 글

이것으로 기본적인 설정이 완료되었다. 정리해보면 첫째, 타입스크립트 코드를 바벨로 트랜스파일하도록 헀다. 둘째, 타입 검사를 할 수 없는 바벨을 보완하기 위해 typescript로 타입 검사를 하는 스크립트를 추가헀다. 셋째, 이에스린트와 프리티어를 설정헀고, 넷째, 비주얼 스튜디오 코드에 설정을 추가했다. 마지막으로 허스키와 린트-스테이지드를 이용해서 커밋 직전에 프리티어가 실행되도록 했다. 이번에 다시 느낀 건데 린터 관련 설정은 불필요하게 복잡하고 많은 시간을 잡아먹는다.

이제 자바스크립트로 작성된 코드를 타입스크립트로 바꾸는 일이 남았다.

Join the Newsletter

I will send you only good things.

Your thoughts? Please leave a reply.