NPM

김동현·2021년 12월 30일
0
post-thumbnail

Node.js의 필요성

Node.js는 웹 어플리케이션 개발에 직접적으로 사용하는 것은 아니지만 개발 환경을 이해하고 구성하는데 Node.js를 사용하기 때문에 프론트엔드 개발에 있어서 Node.js가 필요합니다.

1. 최신 스펙

자바스크립트의 빠른 발전에 비해 브라우저의 지원 속도는 느립니다. 아무리 편리한 스펙이 등장하더라도 이를 "브라우저에 맞게 변환"해주는 역할이 필요합니다(webpack, babel 등,,). 이러한 기술들은 대부분 Node 환경 위에서 동작하는 도구들입니다.

마찬가지로 Typescript나 Sass와 같은 도구들을 사용하려면 그에 맞는 "전용 트랜스파일러"가 필요합니다. 이런 것들 또한 "Node.js 환경이 뒷받침"되어야만 프론트엔드 개발 환경을 만들 수 있습니다.

2. 빌드 자동화

과거처럼 코딩 결과물을 그대로 브라우저에 올리는 경우는 줄어들고 있습니다. 파일을 압축하고, 코딩한 내용을 난독화하고, 브라우저에 따라 풀리필을 추가하는 등 개발 이외에 후속 작업을 거친 다음에 배포를 하게 됩니다.

Node.js는 이러한 일련의 "빌드 과정"(배포하기 위한 과정)을 이해하는데 큰 역할을 할 뿐만 아니라 프로젝트에서 사용중인 패키지(라이브러리)를 다운받고 각종 테스트를 자동화하는 데도 Node.js가 사용됩니다.

3. 개발 환경 커스터마이징

React나 Vue를 사용하게 되면 각각에서 제공해주는 도구(create-react-app, vue-cli)를 통해 개발을 시작할 수 있습니다. 하지만 개발 프로젝트는 각자 형편이라는 것이 있어 자동화 툴을 그대로 사용할 수 없는 경우도 빈번히 존재합니다.

"개발 환경을 커스터마이징"해야 하는데 이때 Node.js 지식이 필요합니다.
어쩌면 자동화된 도구들을 사용할 수 없는 환경이라면 직접 개발 환경을 구축해야하는 상황이 발생할 수도 있습니다.


이러한 이유들로 인해 Node.js는 프론트엔드 개발에 있어서 필수 기술로 "프론트엔드 개발 환경을 이해하고 구성"하는데 큰 역할을 하고 있습니다.

Node.js 설치

Node.js는 https://nodejs.org/en/ 에서 다운받을 수 있습니다. 이때 안정적인 버전 혹은 최신 버전을 선택하여 다운 받을 수 있습니다. Node로 서버를 운영하는 경우 안정적인 버전(LTS)를 다운받고, 개발 환경을 구축하는 경우에는 "최신 버전"을 사용합니다.

REPL

터미널을 연 다음에 다음과 node라고 입력하면 노드 터미널 도구인 "REPL"가 열리는데, REPL은 자바스크립트 코드를 입력하고 바로 그 결과를 확일할 수 있는 프로그램입니다.

터미널에 console.log('Hello, world!');라고 입력하면 Hello, world가 화면에 출력되는 것을 확인할 수 있습니다. 종료하려면 .exit 를 입력하면 이전 쉘 스크립트로 돌아가게 됩니다.

node -v, node --version

터미널에 node -v혹은 node --version를 입력하면 현재 Node.js의 버전을 확인할 수 있습니다.

n latest, n lts, n stable

만약 기존 노드 버전을 최신 버전으로 업데이트하고자 한다면 터미널에 n lts또는 n latest를 입력합니다.

안정적인 버전으로 업데이트하고자 한다면 n stable을 입력합니다.

npm -v, npm --version

npm -v혹은 npm --version는 npm의 버전을 확인할 수 있습니다.

참고로 node.js를 설치하게 되면 자동적으로 npm이 설치가 됩니다.

npm i npm -g

