[Monorepo] yarn workspace 모노레포 환경 내의 컴포넌트가 다른 패키지에서 import 되지 않을 때 해결법 (@babel/runtime)
1. 문제 상황
프로젝트를 시작하면서 yarn berry workspace를 통해 모노레포 환경을 구축하였다.
위 그림과 같이 프로젝트의 주요 목표가 될 '서비스 어플리케이션'들끼리 공통적으로 사용할 컴포넌트들을
package 폴더 안에 '공통 컴포넌트 패키지'로 만들어 컴포넌트 재사용성을 높이고자 하였다.
Cannot find module babel-preset-react-app/node_modules/@babel/runtime/helpers/slicedToArray
그러나 다음과 같은 메시지를 뱉으며 불러오지 못하는 문제를 겪었다.
2. 원인 진단
별도의 레포지토리의 컴포넌트를 import 한 것이 아니라 모노레포 였음에도 불구하고,
컴포넌트를 불러오지 못한 이유가 무엇일지 궁금했다.
그래서 문제가 될만한 요소들을 확인하였다.
2-1. 컴포넌트 패키지에서 export를 누락한 것이 없는지 확인한다.
공통 컴포넌트 패키지에서 export되길 원하는 컴포넌트들을 잘 export 했는지 확인하였다.
각 컴포넌트들을 index.tsx로 묶어서 전체 컴포넌트들을 default로 내보냈다.
export { default as Avatar } from './Avatar';
export { default as Button } from './Button';
export { default as Form} from './Form';
모듈 export 상의 누락 문제는 없는 것으로 확인되었다.
2-2. 필요한 의존성 항목이 없는 것인지 확인한다.
'@babel/runtime' 의존성 항목이 서비스 어플리케이션에서 필요한 것으로 판단되었다.
그렇다면 @babel/runtime은 무엇인가?
@babel/runtime은 바벨의 런타임 라이브러리로서, 프로그램이 실행되는 동안에 필요한 함수들을 지원한다. 이를테면 es6에서 도입된 클래스를 es5이전 환경에서 구동할 수 있게끔 변환해주는 함수 등이 @babel/runtime에 포함되어있다.
플러그인으로서 추가하여 사용하게 되면 @babel/plugin-transform-runtime과 동일하다고 볼 수 있다..
그렇다면 왜 컴포넌트 패키지에서는 잘 트랜스파일링 되는데, 서비스 어플리케이션 환경에서는 트랜스파일링되지 않는 것인가?
그것은 바로 yarn berry의 특성 때문이다. yarn berry는 필요한 의존성 패키지를 탐색할 때 node_modules와는 다른 방식으로 탐색한다.
npm은 하위 패키지와 상위 패키지가 의존성이 겹치게 될 때 오른쪽과 같이 의존성 트리를 변경하고 하위 패키지가 상위 패키지로 거슬러올라와 해당 의존성을 참조하게끔 한다. 하위의 의존성이 끌어올려지는 듯하여 이를 호이스팅된다고도 한다. (자바스크립트의 호이스팅과는 다름)
이러한 방식은 중복되는 의존성을 제거하고 메모리 용량을 save할 수 있다는 장점이 있다. 그렇지만 의존성 관리를 햇갈리게 하고 의존성 사양에 변경이 발생하면 에러 가능성이 있다. (유령 의존성 문제)
yarn berry도 중복된 의존성 설치를 하진 않지만 symlink를 통해 의존성 package를 개별적으로 관리하는 덕에 각각의 패키지가 독립적인 의존성을 유지할 수 있게 해준다. 한마디로 호이스트되어 찾는 방식이 아니게 된거다.
다시 본론으로 돌아가자면, nohoist가 활성화된 yarn berry의 특성으로 인해 추가하지 않은 종속성에 대해 임의로 탐색하지 않아 런타임 환경에서 실행 시 서비스 어플리케이션에서 공통 컴포넌트 패키지의 컴포넌트를 불러오지 못한 것이라는 원인 진단을 내릴 수 있었다. 공식문서(하단 참조 링크 참고)에서도 Module not found 에러가 발생할 수 있으며 이것이 (구조적으로) 고쳐질 수 없는 것임을 설명하고 있다.
3. 해결방법
3-1. 루트 디렉토리에 @babel/runtime을 설치한다.
모노레포 루트에 있는 package.json에 '@babel/runtime'을 의존성 항목에 추가하였다.
yarn add @babel/runtime
그 결과, 컴포넌트가 서비스 어플리케이션에서 정상적으로 import 될 수 있었다.
하지만, 향후 개발단계에서 비슷한 이유로 트랜스파일링 과정에서의 문제 발생이 우려된다.
이를 선제적으로 대비하기 위해서는 개별 패키지/어플리케이션 내부로 들어가서 빠진 종속성 항목이 있는지, .babelrc에서 추가할 속성이 있는지 살펴보고 좀 더 넓은 커버리지를 갖고 있는 @babel/preset을 추가하는거나 필요할 것으로 예상되는 플러그인을 설치하는 것이 더 좋을 것 같다.
참고한 글
https://babeljs.io/docs/babel-runtime
@babel/runtime · Babel
@babel/runtime is a library that contains Babel modular runtime helpers.
babeljs.io
https://techblog.woowahan.com/7976/
Yarn berry workspace를 활용한 프론트엔드 모노레포 구축기 | 우아한형제들 기술블로그
{{item.name}} 안녕하세요 우아한형제들 딜리버리프로덕트실 DH로컬라이징스쿼드 입니다. 저희 조직에서는 백오피스 애플리케이션, 크로스플랫폼 모바일 애플리케이션 등 다양한 프론트엔드 프로
techblog.woowahan.com
https://github.com/facebook/create-react-app/issues/7183
Cannot find module babel-preset-react-app/node_modules/@babel/runtime/helpers/slicedToArray · Issue #7183 · facebook/create-re
Error Message on the terminal: Cannot find module '/Users/pehhuishi/code/react/practice/react-practice/node_modules/babel-preset-react-app/node_modules/@babel/runtime/helpers/slicedToArray Not sure...
github.com
https://toss.tech/article/node-modules-and-yarn-berry
node_modules로부터 우리를 구원해 줄 Yarn Berry
토스 프론트엔드 레포지토리 대부분에서 사용하고 있는 패키지 매니저 Yarn Berry. 채택하게 된 배경과 사용하면서 좋았던 점을 공유합니다.
toss.tech
https://classic.yarnpkg.com/blog/2018/02/15/nohoist/
nohoist in Workspaces
As wonderful as yarn workspaces are, the rest of the community hasn’t yet fully caught up with the monorepo hoisting scheme. The introducing of the nohoist i...
classic.yarnpkg.com
'Frontend' 카테고리의 다른 글
[React] ref와 useRef 훅 (0) | 2024.02.16 |
---|---|
[@tanstack/react-query] Query Status와 Fetch Status (0) | 2024.01.29 |
[Javascript] 이터러블과 이터레이터 프로토콜 (2) | 2024.01.25 |
[TypeScript] '타입스크립트가 정적 트랜스파일링 언어이다' 라는 것의 의미 (2) | 2024.01.10 |
[javascript] 배열에서 특정 인덱스를 삭제하고 새로운 배열을 만드는법 (0) | 2023.12.14 |