Logo

코드 포맷팅은 그냥 Prettier에게 맡기세요

자바스크립트 개발자들 간에 선호하는 코딩 스타일이 다를 수 있죠? 예를 들어, 개발자 A는 문자열을 쌍따옴표(")로 감싸줘야 한다고 주장하는 반면에, 개발자 B는 홑따옴표(')를 사용해야 된다고 주장합니다. 이러한 두 개발자가 한 팀에서 일하면 코드 리뷰 중에 이러한 사소한 코딩 스타일 차이로 키보드 배틀이 일어나는 걸 보게 되죠… 😅

그런데 대게 이런 코딩 스타일에 대한 논쟁은 정답이 없을 분더러, 괜히 소모적인 자존심 싸움으로 번지기 쉬워서 팀워크와 생산성에 나쁜 영향을 줄 수 있습니다. 이번 글에서는 협업 프로젝트에서 이러한 포맷팅 고민을 해결해주는 편리한 개발 도구인 Prettier에 대해서 소개해드리겠습니다.

코드 포맷터 Prettier

코드 포맷터(Code Formatter)란 개발자가 작성한 코드를 정해진 코딩 스타일을 따르도록 자동으로 변환해주는 도구를 말합니다. Prettier는 이러한 코드 포맷터 중에서도 최근에 가장 인기를 많이 얻어 거의 표준이 되고 가고 있는 자바스크립트 라이브러리 입니다. 쟁쟁한 오픈 소스 프로젝트들과 수많은 기업들이 Prettier를 정식 코드 포맷터를 채택해서 사용하고 있습니다. (Facebook, React, Jest, Yarn, Babel, Webpack, Dropbox, Storybook, Paypal, MongoDB, Salesforce, …)

Prettier가 많은 개발자들에게서 급속히 사랑받게 된 이유는 기존 코드 포맷터와 달리 설정 여지가 거의 없다는 것입니다. 다시 말해서 Prettier에서 디폴트로 정해놓은 코딩 스타일에서 크게 벗어나기가 어렵다는 얘기입니다. 이 말은 일단 Prettier를 쓰기 시작하면 더 이상 코딩 스타일에 대해서 팀원 간에 왈가왈부할 여지가 없다는 것입니다.

그래서 처음에 Prettier를 접했을 때는 Prettier에서 강요하는 코딩 스타일이 불편하게 느껴질 수도 있습니다. 하지만 Prettier에서 정해놓은 코딩 스타일들은 오랜시간 개발자 커뮤니티의 의견이 수렴되어 결정이 된 것이기 때문에 대부분 타당한 경우가 많습니다.

Prettier의 또 다른 차별점은 단순히 개발자가 작성한 코드를 수정해주는 게 아니라 구문 분석 후에 완전히 재작성을 해준다는 것입니다. 따라서 변환된 코드가 원래 코드의 동작이 정확히 일치하는 것을 항상 보장해주면 성능도 매우 뛰어납니다.

Prettier 라이브러리 설치

Prettier 라이브러리는 npm 공개 저장소에 prettier라는 이름의 패키지로 올라와 있습니다. 따라서 npm 패키지 매지저를 통해서 어떤 자바스크립트 프로젝트에서도 쉽게 설치해서 사용해볼 수 있습니다.

$ npm i -D prettier

Prettier는 애플리케이션 실행 시점에는 필요가 없기 때문에 -D 옵션을 통해 개발 의존성으로 설치해주세요.

CLI 도구로 사용하기

Prettier가 어떻게 작동하는지 직관적으로 이해하기 위해서 먼저 CLI 도구를 간단히 돌려보겠습니다.

일단 index.js 파일을 하나에 포맷팅이 엉망인 자바스크립트 코드를 작성하겠습니다.

index.js
function HelloWorld({
  greeting = "hello",
  greeted = '"World"',
  silent = false,
  onMouseOver,
}) {
  if (!greeting) {
    return null;
  }

  // TODO: Don't use random in render
  let num = Math.floor(Math.random() * 1e7)
    .toString()
    .replace(/\.\d+/gi, "");

  return (
    <div
      className="HelloWorld"
      title={`You are visitor number ${num}`}
      onMouseOver={onMouseOver}
    >
      <strong>
        {greeting.slice(0, 1).toUpperCase() + greeting.slice(1).toLowerCase()}
      </strong>
      {greeting.endsWith(",") ? (
        " "
      ) : (
        <span style={{ color: "grey" }}>", "</span>
      )}
      <em>{greeted}</em>
      {silent ? "." : "!"}
    </div>
  );
}

그리고 터미널에 npx prettier "index.js" 커맨드를 실행하면 위 코드가 포맷팅되어 출력이됩니다.

npx나 npm 명령어에 대한 자세한 설명은 관련 포스팅를 참고 바랍니다.

$ npx prettier "index.js"
function HelloWorld({
  greeting = "hello",
  greeted = '"World"',
  silent = false,
  onMouseOver
}) {
  if (!greeting) {
    return null;
  }

  // TODO: Don't use random in render
  let num = Math.floor(Math.random() * 1e7)
    .toString()
    .replace(/\.\d+/gi, "");

  return (
    <div
      className="HelloWorld"
      title={`You are visitor number ${num}`}
      onMouseOver={onMouseOver}
    >
      <strong>
        {greeting.slice(0, 1).toUpperCase() + greeting.slice(1).toLowerCase()}
      </strong>
      {greeting.endsWith(",") ? (
        " "
      ) : (
        <span style={{ color: "grey" }}>", "</span>
      )}
      <em>{greeted}</em>
      {silent ? "." : "!"}
    </div>
  );
}

다음과 같이 --write 옵션으로 위 커맨드를 실행하면 index.js 파일의 내용이 포맷팅된 코드로 바로 대체됩니다.

$ npx prettier --write "index.js"
index.js
function HelloWorld({
  greeting = "hello",
  greeted = '"World"',
  silent = false,
  onMouseOver,
}) {
  if (!greeting) {
    return null;
  }

  // TODO: Don't use random in render
  let num = Math.floor(Math.random() * 1e7)
    .toString()
    .replace(/\.\d+/gi, "");

  return (
    <div
      className="HelloWorld"
      title={`You are visitor number ${num}`}
      onMouseOver={onMouseOver}
    >
      <strong>
        {greeting.slice(0, 1).toUpperCase() + greeting.slice(1).toLowerCase()}
      </strong>
      {greeting.endsWith(",") ? (
        " "
      ) : (
        <span style={{ color: "grey" }}>", "</span>
      )}
      <em>{greeted}</em>
      {silent ? "." : "!"}
    </div>
  );
}

이것이 Prettier가 동작하는 기본적인 방식입니다. 정말 간단하죠? 우리가 소스 코드를 건내주면 Prettier는 코드를 포맷팅해서 돌려줍니다.

ES Lint와 통합하기

실제 프로젝트에서는 Prettier는 단독 CLI 도구가 아닌 일반적으로 ESLint와 같은 린터(Linter)와 통합(integration)해서 사용하는 경우가 많습니다.

ESLint와 통합을 위해서는 2개의 npm 패키지를 추가로 설치해야합니다.

$ npm i -D eslint-config-prettier eslint-plugin-prettier

마지막으로 해당 프로젝트의 .eslintrc.js.eslintrc.json과 같은 ESLint의 설정 파일을 열어서 다음 설정을 추가해줍니다.

.eslintrc.json
{
  "extends": ["plugin:prettier/recommended"]
}

기존에 extends 옵션에 다른 값들이 있는 경우, 기존 설정보다 우선하려면 배열 내에 맨 뒤에 위치시키야 함을 주의 바랍니다.

프로젝트에 ESLint가 셋업되어 있지 않거나, ESLint가 생소하신 분들은 먼저 관련 글을 보시고 돌아시면 도움이 될 것 같습니다.

CI와 통합하기

Prettier와 같은 자동 포맷팅 도구는 CI(Continuous Integration, 지속 통합) 과정의 일부로 통합하기도 하는데요. CI에서 Prettier를 실행하면 포맷팅이 적절히 되지 않은 코드가 코드 저장소의 main 또는 master 브랜치에 머지(merge)되는 것을 효과적으로 예방할 수 있기 때문입니다.

이 부분에 대해서는 별도의 글에서 GitHub의 CI 서비스인 GitHub Actions를 사용하여 자바스크립트 프로젝트에서 CI를 구성하는 방법에 대해서 다루고 있으니 참고 바랍니다.

포맷팅 예외

Prettier로 프로젝트 전체를 포맷팅을 할 때, .prettierignore 설정 파일을 생성하면 예외 시키고 싶은 파일이나 디렉터리를 지정할 수 있습니다. 예를 들어, node_modules/ 디렉터리의 경우, 외부 라이브러리의 소스 코드가 위치하고 있기 때문에 포맷팅을 할 필요가 없습니다. 또한 package-lock.json 파일도 NPM으로 패키지를 설치할 때 자동으로 업데이트는 되는 파일이므로 굳이 포맷팅을 할 이유가 없습니다.

.prettierignore
node_modules/
package-lock.json

이렇게 두 줄을 .prettierignore 설정 파일에 추가하면 Prettier는 포맷팅할 때 지정된 디렉터리와 파일을 무시하게 됩니다.

코드 편집기

코드 포맷팅이 필요할 때 마다 매번 터미널에 커맨드를 날리려면 매우 번거롭겠죠? 걱정마세요! 다행히도 대부분의 코드 편집기에서는 Prettier과의 상당히 매끄러운 통합을 지원하고 있습니다.

따라서 본인이 사용하는 편집기에서 제공하는 Prettier 플러그인 또는 익스텐션을 찾아서 설치만 해주시면 됩니다.

이러한 Prettier의 편집기 통합을 활용하면 코드를 작성하면서 실시간으로 포맷팅이 되기 때문에 정말 편리합니다. 👍

마치면서

지금까지 코드 포맷터 Prettier를 사용하는 방법에 대해서 간단하게 살펴보았습니다. 참고로 Prettier는 자바스크립트 뿐만 아니라 타입스크립트, CSS, HTML, JSON, YAML, Markdown 등을 다양한 언어를 지원하고 있습니다.

이제 우리 그만 싸우고 코드 포맷팅은 그냥 Prettier에게 맡기면 어떨까요? 코딩 포맷팅 때문에 싸우기엔 프로젝트의 일정은 빠뜻하고 기능 구현하기에도 너무 빠쁘잖아요 😁