기존 npm 버전을 최신 버전으로 업데이트하고자 한다면 터미널에 npm i npm -g을 입력합니다. -g 옵션을 작성하지 않는다면 해당 프로젝트 내에서만 적용되기 때문에 로컬 전역에 적용하기 위해서는 -g 옵션을 작성해줍니다.

프로젝트 초기화

개발 프로젝트는 외부 라이브러리(패키지)를 다운 받고 빌드하는 등 "일련의 명령어를 자동화하여 프로젝트를 관리"하는 도구로 "npm"이 존재합니다.

npm은 자바스크립트 기반 프로젝트의 빌드 도구입니다. npm을 이용해 프론트엔드 개발 프로젝트를 구축을 해보겠습니다.

npm init

npm에서 제공하는 여러 명령어 중 npm init 명령어를 사용하면 프로젝트를 초기화하는 명령어 입니다. 명령어를 입력하면 프로젝트 메타 정보를 입력할 수 있는 정보가 제공됩니다.

위 그림에서는 sample 디렉토리로 이동한 다음에 npm init을 입력하면 다음과 같이 패키지 이름, 버전 등 프로젝트와 관련한 몇 가지 정보를 얻기 위한 질문을 볼 수 있습니다.

직접 작성하거나 혹은 빈 칸으로 남겨 두면 괄호 안의 기본값으로 지정됩니다. 만약 모두 기본값을 사용할 것이라면 npm init -y를 사용할 수도 있습니다.

package.json

npm init 명령어를 실행한 이후에 sample 프로젝트 폴더 안에 "package.json" 파일이 생성된 것을 확인할 수 있습니다.

Node.js는 package.json 파일에 프로젝트의 모든 정보가 기록됩니다.

// package.json

{
    "name": 프로젝트 이름,
    "version": 프로젝트 버전 정보,
    "description": 프로젝트 설명,
    "main": 노드 어플리케이션인 경우 진입점 경로,
    "scripts": 프로젝트 명령어(기본적으로 test 명령어가 샘플로 존재),
    "author": 프로그램 작성자,
    "license": 라이센스 정보
}

프로젝트 명령어

생성한 프로젝트는 package.json에 "scripts에 등록한 스크립트"를 이용하여 명령어를 자동화할 수 있습니다. 어플리케이션 빌드, 테스트, 배포, 실행 따위의 명령어를 등록합니다.


현재 프로젝트의 scripts에는 test 명령어만 존재합니다. test 명령어를 실행하기 위해서는 터미널에 npm test를 입력해줍니다.

