코딩 플레이그라운드 만들며 맛보는 요즘 FE 개발 환경 Part 1

🗓 2021-02-15

(2022-03-04 업데이트: webpack-dev-server, babel, jest 관련 설정 코드가 수정됐습니다.)

개발을 하다 보면 특정 환경에서 빠르게 코드를 작성하고 그 결과를 확인해보고 싶을 때가 있어요. 라이브러리나 프레임웍 혹은 언어를 공부할 때나 아이디어를 빠르게 실험하거나 프로토타입 해보고 싶을 때 그렇지요. 바닐라 자바스크립트로 충분한 환경이라면 디렉터리 하나 만들고 js 파일 하나 html 파일 하나 만들어서 에디터를 열고 브라우저를 열어서 html 파일을 불러오는 것까지 하면 기본적인 준비가 끝나요. 근데요. 이런 바닐라 자바스크립트 환경을 만드는 것조차도 사실 귀찮을 때가 있어요. 이런 기본 환경도 귀찮은데 실무의 복잡한 환경은 어떻겠어요. 매번 ESlint 넣고 웹팩 넣고 바벨 넣고 하기엔 너무 귀찮습니다. 그래서 지금 필요한 환경과 비슷한 환경의 프로젝트에서 곁다리로 파일을 만들어 간이로 지저분하게 빌려 쓰기도 하죠.

이런 니즈에 대한 응답으로 code sandbox 같은 서비스들도 나왔지만 우리가 익숙한 에디터에서 개발할 수는 없습니다. 에디터에 민감한 분들에겐 큰 단점이죠. 그 안에서 뭔가를 입력하거나 편집할 때는 조금 불편합니다.

저는 이런 불편이 꽤 심했어요. yeoman 같은 스캐폴딩 툴도 있지만 프로젝트를 추가로 매번 만들어야 한다는 것이 귀찮았었고 갯수가 많아지면 관리도 힘들었어요. 중복되서 설치되는 node_modules 용량도 무시못하구요. 아무튼 노드 프로젝트를 어떤 이유로라도 만들다보면 관리가 힘들어졌습니다.

어느 날 문득 러나(lerna)를 공부하다가 떠올랐어요. 일종의 개발 플레이그라운드를 각 환경별로 만들어서 쉽게 실험 환경을 꺼내 쓸 수 있게 하면 어떨까 생각해 봤어요. 여기엔 요즘 많이 사용하는 도구인 러나가 도움이 될 것 같았어요. 그래서 바로 시도해봤죠. 그리고 꽤 만족스러웠습니다. 지금 이 글은 그렇게 개인플레이그라운드를 만들어 사용한 지 한 2개월 정도 지난 시점입니다.

이 글은 개인 개발 플레이그라운드를 어떻게 구축했는지 과정과 도구들을 설명해 드릴 것이고요. 그러면서 자연스럽게 요즘 FE 개발 환경에 대한 소개도 하겠습니다. 글과 함께 핸즈온으로 진행하면 좋을 것 같고요. 다 읽으시면 요즘 FE 개발의 기반 환경들을 어느 정도 맛보실 거예요. 급하신 분들을 위해 파트2 끝부분에 리포 링크를 남기겠습니다. 리포에서 바로 클론해서 사용하시면 됩니다. 프로젝트명은 해처리(hatchery)라고 정했어요. 네 저그의 해처리요. 그럴싸하죠?

제가 자주 필요하는 개발 환경 셋은 총 세 가지 정도입니다.

  1. 기본 환경: webpack, babel, eslint, prettier, jest, testing-library
  2. 타입 스크립트 개발 환경: (기본 환경), typescript
  3. 리액트 + 타입 스크립트 개발 환경: (타입 스크립트 환경), react, styled-component

리스트에서 보시면 아시겠지만 각 개발 환경이 독립적이지 않고 중복돼요. 여기에 vue 환경을 만들더라도 타입 스크립트 개발 환경과 중복될 거예요. 중복되기 때문에 디펜던시 모듈들 즉 node_modules의 내용이 중복될수록 디스크 용량이 부담스러워요.

Pasted Graphic

