최근 개인적으로 공통 UI 라이브러리를 개발하고 NPM에 배포하는 과정을 경험해보았다.
이 과정에서 패키지를 새 버전으로 업데이트할 때마다 실제 배포 전에 로컬 환경에서 테스트 할 수 있는 방법의 필요성을 느꼈다.
이를 위해 조사한 결과 유용한 방법을 발견하여 공유하고자 포스팅을 작성하였다.
패키지를 개발하면서 새 기능을 추가하거나 버그를 수정할 일이 빈번하게 있을건데, 이 때 변경 사항을 npm에 바로 배포하기 이전에 수정한 코드가 제대로 작동하는지 로컬에서 먼저 테스트 하고 검증할 수 있는 방법이 있다면 얼마나 좋을까?
이러한 과정을 도와주는 npm 명령어가 있다. 바로 "npm link" 명령어이다.
npm link로컬에서 개발 중인 패키지를 쉽게 테스트 할 수 있도록 하는 명령어이다. 이를 통해 패키지를 실제 npm 레지스트리에 publish 하기 전에 변경 사항을 직접 확인하고, 다른 프로젝트에서도 즉시 패키지를 사용해 볼 수 있다.
link 라는 단어는 '패키지 폴더를 Symlink(심볼릭 링크)로 연결' 한다는 의미에서 따온 것으로 보인다.
해당 명령어를 사용하면 패키지는 로컬(내 컴퓨터)에서 전역적으로 심볼릭 링크로 만들어지고, 이를 통해 다른 로컬 프로젝트에서 해당 패키지를 참조할 수 있도록 설정된다.
여기서 Symbolic link란, 파일 시스템에서 파일 혹은 디렉토리의 참조를 특정한 다른 곳에 생성하는 특수한 타입의 파일을 말한다. 이 심볼릭 링크는 원본에 대한 경로를 가리키며, 해당 링크를 통해 원본에 접근이 가능하다.
원본에 대한 복사본이 아니라 경로에 대한 참조만 가지고 있으므로, 원본이 수정되더라도 변경 사항을 즉시 확인할 수 있다.
이러한 특성에 맞게 npm 패키지를 심링크로 연결해 로컬에서 사용할 수 있다.
다음 상황을 가정해 보자. 현재 상황은 npm에 배포된 latest version은 0.4.0 이고, 로컬에서 소스 코드 업데이트를 거친 후 0.4.1 버전으로 배포하기 전의 상황이다. 이에 맞춰 package.json의 패키지 버전도 0.4.1로 수정해 주었다.
이제 배포하려는 패키지(심볼릭 링크를 생성하려는 패키지) 디렉토리에서 아래 명령어를 실행하기만 하면 된다.
npm link
링크가 정상적으로 생성되었는지는 어떻게 확인할까?
가장 간단하게 알아볼 수 있는 방법은 npm ls -g 명령어를 사용하는 것이다. 해당 명령어는 시스템에서 전역적으로 설치된 모든 패키지를 나열하는데, 여기에는 링크된 패키지도 포함하여 보여진다.
또한 최상위 패키지만 표시되도록 --depth=0 옵션을 사용하였다.
npm ls -g --depth=0
/usr/local/lib
├── 패키지명@0.4.1 -> 프로젝트경로 # 프로젝트 루트에서 pwd 명령어 실행 결과와 동일
└── 그 외 전역적으로 설치된 패키지들..
이제 해당 패키지를 사용해야 하는 다른 프로젝트에서 다음 명령을 실행해본다. 패키지명은 원본 패키지의 package.json 파일의 있는 "name"을 입력하면 된다.
npm link <패키지명>
이후 패키지를 사용하는 프로젝트(현재 위치한 곳)의 node_modules 디렉토리를 확인해 보면, 링크한 패키지가 존재하는 걸 확인할 수 있다.
또한 원본 패키지에서 소스 코드를 수정하면, 별도로 npm install 같은 과정을 거치지 않고도 변경 사항이 실시간으로 반영되어 쉽게 테스트 해볼 수 있다.
그런데 문제가 있다. 개발 중인 패키지는 React UI Library 로써, 실제 npm에 배포될 때는 빌드 과정을 거쳐서 dist 디렉토리만 업로드 되도록 구성되어 있다. 또한 package.json의 "main" 필드를 통해 dist/cjs/index.js로 진입점 또한 설정된 상태이다.
{
"name": "패키지이름",
"version": "0.4.1",
"main": "dist/cjs/index.js",
"files": [
"dist",
"README.md"
],
// 다른 설정들...
}
하지만 npm link 명령을 통해서는 이런 애플리케이션 진입점 같은 설정들이 먹히지 않고, 단순하게 원본 패키지가 있는 디렉토리 위치를 가리키는 심볼릭 링크를 생성할 뿐이다.
그래서 패키지를 사용하는 쪽에서도 만약 컴포넌트 하나를 불러오려고 한다면 아래와 같이 수동으로 import 문을 작성해야 한다. 개발 중인 컴포넌트를 실시간으로 반영해서 볼 수 있긴 하지만, package.json에서 설정한 일부 설정이 정상적으로 반영되지 않을 수 있다.
import { Button } from "../node_modules/패키지명/dist/esm/index";
따라서 로컬 패키지를 번들링하여 로컬에서 설치해 사용할 수 있는 방법인 "npm pack"에 대하여 알아보자.
npm packnode_modules 안에 심볼릭 링크를 활용해 원본 패키지의 모든 파일/디렉토리에 접근하는 link 방식 대신, 로컬 패키지를 npm install을 통해 실제로 설치할 수 있는 방식이다.
이 명령어는 '패키지로부터 tarball을 생성'하는 명령어이다.
tarball이란, 일반적으로 여러 파일이나 디렉토리를 하나의 파일로 묶어 .tar 확장자를 가지는 형식의 파일을 말한다.
해당 명령을 활용해 패키지를 배포하기 전에 실제 사용 환경처럼 테스트 해 볼수 있어서 유용하다.
위에서 했던 것처럼, 패키지 디렉토리 안에서 바로 명령을 실행하면 된다.
npm pack
해당 과정을 통해 "패키지명-0.4.1.tgz" 라는 파일이 프로젝트 루트에 만들어졌다. 이제 이 파일을 다른 프로젝트에서 어떻게 설치할 수 있는지 알아보자.
npm install 원본프로젝트_절대경로/패키지명-0.4.1.tgz
아까 전 link 명령어와 다른 점이 있다면, 아까는 package.json 파일에 의존성으로 패키지 추가가 안되었었는데, 이 방식은 npm install을 통하여 설치가 이루어지기 때문에 의존성으로 추가된다는 차이점이 있다.
또한 이전처럼 코드에서 import를 해올 때도 이 때는 package.json에서 설정한 애플리케이션 진입점같은 사항들이 반영되기 때문에 실제 패키지 사용 환경과 동일한 방식에서 테스트를 진행해 볼 수 있다는 장점이 있다.
import { Button } from "패키지명";