실행하면 터미널에는 에러 메세지(echo \"Error: no test specified\")를 출력하고 그 다음 줄에 npm 에러(exit 1)가 발생합니다. 이것은 npm 스크립트에 등록된 쉘 스크립트 코드를 실행되었기 때문입니다. echo 명령어로 메세지 "Error: no test specified"를 출력한뒤 에러 코드 1을 던지면서 종료하는 동작을 합니다. 에러 코드 1을 확인하면 에러("npm ERR!...")를 출력합니다.


test명령어 이외에도 npm에서 사용할 수 있는 기본 명령어는 터미널에서 npm을 입력하면 확인할 수 있습니다.

하이라이팅되어있는 것들은 기본적인 명령어로 npm <command> 형식으로 사용할 수 있습니다. 만약 기본적으로 제공하는 명령어 이외에 사용자 정의 명령어를 사용하는 경우에는 npm run <command>형식을 사용합니다.

자주 사용하는 기본적인 명령어들로 start, test, install, uninstall이 있습니다.

  • npm start : 어플리케이션 실행

  • npm test : 테스트

  • npm install : 패키지 설치

  • npm uninstall : 패키지 제거


기본적으로 제공하는 명령어 이외에 사용자 정의 명령어를 추가할 수도 있습니다. 예를 들어, customScript 스크립트는 package.json의 scripts 부분에 customScript 키를 추가하고 값으로는 쉘 스크립트를 문자열로 등록하면 됩니다.


주의할 점으로는 커스텀으로 등록한 명령어는 npm run <command> 형식으로 run을 추가해서 실행해야 합니다.


프론트엔드 개발 환경을 구축하기 위해 추가할 스크립트로는 build, lint 정도가 있습니다.

  • npm build : 소스 빌드

  • npm lint : 소스 컨벤션 검사

패키지(라이브러리) 설치

1. CDN을 이용하는 방법

가장 간단한 방법으로 CDN을 사용하는 방법이 있습니다. "CDN"은 Content Delivery Network의 약어로 보통 자바스크립트의 라이브러리, CSS 라이브러리 등을 빠르게 제공해주는 서버입니다.

CDN을 사용하는 경우 CDN의 서버에 장애가 발생하게 된다면 외부 라이브러리를 가져올 수 없게 됩니다. 그로 인해 우리의 웹 어플리케이션도 정상적으로 동작하지 않을 수 있습니다.

CDN을 사용하는 방법은 html 엘리먼트인 <script></script>를 사용하는 것입니다. 이때 src 속성에 CDN 주소를 작성하는 방법으로 사용할 수 있습니다.

아래는 react 라이브러리를 CDN으로 가져오는 예시입니다.

<script src="https://unpkg.com/react@16/umd/react.development.js"></script>

2. 직접 다운로드하는 방법

이러한 서버 장애와 무관하게 어플리케이션을 구동하기 위해서는 직접 코드를 다운받아서 프로젝트에 추가해주는 것입니다. 위에서 설명한 CDN 방법에서 발생하는 서버 장애가 생긴 경우에도 우리의 어플리케이션은 정상적으로 동작하게 될 것입니다.

하지만 라이브러리는 계속해서 업데이트될 것이며 그에 따라 프로젝트에도 최신 버전으로 업데이트해주어야 합니다. 이러한 업데이트를 개발자가 수작업으로 다운받고 빌드하는 것은 비효율적으로 보입니다.

3. NPM을 이용하는 방법

npm에서 사용할 수 있는 기본 명령어 중에 npm install <package name>을 사용하여 간단하게 우리의 프로젝트에 "라이브러리(패키지)를 설치"할 수 있습니다.

참고로 터미널에서 npm install만을 입력한다면 package.json 파일의 dependencies에 명시된 패키지들을 전부 설치하게 됩니다.


react 라이브러리를 예로 들어 설명하겠습니다. 터미널에서 라이브러리를 설치할 프로젝트로 이동한 다음 npm install react를 입력하면 최신 버전의 react를 npm 저장소에서 찾아 우리 프로젝트로 다운로드합니다.

명령어 실행 이후에 package.json의 dependencies에는 설치한 패키지 정보가 기록됩니다.

패키지 버전 관리

Node.js가 패키지의 버전을 관리하는 방법을 알아보겠습니다. 만약 프로젝트에서 사용하는 패키지의 버전을 매우 엄격하게 제한한다면 프로젝트를 버전업하는 데에 무척 힘들 수 있습니다. 사용하는 패키지들을 모두 버전업해야 우리의 프로젝트를 버전업할 수 있기 때문입니다.

반대로 패키지의 버전을 느슨하게 풀어 놓는다면 오히려 여러 버전을 코드로 관리해야하기 때문에 혼란을 겪을 수 있습니다.

유의적 버전

이러한 "버전 번호를 관리하기 위한 규칙" 이 필요한데 이 쳬계를 "유의적 버전(Sementic Version)"이라고 합니다. npm은 이 유의적 버전을 따르고 있습니다.

유의적 버전은 "주(Major)", "부(Minor)", "수(Patch)" 세 가지 숫자를 조합해서 버전을 관리합니다. 위에서 설치한 react의 버전이 v17.0.2라면 이때 주 버전은 17, 부 버전은 0, 수 버전은 2입니다.

각 버전을 변경하는 기준은 다음과 같습니다.

  • 주 버전(Major Version): 기존 버전과 "호환되지 않게 변경"한 경우

  • 부 버전(Minor Version): 기존 버전과 호환되면서 "기능이 추가"된 경우

  • 수 버전(Patch Version): 기존 버전과 호환되면서 "버그를 수정"한 경우

이렇게 버전 번호를 관리하는 방법을 유의적 버전이라고 하고, Node.js는 유의적 버전의 규칙을 따릅니다.

버전의 범위

npm이 버전을 관리하는 방식은 유의적 버전 명세 뿐만아니라 "버전의 범위를 자신만의 규칙으로 관리"합니다.

  1. 가장 단순한 것이 특정 버전을 사용하는 경우입니다.
    ex) 1.2.3
    이때 npm이 패키지를 설치할 때마다 1.2.3 버전만을 설치하게 됩니다.

  2. 그렇지 않고 특정 버전보다 높거나 낮을 경우 부등호를 사용하여 다음과 같이 명시합니다.
    ex) >1.2.3: 1.2.3 버전보다 높은 버전만 사용
    >=1.2.3: 1.2.3 버전과 같거나 높은 버전만 사용
    <1.2.3: 1.2.3 버전보다 낮은 버전만 사용
    <=1.2.3: 1.2.3 버전과 같거나 낮은 버전만 사용

  3. 마지막으로 "틸트(~)""캐럿(^)"을 사용하여 범위를 명시합니다.

  • 틸드(~)는 마이너 버전이 명시되어 있는 경우 뒤에 오는 패치 버전을 변경합니다. 예를 들어, ~1.2.3 표기는 1.2.3부터 1.3.0 미만까지의 버전을 사용합니다. 마이너 버전이 없는 경우, 예를 들어 ~0과 같은 경우 마이너 버전을 변경합니다. 즉, ~0 표기법은 0.0.0부터 1.0.0 미만까지 사용합니다.
    즉, 마이너 버전이 존재하는 경우 패치 버전을 변경하고, 마이너 버전이 없는 경우 마이너 버전을 변경합니다.

  • 캐럿(^)은 정식 버전에서 마이너와 패치 버전을 변경합니다. 예를 들어, ^1.2.3인 경우 1.2.3부터 2.0.0 미만까지를 포함합니다. 하지만 정식 버전 미만인 0.X 버전은 패치 버전만 갱신합니다. ^0인 경우 0.0.0부터 0.1.0미만까지 사용합니다.
    즉, 정식 버전(1.0.0 이상)에서 마이너 버전과 패치 버전을 업데이트하고, 정식 버전이 아닌 경우(0.X) 패치 버전만 업데이트합니다.