그래서 디펜던시 모듈 정확히는 devDependency 모듈들을 중복 설치하지 않고 공유해서 사용하게 만들 건데요. 이건 러나가 쉽게 해줄 거예요. 우린 배포할 일이 없기 때문에 모두 데브디펜던시로 설치합니다. 그래서 모든 디펜던시가 공유되게 할거에요. 좋죠?

러나(lerna)?

러나를 자세히 다루려는 글은 아니지만 간단한 사용법들은 알려드리면서 진행할게요. 우선 러나가 무엇인지는 간단하게 소개하자면 한 개의 git 리포지토리에서 여러 개의 독립된 프로젝트들을 관리할 수 있게 해주는 도구라고 생각하시면 됩니다. 보통은 NPM 배포 단위입니다. 즉 한 개의 리포에서 여러 개의 NPM 프로젝트들을 관리할 수 있는 것이죠. 한 개의 큰 프로젝트를 책임에 따라 잘 분리해서 독립된 작은 모듈 프로젝트 여러 개로 관리할 때도 사용합니다. 모듈을 별도의 프로젝트로 분리하게 되면 디렉터리나 파일로 모듈을 구분했을 때에 비해 많은 장점이 있지만 불편한 점도 생기는데 이 불편한 점을 러나가 거의 없애준다고 보시면 됩니다.

아니 플레이그라운드를 만드는데 러나가 왜 필요할까요? 위에서 말씀드렸다시피 저는 총 세 가지 개발 환경이 필요해요 아니 나중엔 더 필요할 수도 있겠죠. 이런 개발 환경, 즉 프로젝트 여러 개를 하나의 리포에서 관리하는 데는 러나만 한 게 없고요 특히나 디펜더시를 공유하는 부분에서는 러나가 특약 처방이었어요. 개발 환경 3개 이상을 관리하면서 디펜더시들을 한곳에서 나눠쓰게 하기도 쉬워요. 관리뿐 아니라 디스크 용량 면에서 좋겠죠? 그래서 러나를 사용합니다. 개발 환경을 분리할 용도로 러나가 만들어진 건 아니지만 뭐 어때요 도구는 도구일 뿐 …

기본적인 플레이그라운드 환경 만들기

실제 제가 작업했던 순서와는 차이가 있지만 편의상 러나부터 설치하겠습니다. npm init 으로 이미 프로젝트는 만들어진 상태라고 간주할게요.

러나를 설치합니다.

npm i -D lerna

이 프로젝트를 러나가 관리하는 프로젝트로 만듭니다.

npx lerna init --independent

independent 옵션은 내부 패키지(여기서는 각 개발 환경)들을 독립적으로, 개별적인 버전으로 관리하겠다는 옵션이에요. 지금 우린 그러는 게 좋겠죠? init 커맨드가 실행되면 lerna.json 파일하고 packages라는 디렉토리가 생겨요. 기본적인 러나 환경이 만들어졌다고 보시면 됩니다.

자 이제 우리가 할 것은 개발 환경 중 첫 단계 기본 자바스크립트 개발 환경을 만드는 거예요.

npx lerna create pgjs

플레이그라운드니까 각 환경 앞에 프리픽스로 pg를 붙일거에요 그래서 pgjs 이렇게 만들었어요. 실행하면 내부에서 npm init 이 실행되요 그래서 만들 프로젝트 정보를 또 입력해야해요. 이 패키지는 플레이그라운드라는 프로젝트안에서 관리다는 서브 프로젝트인거죠. 적절하게 정보를 입력해서 프로젝트를 생성하면 pacakges 디렉토리안에 패키지가 생성되요.

기본 템플릿에 해당하는 내용들이 미리 만들어져있습니다만 저는 이 기본 제공 디렉토리 구조가 마음에 들지 않아 패키지의 디폴트 템플릿을 변경하는 방법을 찾아봤지만 아직 없는 것 같습니다. 필요한 사람들이 저 말고도 있는 것 같아서 에이 이번 기회에 기여나 한번 해볼까 했지만 늘 그렇듯 말뿐이었죠.

디렉토리 구조는 취향일 수 있겠지만 가능하면 지금은 저하고 맞춰주세요. __tests__ 폴더를 지웠구요. lib 디렉토리를 src로 바꿨어요. 그리고 src 안에 pgjs.js파일이 있는데 index.js로 바꿨어요.

