npm과 pnpm에서 patch-package로 외부 라이브러리 직접 패치하기

Rony·2026년 2월 27일
post-thumbnail

들어가며

개발을 하다 보면 외부 라이브러리에서 버그를 발견하거나, 우리 프로젝트에 맞게 살짝 동작을 바꾸고 싶을 때가 있다. 이럴 때 가장 흔한 해결책은 node_modules 안의 파일을 직접 수정하는 것인데....

문제는, node_modules는 git에 올리지 않는다. 누군가 npm install을 다시 실행하면 수정한 내용이 날아가버리는 문제가... 팀 전체가 같은 수정을 반복해야 하거나, CI/CD 파이프라인이 깨지는 상황이 발생하게 된다.

이 문제를 깔끔하게 해결해주는 도구가 바로 patch-package 이다.


patch-package란?

patch-package는 node_modules에 가한 변경 사항을 diff 파일 형태로 저장해두고, npm install 이후 자동으로 해당 패치를 다시 적용해주는 도구다.

핵심 동작 원리는 아래와 같다.

  1. node_modules/some-package/index.js를 직접 수정
  2. npx patch-package some-package 명령을 실행
  3. patches/some-package+1.0.0.patch 파일이 생성됨
  4. 이 .patch 파일을 git에 커밋
  5. 이후 누가 npm install을 하더라도 postinstall 훅을 통해 패치가 자동 적용

.patch 파일은 일반적인 unix diff 형식이라 코드 리뷰도 가능하고, 변경 이력도 git에 남기때문에 대상 라이브러리에서 어떤부분을 바꿨는지 확인 및 관리가 용이하다.


왜 patch-package를 써야 할까?

1. 라이브러리 버그수정을 기다리지 않아도 된다

오픈소스 라이브러리에 버그를 발견하고 PR을 올렸는데, 메인테이너가 몇 달째 응답이 없는 경우가 있다. 아니면 이미 지원이 종료되어 더이상의 업데이트가 없는 라이브러리 이거나... 이때 patch-package를 쓰면 릴리즈를 기다리지 않고 지금 당장 문제를 해결할 수 있다.

2. 팀 전체에 일관된 수정이 적용된다

.patch 파일을 git에 올려두면, 팀원 누구든 npm install 한 번으로 동일한 환경을 갖출 수 있다. "내 로컬에서는 됐는데?"라는 곤란한 상황을 피해보도록 하자...

3. 변경 이유가 코드로 남는다

직접 node_modules를 수정하면 왜 고쳤는지 아무도 모른다. patch-package를 쓰면 .patch 파일에 변경 내용이 diff 형식으로 남고, git commit 메시지로 이유까지 기록할 수 있다.

4. 라이브러리 업데이트 시 충돌을 명확하게 알 수 있다

패치가 적용된 라이브러리를 버전 업그레이드하면 패치가 실패하게 된다. 이는 "이 라이브러리 업그레이드할 때 패치를 다시 확인하세요" 라는 명확한 신호 역할을 하게된다.


npm 프로젝트에서 설정하기

1단계: 패키지 설치

npm install patch-package --save-dev

2단계: postinstall 스크립트 추가

package.json에 postinstall 스크립트를 추가.
(이 스크립트는 npm install 이후 자동으로 실행됨)

{
  "scripts": {
    "postinstall": "patch-package"
  }
}

3단계: node_modules 파일 수정

패치를 적용하고 싶은 라이브러리의 파일을 직접 수정한다.

예를 들어 some-library 패키지의 index.js에서 버그를 고쳤다면:

# 파일 수정 후 터미널에서 패치 파일 생성명령어 실행
npx patch-package some-library

patches/ 디렉토리에 다음과 같은 파일이 생성된다.

patches/some-library+2.3.1.patch

4단계: git에 커밋

이제 변경사항을 git 에 커밋 후 올리고,
팀원이 npm install을 실행하면 postinstall 단계에서 패치가 자동 적용된다.


pnpm 프로젝트에서 설정하기

pnpm은 v6.35.0 이후로 pnpm patch 라는 빌트인 기능을 제공하기 때문에 npm 을 사용하는 프로젝트와 설정방법이 약간 다르다. patch-package를 별도로 설치하지 않아도 되며, pnpm의 방식이 더 공식적이고 안정적이다.

