thumbnail

bun으로 monorepo 구현을 포기한 이유

생성일2024. 1. 29.
태그
작성자지한솔

notion image
A라는 서비스의 디자인 시스템을 유지하면서 B라는 새로운 서비스를 개발하고자 하는 단순한 호기심에서 시작된 저의 여정은, 적절한 컴포넌트와 로직의 분리를 통해 이를 달성하고자 하는 목표로 이어졌습니다. 이를 위해 저는 모노레포 환경을 구축하기로 결정하였고, 이 과정에서 많은 삽질을 했습니다.
모노레포 방식에는 lerna, yarn berry 등 다양한 레퍼런스가 존재하나, 저는 bun.js를 활용하고자 하는 생각에 이끌렸습니다. 그 이유는 bun.js의 간결하고 직관적인 특성, 그리고 빠른 올인원 JavaScript 런타임 및 툴킷으로서의 강점이 마음에 들었기 때문입니다. 이로 인해 저는 bun.js를 활용한 모노레포 구축의 길로 들어서게 되었습니다.

Bun.js 를 선택한 이유

bun.js를 선택하여 모노레포를 구현한 이유는 크게 세 가지입니다.
첫 번째로, Bun.js는 자신을 가장 빠른 올인원 JavaScript 런타임 및 툴킷으로 소개하며, 그 자신감이 마음에 들었습니다. 자신감 있는 도구는 그만큼 사용자에게 신뢰를 줄 수 있습니다. 이런 점이 bun.js를 선택하는 데 큰 동기가 되었습니다.
두 번째로, Bun.js는 간단하고 쉬운 workspace 방식을 제공한다고 합니다. 이는 복잡한 프로젝트 구조를 관리하고자 하는 제 목표와 잘 맞아떨어졌습니다. 또한, 이런 특성은 코드의 가독성과 유지 보수성을 높이는 데 크게 기여할 것이라고 생각했습니다.
세 번째로, Bun.js의 심플한 로고인 작고 소중한 만두는 그 자체로도 저를 사용하게 만들었습니다. 이런 디테일은 bun.js의 유저 경험에 대한 신경 쓰임을 보여주며, 이는 bun.js를 신뢰하는 데 큰 도움이 되었습니다.
notion image
개인 프로젝트를 bun으로 작업했을 때, 그 속도와 편리성이 상당히 좋았습니다. 메이저 버전이 새롭게 올라온 것에 대한 걱정은 있었지만, 패키지 매니저 정도의 활용에 큰 문제가 없을 것이라고 생각하며 bun.js를 선택하게 되었습니다.

Bun.js로 프로젝트 만들기

구조 설계

notion image
저의 모노레포 구조 설계는 다음과 같습니다:
  1. 공통으로 관리될 패키지는 Root Directory를 통해 의존성을 관리합니다. 이는 공통 패키지의 버전 관리를 효율적으로 하기 위함입니다.
  1. Apps Directory에 있는 프로젝트는 Libs의 공용 컴포넌트를 참조하여 작업을 진행합니다. 이는 컴포넌트의 재사용성을 높이고, 코드의 중복을 최소화하기 위한 방법입니다.
  1. Libs는 필요한 스타일 라이브러리를 설치해 컴포넌트를 만드는 것에 집중하고, React Project는 그것을 사용하는 것에만 집중합니다. 이는 역할 분리를 통해 개발의 효율성을 높이기 위함입니다.
  1. ESLint, Prettier는 전역에서 관리합니다. 이는 코드의 일관성을 유지하고, 팀원 간의 협업을 원활하게 하기 위한 방법입니다.
이러한 규칙을 세우고, 이를 바탕으로 프로젝트를 구성하였습니다. 이 과정에서 여러 시행착오를 겪었지만, 정말 많은 경험치를 얻었다고 생각합니다.

workspace 설정

bun.js를 이용하여 workspace를 구성하는 과정은 매우 간단했습니다. bun init 명령어를 통해 bun 프로젝트를 생성하고, root package.json에 workspaces를 설정함으로써 간단히 workspaces를 생성할 수 있었습니다.
# bun 프로젝트 생성 bun init
// Root package.json { "name": "monorepo", "module": "index.ts", "type": "module", // workspace 생성 "workspaces": [ "libs", "apps/vite-react" ], "devDependencies": { "@types/bun": "latest" }, "peerDependencies": { "typescript": "^5.0.0" } }
bun install
위 처럼 root package.json 을 설정하고 실행하면 아래처럼 libs와 vite-react 를 workspace 로 만들어줍니다.
+ libs@workspace:libs + vite-react@workspace:apps/vite-react
그럼 이제, libs에서 emotion css를 활용하여 공용 컴포넌트를 만드는 작업을 진행해보겠습니다. 이를 위해 emotion css를 libs 폴더에서만 사용할 수 있도록 libs에 패키지를 설치하였습니다.
# libs bun add @emotion/styled @emotion/react
그러나 이 과정에서 예상치 못한 문제가 발생하였습니다. libs에 패키지를 설치했음에도 불구하고, 해당 라이브러리가 libs의 node_modules에 설치되어 있지 않고 root의 node_modules에 설치된 것을 확인하였습니다.
이는 패키지의 버전 관리가 코드 변화의 주요 원인이 될 수 있기 때문에 문제가 됩니다. 특히 메이저 버전이 올라가면서 변화가 크게 일어납니다.
notion image
이전에 emotion/react의 10.11.3 버전이 12.4.3 버전으로 올라오면서 사용방법이 바뀐다고 가정해 봅시다. 저희는 이전의 context 를 잊은채
bun add @emotion/react
명령어를 수행하였습니다. 그럼 이전에 node_modules 에 설치되어있던 10.11.3 버전을 새롭게 설치한 12.4.3 버전으로 덮어쓰여지게 됩니다. old-project는 새로운 버전에 호환되지 않는 옛날 코드를 유지하면서 에러가 발생하게 되고, 이전 버전을 사용하는 프로젝트가 많다면 더 많은 에러 수정을 진행하게 될 것입니다.
이런 문제를 해결하기 위해, emotion/react를 root에서 관리하는 방법을 고려해볼 수 있습니다. 그러나 이는 제가 세운 설계의 3번째 규칙을 위반합니다. 많은 프로젝트에서 사용하지 않는다면 전역에서 관리할 필요가 없고, 사용하는 프로젝트 내부에서 패키지 버전을 관리하는 편이 관리하기 더 쉽습니다.
Bun.js는 정말 빠르고 간단합니다. apps/vite-react는 libs의 코드를 참조하기 위해
"dependencies": { "libs": "workspace:../../libs", },
만 설정하면 될 정도로 모노레포 구성 방식이 심플하고 직관적입니다.
하지만, 장점이 명확한 만큼 단점도 명확했습니다. 모든 로컬 패키지가 root에 설치되는 이슈는 치명적이었습니다. 단기적으로는 문제가 되지 않겠지만, 장기적으로 운영하다 보면 이슈가 생길 수 있습니다.
저는 찾지 못했지만… 이 문제를 해결할 수 있는 방법이 있을 수 있습니다. 혹시 그 방법을 알고 계신다면 저에게 공유해주시면 감사하겠습니다.
 
다음 포스팅은 Yarn berry로 모노레포를 구현한 내용에 대해 작성해보려고 합니다. Yarn berry 는 많은 레퍼런스가 있었지만 정말 많은 이슈도 있었습니다. 작업하면서 생겼던 트러블 슈팅들을 정리해 공유하고, 다양한 개발자 분들의 의견을 듣고자 합니다.
 
감사합니다.