이렇게 js 개발환경의 기초공사가 끝났습니다.

ESLint

제일 먼저 ESLint는 설치합니다. ESlint는 이제 거의 표준이라 대부분 사용하실 거예요. 코드를 잘 짜고 있나 감시하면서 도와주는 잔소리꾼이죠. packages/pgjs 디렉터리로 이동해서 npm i -D eslint 이렇게 npm을 이용해서 설치할 수 있지만 우린 러나로 관리하니까 러나를 이용해볼게요

npx lerna add eslint packages/pgjs --dev

러나의 add 커맨드를 사용해서 디펜더시를 설치하면 장점이 몇 가지가 있는데 그중 하나가 다중 패키지에 디펜더시를 한 번에 설치할 수 있다는 점이에요. 하지만 지금은 딱히 장점은 없겠네요. 패키지 입장에서는 npm을 이용해서 설치한 것과 크게 다를 건 없습니다. 그리고 모든 디펜던시는 devDependencies로 설치합니다. 그 이유는 파트2에서 알 수 있습니다.

packages/pgjs 로 이동합니다. 그리고 ESlint 기본 설정파일을 만듭니다.

npx eslint --init

선택할게 여러개 나오는데 우선 아래와 같이 선택해주세요.

How would you like to use ESLint? · problems
What type of modules does your project use? · esm
Which framework does your project use? · none
Does your project use TypeScript? · No 
Where does your code run? · browser
What format do you want your config file to be in? · JavaScript

위 작업을 통해 packages/pgjs/.eslintrc.js설정파일이 생성되요. 제대로 설치되었는지 확인해 볼까요?

npx eslint src

'module' is not defined라는 에러가 출력되면 성공한 거예요. 에러는 예상했던 에러입니다. 나중에 수정할거에요. 일단 넘어갑니다.

프리티어(Prettier)

다음은 프리티어를 설치할게요. 프리티어를 아직 안 쓰시는 분은 계시다면 꼭 쓰세요. 두 번 쓰세요. 이제 스타일 따위 변경하느라고 시간 낭비하지 맙시다. 특히 코드 리뷰할 때 스타일 관련 이슈는 지겹잖아요? 생산적이지 않아요. 그런 반복되고 단순한 작업은 기계에 양보하세요. 이제 우리가 코드 리뷰에서 볼 수 있는 스타일 관련 코멘트는 “프리티어 세팅 제대로 하셨어요?” 정도입니다. 심지어 파싱 하는 과정에서 오타까지 검수해 주는 보조 효과까지 있어요.

ESLint의 오토 픽스 기능이 프리티어를 대체할 수 있을지는 아직 모르겠어요. 한 1.5년 전에 저장할 때마다 오토 픽스를 적용해 프리티어를 대체할 수 있는지 테스트해봤는데 조금 불편했던 기억이 있어요. 자세한 이유는 기억이 안 나지만 "안되겠다" 했던 기억은 있어요. ESLint의 오토 픽스도 도움이 안 된다는 말이 아니에요. 유용한 기능이고 저도 가끔씩 쓰지만 프리티어의 그것과는 달랐단 말입니다.

npx lerna add prettier packages/pgjs --dev

프리티어 설정은 우선 제가 쓰는 것을 복붙할게요. 프리티어는 우리가 플레이그라운드로 만드는 각 환경 셋에서 동일한 설정을 사용할 것이기 때문에 packages/pgjs 경로가 아니라 플레이그라운드 루트에 설정 파일을 만들 거예요. 프리티어는 굳이 환경마다 다르게 적용할 필요가 없어요.

플레이그라운드 루트에 .prettierrc 파일을 만들어 주세요

{
  "singleQuote": true,
  "printWidth": 100,
  "tabWidth": 2,
  "useTabs": false,
  "semi": true,
  "quoteProps": "as-needed",
  "jsxSingleQuote": false,
  "trailingComma": "es5",
  "arrowParens": "always",
  "endOfLine": "lf",
  "bracketSpacing": true,
  "jsxBracketSameLine": false,
  "requirePragma": false,
  "insertPragma": false,
  "proseWrap": "preserve",
  "vueIndentScriptAndStyle": false
}