참고: pnpm의 빌트인 patch 기능을 사용하는 것을 권장하지만, 기존 patch-package 워크플로우에 익숙하다면 pnpm에서도 patch-package를 그대로 사용할 수 있다.

방법 A: pnpm 빌트인 patch 사용 (권장)

1단계: 패치 작업 시작

pnpm patch some-library@2.3.1

pnpm이 임시 디렉토리를 만들고 해당 경로를 터미널에 출력해준다.

You can now edit the following folder: /tmp/abcd1234/node_modules/some-library
Once you're done with your changes, run "pnpm patch-commit /tmp/abcd1234"

2단계: 파일 수정

출력된 임시 경로로 이동해 파일을 수정한다.

# 예시
vim /tmp/abcd1234/node_modules/some-library/index.js

3단계: 패치 커밋

pnpm patch-commit /tmp/abcd1234

patches/some-library@2.3.1.patch 파일이 생성되고, package.json에 자동으로 다음 내용이 추가된다.

{
  "pnpm": {
    "patchedDependencies": {
      "some-library@2.3.1": "patches/some-library@2.3.1.patch"
    }
  }
}

4단계: git에 커밋

변경사항을 git에 올린 이후 다른 팀원이 pnpm install을 실행하면 패치가 자동 적용된다.


방법 B: pnpm에서 patch-package 사용

기존 patch-package 방식을 선호하거나, npm/pnpm 혼용 환경이라면 pnpm에서도 patch-package를 사용할 수 있다.

1단계: 패키지 설치

pnpm add -D patch-package

2단계: pnpm 설정

pnpm은 기본적으로 node_modules를 symlink 구조로 관리하기 때문에 직접 수정이 까다롭다. .npmrc에 다음 설정을 추가해 평탄한(flat) 구조로 만들어준다.

# .npmrc
shamefully-hoist=true

또는 패치 대상 라이브러리만 hoist 설정을 추가할 수도 있다.

public-hoist-pattern[]=some-library

3단계: postinstall 스크립트 추가

{
  "scripts": {
    "postinstall": "patch-package"
  }
}

4단계: 파일 수정 후 패치 생성

# node_modules/some-library/index.js 수정 후
npx patch-package some-library

5단계: git에 커밋

변경된 사항을 git 에 올려준다.


생성된 .patch 파일 살펴보기

실제로 생성된 .patch 파일의 내용은 아래와 같다.

diff --git a/node_modules/some-library/index.js b/node_modules/some-library/index.js
index a1b2c3d..e4f5g6h 100644
--- a/node_modules/some-library/index.js
+++ b/node_modules/some-library/index.js
@@ -42,7 +42,7 @@ function doSomething(input) {
   if (!input) {
-    return null;
+    return undefined; // null 대신 undefined 반환하도록 수정
   }

일반적인 git diff 형식이라 코드 리뷰 시 변경 내용이 명확하게 확인이 가능하다.


실전 팁

패치 적용 여부 확인

patch-package는 패치 적용 시 성공/실패 여부를 터미널에 출력한다. CI 환경에서 패치 실패 시 빌드가 중단되도록 설정하면 안전하다.

라이브러리 버전 업그레이드 시

라이브러리를 업그레이드하면 기존 패치가 맞지 않아 실패할 수 있다. 이 경우 다음 단계로 처리하도록 하자.

  1. 새 버전으로 업그레이드 (npm update some-library)
  2. 기존 .patch 파일을 확인하고 여전히 필요한지 검토
  3. 필요하다면 새 버전 기준으로 패치 재생성
  4. 불필요하다면 .patch 파일 삭제

fork vs patch-package

변경 범위가 크고 장기적인 유지보수가 필요하다면, 해당 라이브러리를 fork해서 package.json에서 fork 주소를 직접 참조하는 방법도 있다. 반면 작은 버그 수정이나 단기 임시 패치라면 patch-package가 훨씬 가볍고 관리가 편합니다.


이슈

간혹 로컬머신에서는 정상적으로 실행이 되었는데 배포시 빌드가 실패하는 경우가 있는데 내가 겪었던 케이스는 pnpm 의 버전이 로컬머신과 배포시 실행되는 버전이 달라서 발생된 문제였다.
이 경우는 pnpm 의 버전을 동일하게 맞춰주면 되는데 package.json 에 packageManager 를 명시해주면 해결된다.

{ 
 ...
 "packageManager": "pnpm@9.12.3",
 ...
}

참고 링크

profile
sang kwon seo

0개의 댓글