모노레포 common 패키지의 옛 코드가 반영되는 오류 수정 후기
2025년 10월 18일 오후 06:03
1. 분명히 코드를 업데이트했는데
지금 작업 중인 리액트 프로젝트는 pnpm의 Workspace 기능을 활용한 모노레포로 구성되어 있다. 리액트 프로젝트에서 pnpm build 명령어를 입력하면 php 프로젝트로 빌드된 js, css 파일이 올라가는 구조이다.
리액트 프로젝트에는 common 디렉토리가 있는데, 타입스크립트 코드를 트랜스파일링 해서 모듈로서 다른 프로젝트가 공용으로 사용할수 있도록 작동한다. 따라서 공용 모듈을 작성하고 싶다면 common 에 가서 작성후 export 한후 해당 디렉토리 내부에서 pnpm build 명령어를 실행하면 된다.
(프로젝트 루트의 package.json에는 다음과 같이 명령어가 설정되어 있었다.)
{
"name": "@something/root",
"private": true,
"scripts": {
"build:common": "pnpm --filter @something/common build",
"start:desktop-one": "pnpm --filter @something/desktop-one start",
"build:desktop-one": "pnpm --filter @something/desktop-one build",
"start:desktop-two": "pnpm --filter @something/desktop-two start",
"build:desktop-two": "pnpm --filter @something/desktop-two build",
...
"build:full": "pnpm -F @something/common -F @something/desktop-one -F (...) build"
},
"workspaces": [
"packages/*"
],
(...)
에러 발생 경위
- common 프로젝트의 코드를 업데이트하고 pnpm run build:full 명령어를 입력하여 다른 프로젝트의 코드들에 업데이트된 common 프로젝트의 코드가 반영되게 하였다. (브랜치 A에서 작업)
- 그리고 common 프로젝트의 코드가 업데이트 되기 전의 브랜치 B로 바꿔서 다른 작업을 실행했다.
- 다시 브랜치 A로 돌아와서, common이 아닌 프로젝트 ‘ㄱ’에서 작업 후 프로젝트 ‘ㄱ’을 빌드했다.
그리고 확인을 해보니 common에 1번 이전 코드가 반영되어 있었다. 왜 갑자기 common의 이전 코드가 반영이 된거지싶어서 롤백을 하면서 확인해보니 프로젝트 ‘ㄱ’을 빌드하고 나서부터 common 프로젝트의 옛 버전의 코드가 반영이 되었다. 왜 갑자기 이런 문제가 생긴 것일까? 브라우저 캐싱 문제인가? 문제를 재현해보기 위해서 새로 브랜치를 파서 1번 시점으로 롤백한다음, 바로 프로젝트 ‘ㄱ’만 빌드를 해보았다. 하지만 이 때에는 common 프로젝트의 최신 코드가 제대로 반영이 되었다. 그러면 무엇이 문제였을까?
2. 원인: dist는 깃에서 tracking하지 않는다
생각해보니 프로젝트 ‘ㄱ’을 빌드하기 전에 브랜치(common 프로젝트 코드를 업데이트 하기 전)를 바꿔서 작업을 했었다. 그리고 확실하지는 않지만, 그 때 full 빌드를 해서 common 프로젝트의 코드들이 빌드되었을 것이다. 그래서 dist 폴더에 이전 코드들이 저장이 되었을 것이다.
그리고 나는 브랜치를 다시 바꾸었다. dist에 있는 코드들은 깃에서 무시되기 때문에 브랜치를 바꾸었음에도 변경되지 않고 그대로 유지된다. 그리고 나는 프로젝트 ‘ㄱ’을 빌드했다. 이 때, dist에 있는 common 이전 코드들이 프로젝트 ‘ㄱ’에 적용되는 부작용이 발생한다.
참고: common 코드가 프로젝트 ‘ㄱ’에 반영되는 과정 요약
- Workspace 의존성 선언
// packages/'ㄱ'/package.json
"dependencies": {
"@something/common": "workspace:^0.0.0"
}
workspace:프로토콜로 로컬 패키지 사용 선언
- pnpm의 심볼릭 링크 생성
node_modules/@something/common → ../../common
pnpm install시 심볼릭 링크 자동 생성- 실시간으로 packages/common 디렉토리 참조
- Common 패키지의 진입점
// packages/common/package.json
{
"main": "dist/index.js",
"module": "dist/index.js",
"typings": "dist/index.d.ts"
}
- import 시 항상
dist/폴더의 빌드된 파일 참조
- 빌드 프로세스
// 'ㄱ'/src/App.tsx
import TopNav from '@something/common/dist/components/common/desktop/TopNav';
빌드 시 동작:
- Webpack이
@something/commonimport 발견 node_modules/@something/common심볼릭 링크 추적- packages/common 디렉토리 도달
- package.json의
main필드 확인 →dist/index.js packages/common/dist/폴더의 파일 읽기- 해당 코드를 ‘ㄱ’ 번들에 포함
3. 해결책: 빌드 시 항상 common 프로젝트를 먼저 빌드한다
요약하자면, 다른 브랜치에서 작업된 common 코드가 dist/에 반영되는데, 브랜치를 바꿀 때 이 내용들이 바뀌지 않고 그대로 따라와서 생기는 문제이다. 브랜치를 바꾸었을 때 common 프로젝트 (’src/’에 존재하는) 코드들은 깃에 tracking되기 때문에 common 프로젝트를 빌드한다면 dist/의 코드들이 최신 코드들로 바뀌게 된다.
→ 루트의 package.json 스크립트를 수정하자
{
"name": "@something/root",
"private": true,
"scripts": {
"build:common": "pnpm --filter @something/common build",
"start:desktop-one": "pnpm --filter @something/desktop-one start",
"build:desktop-one": "pnpm -F @something/common build && pnpm -F @something/desktop-one build",
"start:desktop-two": "pnpm --filter @something/desktop-two start",
"build:desktop-one": "pnpm -F @something/common build && pnpm -F @something/desktop-two build",
...
"build:full": "pnpm -F @something/common build && pnpm -F @something/desktop-one -F (...)"
},
"workspaces": [
"packages/*"
],
(...)
어떤 프로젝트를 빌드할 때마다 무조건 common 프로젝트를 빌드해서 dist/ 코드의 최신성을 보장했다. 이를 위해 script 앞에 “pnpm -F @something/common”을 입력하였고, common 프로젝트 빌드가 다 끝난 뒤에 다른 프로젝트 빌드를 시작해주기 위해 “&&”로 연결해주었다.
이번 문제가 발생했을 때, 처음에 왜 문제가 발생했는지 파악하지 못해서 꽤 애를 먹었었다. 처음에는 브라우저 캐싱이 원인이지 않을까 추측했기 때문에 엉뚱한 방향으로 디버깅을 했었다. 이번에 삽질을 하면서 common 프로젝트가 다른 프로젝트에 어떻게 반영되는지 과정을 살펴보며 이해할 수 있게 되었다. 이번 디버깅을 통해 앞으로common dist/ 코드들의 최신성을 보장할 수 있게 되어서 다행이라는 생각이든다.