각 옵션별 설명은 스키마를 확인하시면 되는데 정말 보기 싫게 만들어져있어요. 그냥 우선 제 설정 쓰시다가 불편한 거 몇 개 수정해서 쓰시면 좋을 것 같아요.

프리티어는 터미널에서도 실행 가능하지만 편하게 사용하려면 에디터나 IDE에 설정해 주셔야 해요. 공식 사이트에 정보를 참조하시면 될 것 같아요. 보통 쉽게 설정할 수 있어요.

제대로 설정이 되었는지 테스트는 packages/pgjs/index.js 파일에서 인덴테이션을 엉망으로 만들고 저장을 해보시면 됩니다. 정상적으로 프리티어가 설정되면 개떡같이 코드를 만들어도 찰떡같이 이쁘게 정리해 줘요. 이제 복붙할때 일일이 코드를 백스페이스, 탭, 스페이스를 이용해서 정리할 필요 없이 그냥 저장만 해주면 알아서 상황에 맞게 정리가 되는 거예요. 생산성 많이 좋아집니다. 객체 리터럴 등의 코드를 대충 만들고 저장할 때 촤자작 정리되는 것을 볼 때면 쾌감까지 느껴집니다.

웹팩(Webpack)

다음은 웹팩입니다. 번들링을 위해서 그리고 빌드에 필요한 도구를 연동하거나 서버를 띄우는데 사용합니다. 웹팩은 진작부터 어떤 프로젝트에서건 항상 설치해야 하는 도구가되었습니다. 자 웹팩을 설치합니다. 어떻게 하는지 아시죠? 웹 팩은 최신 버전을 설치합니다(webpack 5)

npx lerna add webpack packages/pgjs --dev
npx lerna add webpack-cli packages/pgjs --dev
npx lerna add webpack-dev-server@4.0.0-beta.0  packages/pgjs --dev

총 세 개의 디펜더시를 설치해야 해요. webpack-dev-server는 쉽게 프런트 서버를 만들어주는 도구인데 웹팩5를 지원하는 버전인 4.0이 아직 베타버전이에요. 베타 딱지가 조만간 필요 없을 수 있어요. 자 웹 팩을 설치했으니 다음으로 해야 할 일은 뭘까요? 웹 팩 설정 파일 webpack.config.js를 만듭니다. packages/pgjs 경로에 만들어주세요. 설정 파일에 대한 내용을 여기서 일일이 다루진 않을 겁니다. 일단 간단하게 복붙 해주세요.

const path = require('path');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = (env, argv) => {
  let config = {
    entry: ['./src/index.js'],
    output: {
      filename: '[name].js',
      path: path.resolve(__dirname, 'dist'),
    },
    module: {
      rules: [],
    },
    resolve: {
      extensions: ['.ts', '.tsx', '.js', '.json'],
      alias: {
        '@src': path.resolve(__dirname, 'src/'),
      },
    },
    optimization: {
      splitChunks: {
        cacheGroups: {
          commons: {
            test: /[\\/]node_modules[\\/]/,
            name: 'vendors',
            chunks: 'all',
          },
        },
      },
    },
  };

  if (argv.mode === 'development') {
    config = {
      ...config,
      plugins: [
        new CleanWebpackPlugin(),
        new HtmlWebpackPlugin({
          title: 'Development',
          showErrors: true,
        }),
      ],
      devServer: {
        open: {
          app: {
            name: 'Google Chrome', // 플랫폼에 따라 다름, 윈도우에서는 'chrome'
          }
        },
        host: '0.0.0.0',
        client: {
          overlay: {
            warnings: false,
            errors: false,
          },
        }
      },
      devtool: 'eval-cheap-module-source-map',
    };
  }

  return config;
};

설정 파일을 보면 플러그인 두 개를 사용하고 있어요 html-webpack-plugin 하고 clean-webpack-plugin입니다. html-webpack-plugin 프런트 서버에서 사용될 index.html을 만들어주는 플러그인이고요. clean-webpack-plugin는 빌드 디렉터리 지워주는 역할을 합니다. 이것도 설치할게요.

npx lerna add html-webpack-plugin packages/pgjs --dev
npx lerna add clean-webpack-plugin packages/pgjs --dev

