react와 같이 node.js 기반으로 개발하다보면, 여러 패키지를 설치해서 사용하게 됩니다. 그리고 그러다 보면, 기존 패키지의 코드를 수정해서 사용해야 하는 경우가 생깁니다! 이럴 때는 어떻게 해야 할까요?

미련했던 옛 시절⌗

현재 작업 중인 프로젝트에서는 webrtc 기반으로 코드 에디터의 내용을 동기화 하는 기능을 구현했었습니다. 그러다 보니 오픈소스 패키지를 사용하다가 필요한 기능을 넣기 위해 패키지를 수정할 필요가 있었죠. 그래서 고민하다가… node_modules 폴더에서 해당 패키지의 소스 코드를 찾아서 그걸 /src/lib 폴더에 복사해두고 직접 수정했습니다! 그리곤 설치된 패키지를 import 하는 대신에 /src/lib에 복사해서 수정한 파일을 import 하는 방식으로 구현했죠.

물론 이 방법에도 장점은 있습니다. 간단하죠! 그리고 디버깅도 쉽습니다. 코드가 내 프로젝트 안에 있으니까요. 그런데 이 작업을 할 당시에도 "나중에 시간이 좀 지나서 패키지를 업데이트해야 되면, 일일이 변경점을 찾아서 수정해야 되나...?" 하는 불안감은 있었지만 그런 걸 생각할 여유가 아예 없었기 때문에 그냥 그대로 뒀습니다.

기술적 부채는 결국 돌아온다!⌗

그렇게 대충 마무리를 하고 2년이 지났고, 그 프로젝트를 다시 들여다 보고 있었습니다. 어떻게든 회사가 죽지 않고 버티다 보면 신기하게도 이미 수명이 끝났다고 생각했던 솔루션이 다시 부활하게 되는 순간이 오곤 합니다. 네, 지금이 그런 순간이었던 거죠. 거의 포기했던 솔루션을 다시 봐야 하는 상황인거죠. 개발자라면 이때의 막막한 심정을 공감하실 겁니다. 본인이 막대한 노력을 들여서 일을 장황하게 벌여놨지만, 시간이 한참 지나서 그걸 다시 스스로 수습해야 하는 상황말이죠…

어쨌거나 그 당시에 넘쳐나던 요구사항을 쫓아가기 급급하면서 계속 새로운 기능을 공장처럼 찍어냈고, 여러가지 사정으로 인해 그 기능들은 제대로 테스트 과정을 거치지도 못한 채 방치되었습니다. 빚을 내면서 빨리 개발했지만, 그 빚을 갚지 못하면서 이자만 눈덩이 처럼 불어난 셈이죠. 패키지 파일을 /src/lib에 복사했던 건 수 많은 부채 중의 하나였습니다.

좀 더 우아한 방법이 없을까?⌗

이 문제에 대해 위대하신 ChatGPT님과 대화하다 보니, 여러가지 방법이 있지만 가장 간단한 건 patch-package를 활용하는 방법이라는 걸 알게되었습니다. 그러니까, node_modules/some-package/src/source.js 파일을 직접 수정하고, npx patch-package some-package 명령을 실행하면, 원래 패키지에서 변경된 점을 찾아서 patches 폴더에 기록하고 패키지를 새롭게 빌드해줍니다. patches 폴더에 기록된 내용을 들여다보면 대충 다음과 같은 내용입니다.

diff --git a/node_modules/some-package/src/source.js b/node_modules/some-package/src/source.js
index c0fc343..92a2941 100644
--- a/node_modules/some-package/src/source.js
+++ b/node_modules/some-package/src/source.js
@@ -97,6 +97,7 @@ someArray[someIndex] = (

 // @todo - blah blah some original source code
 const someVariable = 30000
+const someOtherVariable = 4000;

게다가! package.json의 scripts에 postinstall 스크립트를 추가하면, 패키지를 설치할 때마다 자동으로 패치 파일을 적용해줍니다.

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

패키지를 새로 설치할 때 마다 수작업으로 변경사항을 적용할 필요가 없는 거죠! 다만, patch 파일 이름(some-package+0.1.6.patch) 에서도 알 수 있듯이 패키지의 버전이 바뀐다면 패치는 자동 적용되지 않습니다. 그럴 때는 다음과 같이 파일의 이름을 변경하고 다시 시도해볼 수 있습니다.

# 패키지 버전이 0.1.6에서 0.1.7로 바뀌었다고 가정해봅니다.
> cp patches/some-package+0.1.6.patch patches/some-package+0.1.7.patch
# 패치를 적용해봅니다.
> npx patch-package

만약 패키지가 업데이트 되면서 패치와 관련된 코드가 변경되었다면 패치는 실패하며 그때는 패치를 새로 만들어야 합니다. 이 방법도 만능은 아닌 셈이죠. 그래도 현 시점에서 가장 간단하면서도 우아하게 적용할 수 있는 방법이었습니다.