위에서 설치한 react 라이브러리는 ^17.0.2로 표기되어 있으며 이는 정식 버전이므로 17.0.2부터 18.0.0 미만까지 사용합니다.

보통 라이브러리 정식 릴리즈 전에는 패키지 버전이 수시로 변경됩니다. 0.1.0에서 0.2.0로 마이너 버전이 변경되더라도 하위 호환성을 지키지 않고 배포하는 경우가 빈번합니다. 그래서 틸트(~)로 버전을 관리하는 경우, ~0은 0.0.0부터 1.0.0미만까지 사용하기 때문에 하위 호완성을 지키지 못하는 0.2.0로도 업데이트 되어버리는 문제가 생길 수 있습니다.

반면에 캐럿(^)으로 버전을 관리하는 경우, ^0은 0.0.0부터 0.1.0 미만까지, 즉 정식 버전이 아닌 경우 패치 버전만 업데이트하여 사용하기 때문에 하위 호환성을을 유지할 수 있습니다.

NPM으로 패키지를 설치하면 package.json에 설치한 버전이 기록되는데 "캐럿 방식(^)"을 이용합니다. 초기에는 버전 범위에 틸트(~)를 사용하다가 캐럿(^)을 도입해서 기본 동작으로 사용했다. 그래서 우리가 설치한 react는 ^17.0.2 표기로 버전 범위를 기록되어 있습니다.

profile
Frontend Dev

0개의 댓글