복붙한 웹팩 설정은 아주 기본적인 설정이에요. 엔트리 포인트가 무엇이고 청크를 어떻게 나눌 것이며 서버는 어떻게 띄울지에 대한 설정이 들어 있습니다. 설정에 대한 더 자세한 내용은 공식 사이트를 참조하시면 될 것 같아요. 지금은 특별히 만질 것이 없습니다.

우선 서버가 뜨는지 확인해 볼게요. packages/pgjs 경로에서 아래와 같이 입력합니다.

npx webpack serve --mode development

개발 모드로 개발 서버를 띄우겠다는 커맨드입니다. 서버는 브라우저에서 localhost:8080 으로 확인할 수 있는데 지금은 아무것도 안 나오죠? packages/pgjs/index.js파일을 수정해 볼게요. 내용을 다 지우고 얼럿 하나 띄워 볼까요?

alert(OK);

브라우저에서 서버를 열어둔 상태라면 파일을 저장하는 순간 자동으로 리프레시 돼서 얼럿창이 뜰거에요. 얼럿이 정상적으로 뜬다면 웹팩 기본 설정은 끝난 겁니다.

바벨(Babel)

이제 우리들의 막강한 친구인 바벨을 설치합니다. 플레이그라운드의 개발 환경을 바닐라 자바스크립트만 사용해서 필요에 따라 제한된 브라우저만 사용하실 분이시라면 바벨은 설치하지 않아도 될 것 같습니다만 가능하면 실무 환경과 동일한 게 좋기 때문에 바벨은 설치하는 게 좋습니다. 저는 다양한 프레임웍 환경까지 염두 했기 때문에 선택의 여지없이 사용합니다.

프로젝트 루트에서 바벨과 필요한 모듈들을 설치합니다.

npx lerna add @babel/core packages/pgjs  --dev
npx lerna add @babel/preset-env packages/pgjs --dev
npx lerna add core-js packages/pgjs --dev

첫 번째는 바벨 코어 모듈이고 두 번째 세 번째는 브라우저 대응을 위해 설치합니다. 사실 플레이그라운드의 경우 브라우저 대응을 할 필요가 있을까 싶지만 실무의 일부 로직을 확인하려는 경우나 바벨 자체를 테스트하기 위한 용도로 필요하기 때문에 최대한 실무에서 쓰는 환경은 그대로 사용하려고 합니다.

자, 바벨을 설치했으니 설정을 해야겠죠? packages/pgjs.babelrc 파일을 만듭니다.

{
  "presets": [
    [
      "@babel/preset-env",
      {
        "useBuiltIns": "usage",
        "corejs": 3,
        "debug": false
      }
    ]
  ],
  "plugins": [
    ["@babel/plugin-proposal-class-properties", { "loose": true }],
    ["@babel/plugin-proposal-private-methods", { "loose": true }],
    ["@babel/plugin-proposal-private-property-in-object", { "loose": true }]
  ]
}

앗! 설정을 복붙하고 보니 하나를 빼먹었네요. 아직 TC39 stage-3 단계에 있는 클래스 필드를 온전히 쓰기 위해 바벨 플러그인을 하나 설치해야 해요. 자바스크립트(ECMAScript) 는 매해 발전하고 개선되고 있습니다. 지속적으로 관심 갖고 적극 도입하는 것을 권장합니다. stage-3 단계에 있는 스펙은 실무에 적용해도 되는 수준입니다. 이점이 바벨을 사용하는 근본적인 이유기도 하죠 :)

(2022-03-04 업데이트: class-properties ES2022의 스펙으로 결정됨에 따라 최신 preset-env에 포함됐기 때문에 별도로 설치할 필요 없습니다. 아래의 작업은 하지 않으셔도 됩니다.)

npx lerna add @babel/plugin-proposal-class-properties packages/pgjs —dev

바벨 설정도 해야 하지만 바벨을 장점을 온전히 살리려면 브라우저스리스트(Browserslist)설정도 해야 해요. 바벨을 통해 변경되는 코드가 어떤 브라우저들을 지원해야 하는지에 대한 정보라고 생각하시면 됩니다. 설정 내용은 가독성이 좋은 편이라 금방 적응하실 거에요. 더 자세한 내용은 Browserslist 쾌속 가이드를 참고해 주세요.

