Logo

자바스크립트 프로젝트에서 스크립트 활용하기 (npm run)

자바스크립트 프로젝트에서 개발을 하다보면 터미널을 열고 명령어를 실행해야하는 경우가 빈번하게 생기는데요. 대표적인 예로 로컬 환경에서 애플리케이션을 빌드하고 구동하거나 테스트를 실행하는 것을 들 수 있습니다.

이번 포스팅에서는 자바스크립트 프로젝트에서 자주 사용되는 명령어를 스크립트로 등록하고 실행하는 방법에 대해서 알아보겠습니다.

반복 명령은 스크립트로

자바스크립트 프로젝트에서 개발을 진행하다보면 테스트나 빌드(build), 린트(lint), 포맷(format)처럼 반복적으로 수행해야하는 작업들이 생기기 마련입니다. 각 작업은 일반적으로 특정한 개발 도구의 명령어를 실행하게되는데요. 예를 들어, 테스트를 수행할 때는 Jest나 Mocha와 같은 테스트 러너(runner)를 실행하고, 빌드를 수행할 때는 Webpack이나 Parcel과 같은 번들러(bundler)를 실행하고, 린트를 수행할 때는 ESLint와 같은 린터(linter)를 실행하게 됩니다.

이러한 상황은 프로젝트에 참여하고 있는 개발자들에게 (특히 경험이 많치 않은 개발자들에게) 상당히 골치아픈 문제가 될 수 있습니다. 왜냐하면 프로젝트의 모든 개발자들이 이러한 개발 도구들이 제공하는 CLI(Command Line Interface, 커맨드 라인 인터페이스)에 대해서 숙지하고 있어야 하기 때문입니다. 게다가 각 CLI가 제공하는 커맨드와 옵션이 다 달라서 모든 개발자가 매번 정확한 명령어를 터미널에 타이핑하는 것은 쉽지 않은 일입니다. 그 개발자가 여러 프로젝트에 참여하고 있다면 더욱 괴로워지겠지요…

이 문제를 해결하는 좋은 방법은 각 반복 작업을 수행할 때 실행해야하는 명령어를 미리 스크립트로 만들어 놓는 것입니다. 그러면 프로젝트의 개발자는 반복 명령을 수행할 때 어떤 스크립트를 실행해야하는지만 기억하면 되기 때문입니다.

프로젝트에서 필요한 스크립트를 준비하는 방법은 여러 가지가 있으며 각 방법마다 장단점이 있습니다. 전통적인 방법으로 쉘(shell) 스크립트를 작성할 수도 있고, Make와 같은 빌드 자동화 도구를 도입할 수도 있습니다.

해당 프로젝트가 Node.js를 기반으로 되어있는 자바스크립트 프로젝트라면 package.json 파일과 npm run 명령어를 사용하여 이 보다 훨씬 간편하게 스크립트를 등록하고 실행할 수 있습니다.

스크립트 등록

Node.js 기반 프로젝트에서는 프로젝트의 메타 데이터를 관리하기 위해서 package.json 파일을 사용합니다. 이 package.json 파일의 scripts 부분에 반복적으로 수행해야하는 스크립트를 등록해놓을 수 있습니다.

스크립트를 등록할 때는 package.json을 열고 직접 편집할 수도 있으나 그러면 오타의 위험이 있어서 가급적 npm pkg set scripts.{스크립트 이름}={명령어} 명령어를 사용하시는 것을 추천드립니다.

예를 들어, 콘솔에 Hi!를 출력해주는 명령어를 실행해주는 hi라는 스크립트를 추가해보겠습니다.

$ npm pkg set scripts.hi "echo 'Hi!'"

이제 package.json 파일을 열어보시면 다음과 같이 hi 스크립트가 추가되어 있는 것을 확인하실 수 있을거에요.

package.json
{
  // 생략
  "scripts": {
    "hi": "echo 'Hi!'"  },
  // 생략
}

스크립트 실행

이렇게 등록한 스크립트는 npm run <스크립트 이름> 명령어를 통해 실행할 수 있습니다.

터미널을 열고 npm run hi라고 입력하고 엔터키를 눌러봅니다.

$ npm run hi

> our-project@1.0.0 hi
> echo 'Hi!'

Hi!

package.json 파일에 명시해놨던 echo 'Hi!'가 실행되어 콘솔에 Hi!가 출력되는 것을 볼 수 있습니다.

어떤가요? 정말 쉽지 않나요? 😙

테스트 스크립트

실제 자바스크립트에서 프로젝트에서 자주 쓸법한 명령어를 스크립트로 등록하고 실행하보겠습니다.

개발자들이 가장 많이 수행하는 작업 중에서 테스트 실행을 빼놓을 수 없을 것입니다. 특히 TDD(Test Driven Development, 테스트 주도 개발)를 하는 분들에게는 필수 스크립트일텐데요.

간단한 실습을 위해 많이 사용되는 테스트 실행 도구인 Jest를 먼저 프로젝트에 설치하겠습니다.

$ npm i -D jest

그 다음 샘플 테스트 파일을 하나 작성해보겟습니다.

test.js
test("1 is 1", () => {
  expect(1).toBe(1);
});

