pile·
프론트엔드·레모네이드레모네이드·

Yarn Workspace를 이용한 Monorepo 구성

패스트캠퍼스 랭귀지 팀이 학생용·강사용 프론트엔드가 같은 컴포넌트를 공유하도록 디자인된 상황에서, 별도 저장소 대신 모노레포를 택하고 Yarn Workspace 로 정착하기까지의 시행착오다. 처음엔 디렉터리만 나눠 상대 경로로 import 했다가 두 번의 에러를 만나 도구가 필요해진 과정을 그대로 보여준다.

핵심 포인트
  • 모노레포 도구들이 무거워 보여 처음에는 `common`, `student`, `teacher` 디렉터리로만 나누고 상대 경로 import 로 연결했다.
  • 첫 번째 벽은 `unexpected token`. Next.js 는 빌드 시 프로젝트 디렉터리 안의 파일만 트랜스파일해서 외부의 `common` 이 제외됐다.
  • `next-transpile-modules` 를 `next.config.js` 에 적용해 외부 모듈도 트랜스파일되게 했고, 다른 플러그인과 겹치면 `withTM()` 을 가장 바깥에 둔다.
  • 두 번째 벽은 React 인스턴스 중복. 패키지 관리도구를 거치지 않아 의존성이 따로 관리되면서 `common` 이 또 다른 React copy 를 만들었다.
  • Yarn Workspace 는 각 워크스페이스를 패키지처럼 의존성으로 연결하고 공통 의존성을 루트 `node_modules` 로 hoist 해 이 문제를 푼다.
상세 정리
  • 배경: Fastone Online 프로젝트에는 학생·강사·관리자 세 프론트엔드가 있고, 디자인 단계에서부터 학생과 강사가 같은 컴포넌트를 공유하도록 만들어져 크기·레이아웃만 바꾸면 될 것으로 봤다.
  • 공용 컴포넌트를 별도 저장소로 빼는 안도 검토했지만 관리가 쉽지 않을 것 같아 모노레포로 방향을 잡았다.
  • 상대 경로 import 자체는 잘 됐다. 한 저장소 안이라 경로를 바꿀 필요도 없어 처음엔 쉬워 보였다.
  • 버전만 다른 공통 패키지는 hoist 되지 않고 해당 워크스페이스의 `node_modules` 에 설치된다는 규칙도 짚는다.
  • 적용 후 구조는 이전과 같고 루트에 `package.json` 이 하나 더 생긴다. 여기에 `workspaces` 경로와 공통 패키지를 적는다.
  • 루트 `package.json` 에는 `private: true` 를 넣는다. 워크스페이스는 배포 대상이 아니므로 실수로 공개되지 않게 하라는 공식 문서 권고를 인용한다.
  • 실행 스크립트는 `yarn workspace student dev` 형태로 감싸 `dev:student`, `build:student`, `test:student` 등을 루트에 모아 뒀다. 각 프로젝트 폴더로 이동하지 않아도 된다.
  • 의존성으로 연결한 뒤에는 경로가 아니라 `common` 의 `package.json` 에 적은 name 으로 import 한다. `import { Button } from "common"` 처럼 일반 라이브러리와 똑같이 쓰인다.
  • `next-transpile-modules` 설정도 `["../common"]` 에서 `["common"]` 으로 바뀐다.
  • 배포는 Google Cloud Build 와 Docker 를 쓰고 있어, 루트 `package.json` 의 scripts 와 Dockerfile 의 yarn 명령을 손보는 정도로 가능할 것으로 본다.
  • 회고: 심볼릭 링크로 가볍게 끝내려 했지만 예상 못 한 오류들 때문에 못 했고, Yarn Workspace 가 생각보다 가벼워 전화위복이 됐다고 정리한다.
왜 읽나Next.js 프로젝트 여러 개가 컴포넌트를 공유해야 할 때, 도구 없이 시작하면 어디서 막히는지와 Yarn Workspace 가 정확히 무엇을 해결하는지 알려준다.
레모네이드
레모네이드 블로그
원문은 여기서 이어서 읽을 수 있어요
원문 읽기
읽음 (0)

이 글과 비슷한

  1. 프론트엔드·여기어때 (GC컴퍼니)여기어때 (GC컴퍼니)·

    항공 프론트엔드 구축기 (7/10): 창구를 하나만 두었습니다

    여기어때 항공 서비스 프론트엔드가 웹과 앱 웹뷰 두 환경에서 동일한 함수 호출로 동작하는 앱 브릿지 추상화 레이어를 설계한 과정을 다룬다. iOS·안드로이드 규약 차이와 "웹에 존재하지 않는 브릿지를 어떻게 호출하나"라는 문제를 단일 추상화 층으로 해결한 구현 사례다.

    요약 이어보기
    #react#typescript#webview+2