packages/pgjs/package.json 파일에 browserslist 설정을 추가합니다.

"browserslist": [
    "> 1%",
    "last 2 versions",
    "not ie < 11"
  ]

전 세계 브라우저 사용을 1% 이상의 브라우저들을 지원하며, 최신 버전 두 개까지만 허용하고, IE는 10이하는 지원하지 않겠다는 뜻입니다. 바벨, 정확히는preset-env 가 이 정보를 이용해 빌드 결과물의 내용과 corejs에서 꺼내 쓸 폴리필을 결정합니다.

바벨 cli 도구를 이용해도 터미널에서 독립적으로 빌드를 할 수 있지만 우리는 웹팩을 사용하니까 바벨하고 웹팩을 연동해볼게요.

webpack.config.js 파일을 보면 아래와 같은 부분이 있어요.

module: {
 rules: []
},

저 rules라는 빈 배열에 로더를 이용해서 바벨을 연동합니다. 로더는 웹팩에서 번들링 기능을 확장할 수 있는 일종의 플러그인 혹은 익스텐션이라고 생각하시면 됩니다.

바벨 로더를 설치하고 설정까지 해볼게요.

npx lerna add babel-loader packages/pgjs —dev

설치가 끝나면 webpack.config.js 에 바벨 로더를 추가합니다.

module: {
 rules: [
  {
   test: /\.(ts|js)$/, // 나중에 타입스크립트도 추가할 것이기 때문에 ts 파일도 바벨로 보냅니다.
   exclude: /node_modules/,
   use: {
    loader: 'babel-loader',
   },
      }
   ]
},

바벨이 잘 적용되었는지 확인하는 방법은 packages/pgjs/src/index.js 파일을 아래와 같이 수정한 다음,

class MyClass {
  #pField = 'hello';

  getPField() {
    return this.#pField;
  }
}

console.log(new MyClass().getPField());

서버를 띄워 클래스 필드를 지원하지 않는 브라우저에서 확인하거나. 번들링 된 파일의 코드를 확인하면 됩니다만 번거롭죠? 아마 별문제 없을 겁니다. 빌드 에러가 나지 않았다면 그냥 넘어가도 좋습니다.

아마 에디터에 ESLint가 제대로 설정되어 있다면 ESLint가 packages/pgjs/src/index.js 파일에서 사용한 프라이빗 필드 문법 #를 정상적으로 인식하지 못하는 것을 볼 수 있을 거에요. ESLint가 바벨로 확장된 문법을 몰라서 그러는 건데요. 이 문제는 @babel/eslint-parser를 사용해서 해결할 수 있어요.

npx lerna add @babel/eslint-parser packages/pgjs —dev

우선 설치하구요 .eslintrc.js 상단 에 파서 옵션을 추가합니다.