프로젝트 상의 모든 테스트를 실행하려면 node_modules/.bin 디렉토리 안에 있는 jest 커맨드를 실행해야 합니다.

$ node_modules/.bin/jest
 PASS  ./test.js
  ✓ 1 is 1 (1 ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        0.1 s, estimated 1 s
Ran all test suites.

테스트를 실행할 때 마다 매번 이 긴 경로를 타이핑하려면 힘들겠죠? 다행히도 스크립트에 커맨드를 등록할 때는 node_modules/.bin를 생략할 수 있습니다. 😌

그럼 npm pkg set 명령어를 이용해서 test라는 스크립트를 추가해보겠습니다.

$ npm pkg set scripts.test="jest"
package.json
{
  // 생략
  "scripts": {
    "hi": "echo 'Hi!'",
    "test": "jest"  },
  // 생략
}

이제 터미널에서 npm run test를 실행하면 위와 동일하게 테스트가 실행됩니다. 🎉

$ our-project npm run test

> our-project@1.0.0 test
> jest

 PASS  ./test.js
  ✓ 1 is 1 (1 ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        0.12 s, estimated 1 s
Ran all test suites.

복잡한 명령어

테스트를 실행할 때 --watch 옵션을 사용하여 관찰모드로 실행할 때가 많은데요. npm run 명령어로 추가적인 옵션을 넘길 때는 옵션 바로 앞에 --를 붙야줘야 합니다.

예를 들어, npm run test 스크립트를 실행 할 때 --watch 옵션을 사용하고 싶다면 터미널에 npm run test -- --watch이라고 타이핑해야 합니다.

$ our-project npm run test -- --watch

> our-project@1.0.0 test
> jest --watch

 PASS  ./test.js
  ✓ 1 is 1 (1 ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        0.114 s, estimated 1 s
Ran all test suites related to changed files.

Watch Usage
 › Press a to run all tests.
 › Press f to run only failed tests.
 › Press p to filter by a filename regex pattern.
 › Press t to filter by a test name regex pattern.
 › Press q to quit watch mode.
 › Press Enter to trigger a test run.

만약 프로젝트의 많은 개발자들이 관찰모드로 테스트를 한다면 어떨까요? 그럴 때는 jest 명령어에 --watch 옵션을 붙여서 별도의 스크립트로 등록해주면 됩니다.

예를 들어, 다음과 같이 test:watch 스크립트를 추가해서 사용할 수 있습니다.

$ npm pkg set scripts.test:watch="jest --watch"
package.json
{
  // 생략
  "scripts": {
    "hi": "echo 'Hi!'",
    "test": "jest",
    "test:watch": "jest --watch"  },
  // 생략
}

모든 스크립트 확인

실제 프로젝트에서 위와 같은 방식으로 스크립트를 계속 추가하다보면 package.json 파일의 scripts 영역이 아래와 같이 점점 늘어나게 됩니다.

package.json
{
  // 생략
  "scripts": {
    "start": "webpack serve --open",    "build": "webpack",    "test": "jest",    "test:watch": "jest --watch",    "lint": "eslint --cache --ext .js,.jsx .",    "lint:fix": "eslint --fix --cache --ext .js,.jsx .",    "cy:open": "cypress open",    "cy:run": "cypress run",  },
  // 생략
}

터미널에서 npm run 커맨드를 스크립트 이름 없이 실행하면 굳이 package.json 파일을 뒤지지 않더라도 프로젝트에서 사용이 가능한 모든 스크립트를 나열해줍니다.

$ npm run
Lifecycle scripts included in our-project@1.0.0:
  start
    webpack serve --open
  test
    jest

available via `npm run-script`:
  build
    webpack
  test:watch
    jest --watch
  lint
    eslint --cache --ext .js,.jsx .
  lint:fix
    eslint --fix --cache --ext .js,.jsx .
  cy:open
    cypress open
  cy:run
    cypress run

예외적으로 starttest 스크립트의 경우, 워낙 자주 사용되는 스크립트이기 때문에 npm run에서 run을 생략해도 무방합니다.

즉, 아래 두 커맨드는 동일한 효력을 내며,

$ npm run start
$ npm start

아래 두 커맨드도 마찬가지 입니다.

$ npm run test
$ npm test

개발자들은 대부분 짧은 명령어를 선호하기 때문에 run을 생략하고 많이 사용하는 것 같습니다.

마치면서

이상으로 자바스크립트 프로젝트에서 빈번하게 사용되는 명령어를 어떻게 스크립트로 등록하고 실행할 수 있는지에 대해서 알아보았습니다. 사실 협업 프로젝트에서 이러한 스크립트의 적절한 활용은 개발자 개개인의 편의 뿐만 아니라 프로젝트의 전체 생산성에도 영향을 줄 수 있습니다. 시간을 잠깐 투자하셔서 이 부분에 대해 잘 정리를 해놓으시면 도움이 될 것 같아서 한 번 다루어 보았습니다.

참고로 npm run 명령어는 엄밀히 얘기하면 npm run-script 명령어의 별칭(alias), 즉 단축 명령어입니다. npm run-script 명령어에 대한 좀 더 자세한 내용은 공식 npm 문서를 참고 바랍니다.