module.exports = {
  parser: '@babel/eslint-parser', // 추가
  env: {
    browser: true,
    node: true, // 추가

그리고 envnode: true를 추가해서 commonjs모듈 시스템을 이해할 수 있도록 수정합니다. 이거 없으면 설정파일에서 'module' is not defined라는 에러가 뜰 거에요.

제스트(Jest)

저는 유닛 테스트 도구로 모카(mocha)를 시작으로 자스민(jasmine) + 카르마(karma) 조합을 오래 사용하다가 한 1~2년 전부터 제스트로 정착했어요. 셋 다 좋은 도구입니다. 제스트까지 진화한 게 아니에요. 환경에 따라 그리고 테스트를 대하는 개발자의 취향 혹은 철학에 따라 선택하시면 됩니다. 저와 그리고 제가 속한 조직은 검토 끝에 제스트를 선택했습니다.

npx lerna add jest packages/pgjs --dev

제스트를 설치했으면 이번에도 설정을 해야 합니다. JS 기본 환경에서는 특별히 설정할 것도 없습니다. packages/pgjs 경로에 jest.config.js 파일을 만듭니다.

module.exports = {
  testEnvironment: 'jsdom',
  moduleFileExtensions: ['js', 'json'],
  moduleNameMapper: {
    '^@src/(.*)$': '<rootDir>/src/$1',
  },
  watchPathIgnorePatterns: ['/node_modules/'],
};

설정 내용은 간단해요. moduleFileExtensions옵션으로 사용할 모듈 파일 확장자 정의했고요. moduleNameMapper@src로 테스트할 파일이 있는 경로를 간단하게 사용할 수 있도록 Alias처럼 정의했습니다. 마지막 watchPathIgnorePatterns로 불필요한 디렉터리를 와치(watch) 대상에서 제외했습니다. 와치 기능은 코드가 수정되면 자동으로 테스트를 다시 돌려주는 기능이고요. 이외에 추가 설정은 공식 사이트를 참고하시면 될 것 같아요. 자 이제 실행해볼까요?

packages/pgjs/src/index.js 파일을 다시 수정할게요.

class MyClass {
  #pField = 'hello';

  getPField() {
    return this.#pField;
  }
}

export default MyClass; // 요기

MyClass를 테스트 파일에서 사용할 수 있도록 MyClass를 익이 스포트 했습니다. 이제 MyClass를 테스트하는 테스트 케이스를 만들어 볼게요. index.js와 동일한 경로에 index.test.js라고 파일을 만듭니다.

import MyClass from '@src/index';

describe('MyClass', () => {
  it('could returns pField value using getPField() ', () => {
    expect(new MyClass().getPField()).toEqual('hello');
  });
});

제스트는 it 함수와 test로 테스트 케이스를 작성할 수 있는데요. 둘 다 똑같다고 보시면 되는데요. 테스트와 디스크립션이 어떻게 상호작용할지에 따라 선택하시면 좋아요. it 함수의 itdescribe 함수의 디스크립션을 가리킨다 라로 생각하시면 됩니다. 그래서 it 함수의 디스크립션은 it이라는 주어가 이미 있다고 가정하고 작성하시면 됩니다.

이제 packages/pgjs 경로에서 테스트를 돌려 볼게요.

npx jest

실행하면 결과가 바로 나옵니다.

 PASS  src/index.test.js
  MyClass
    ✓ could returns pField value using getPField()  (2 ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        0.949 s, estimated 1 s

멋지죠? DOM도 테스트할 수 있지만 DOM 관련 테스트는 추가 도구 testing-library 와 함께하면 좋아요. 이것 관련해서는 리액트 설정할 때 다시 다룰게요.

아! 제스트는 Node 환경을 사용하기 때문에 실제 DOM을 직접 테스트할 수는 없어요. 그래서 jsdom 같은 가상 DOM을 이용해서 테스트합니다. 알아서 해주니까 딱히 뭘 해줄 필요는 없는데요. 가짜 DOM이다 보니 가끔 이벤트 객체 정보나 Range 같은 특정 API들이 정상 동작하지 않을 때가 있어요. 이것 때문에 며칠 고생했던 적이 있어서 말씀드려요. 대부분의 브라우저 API는 정상 동작으로 잘 모킹해 주지만 그렇지 않은 경우가 있으니 내 실수의 여지가 없는 상황에서는 한번 의심해보시면 좋아요. 근데 보통 내 실수입니다. :()

마무리

자 제스트 설정까지 해서 기본 자바스크립트 환경은 모두 만들었습니다. 아직은 플레이그라운드라기보다는 그냥 요즘 개발 환경을 하나씩 설치하고 설정까지 해본 것에 불과하지만 여기서 끝이 아닙니다. 파트 2에서는 기본 자바스크립트 환경을 토대로 타입 스크립트와 리액트 개발 환경을 추가할 건데요. 러나를 이용해서 디펜던시 모듈의 중복을 쉽게 줄일 수 있고요. 각종 설정 파일들도 중복을 줄일 수 있게 할 거예요. 그리고 어떻게 플레이그라운드로 활용할지도 생각해 봐야겠죠? 알짜는 파트 2에 있습니다. 우선 여기까지 해서 파트 1으로 정리하고요 파트 2에서 마무리할게요. 파트 2로 바로가기!

♥ Support writer ♥
with kakaopay

크리에이티브 커먼즈 라이선스이 저작물은 크리에이티브 커먼즈 저작자표시-비영리-변경금지 4.0 국제 라이선스에 따라 이용할 수 있습니다.

© Sungho Kim2023