ryong.logryong.log
Yarn Berry 도입하기 배너
2023년 11월 16일·읽는 데 약 4분

Yarn Berry 도입하기

관련 글

음성인식 기반 스마트 민원서식 키오스크 서비스 개발 및 운영

2023. 10. 19.

OpenRun

2023. 10. 12.

Moong Trip

2024. 3. 5.

Yarn Berry 도입

npm의 비효율적인 node_modules 설치와 관리, 유령 의존성과 같은 단점을 보완하기 위하여

yarn berry를 도입하기로 결정하였고, yarn berry를 도입하면서 기대하는 이점은 아래와 같다.

  • CI/CD 시간 단축 (install 및 build)
  • 유령 의존성 문제 해결
  • node_modules에서 zip 파일로 의존성을 관리하면서 간소화된 폴더 사이즈
  • 새로운 의존성 설치 시 유용한 플러그인 기능

프로젝트 구조 설명

전체적인 큰 틀과 흐름은 비슷하지만 프로젝트를 관리하는 폴더 구조에 따라서 조금씩 달라지기 때문에 해당 게시글의 기반이 되는 프로젝트 구조를 첨부하면 다음과 같다.

📁 root
📁 app
📁 frontend (Node.js)
📁 templates (React)
📄 package.json
📄 package.json
📁 backend

우리의 목표는 npm으로 관리하던 React 프로젝트만 yarn berry로 마이그레이션하고, Node.js 서버는 npm으로 유지하는 것이다.

yarn 설치하기

우선, GitLab에서 의존성 설치가 되어 있지 않은 파일을 다운로드 받고 프로젝트 루트에서 vscode를 연다.

다음으로, 상단 폴더 구조에 따라 app/frontend/templates/ 폴더로 이동한다.

powershell
Copied
1$ > cd app/frontend/templates

다음으로, 불필요한 폴더와 파일들을 삭제한다.

  • app/frontend/templates/node_modules/
  • app/frontend/templates/package-lock.json

다음으로, 이동한 폴더에서 yarn 버전을 berry로 변경해준다.

powershell
Copied
1$app/frontend/templates > yarn set version berry

위 명령어를 실행하면 templates 폴더에만 변화가 생기는 것이 아닌 frontend 폴더에도 변화가 생기는데,

이는 yarn이 package.json이 존재하는 최상단의 루트 경로를 찾아서 해당 경로에 세팅을 해주게 되기 때문이다.

frontend 폴더에 세팅된 yarn 파일과 옵션들을 templates 폴더로 이동시켜주는 다음 과정을 따라하자.

  1. frontend/.yarn/releases/yarn-3.6.3cjs 파일을 frontend/templates/.yarn/releases/ 폴더 아래로 이동시킨다.
  2. 파일을 이동시키고 난 후, 파일이 비어있는 frontend/.yarn/ 폴더는 삭제해준다.
  3. frontend/.yarnrc.yml 파일도 frontend/templates/ 폴더 아래로 이동시킨다.
  4. frontend/package.json 파일의 마지막에 추가된 코드를 frontend/templates/package.json 파일로 옮겨 적고 frontend/package.json 파일을 원래대로 돌려놓는다.
      json
      Copied
      1{2	// ...3	"packageManager": "yarn@3.6.3"4}
  5. frontend/templates/ 폴더에 비어있는 yarn.lock 파일을 추가한다. 이를 추가하지 않으면 아래와 같은 에러가 발생한다.


위 과정들 모두 마치고 나면 본격적으로 의존성 설치를 진행한다.

yarn berry 3.6.3 버전의 경우 기본적으로 pnp 방식으로 의존성을 해결하므로, .yarnrc.yml 파일에 속성을 추가해줄 필요는 없다.

powershell
Copied
1$app/frontend/templates > yarn install

설치를 완료하면 yarn.lock 파일이 채워지면서 다음과 같은 폴더와 파일들이 추가된 것을 확인할 수 있다.

  • .yarn/cache/ : 압축된 dependencies들이 위치한 곳
  • .pnp.cjs : Plug’n’Play module resolver, dependencies들을 찾을 수 있는 정보가 기록된다.

      디스크 I/O 없이 어떤 패키지가 어떤 라이브러리에 의존하는지, 각 라이브러리는 어디에 위치하는지를 바로 알 수 있다.

  • .yarn/**
  • .pnp.loader.mjs

명령어 스크립트 변경하기

React 프로젝트의 패키지 매니저가 npm에서 yarn으로 변경되었으니, npm으로 실행하던 명령어를 yarn으로 변경해야 한다.

우리 프로젝트에서는 /app/frontend/package.json에서 Node 서버가 실행되면서 React를 띄워주고 있었으므로, /app/frontend/package.json 파일의 script를 다음과 같이 변경해줘야 한다.

json
Copied
1{2	{3		"scripts": {4			"start": "concurrently \"npm run start:srv\" \"npm run start:cli\"",5	    "start:srv": "nodemon app",6	    "start:cli": "cd templates && yarn start",7	    "build:cli": "cd templates && yarn build",8	    "install:cli": "cd templates && yarn install",9		}10		// ...11}

Node 서버에서 실행시킬 명령어는 npm run *으로 유지하고, React 서버를 실행시킬 명령어만 npm run에서 yarn으로 변경했다.

프로젝트 실행해보기

이제 frontend 폴더에서 npm install로 Node 의존성을 설치해 준 다음 프로젝트를 실행시켜보자.

json
Copied
1$app/frontend > npm run start

실행 결과, 무시무시한 에러들이 등장했다.

이슈 트래킹을 하기 위해 에러 메시지로 등장한 VirtualTable.tsx라는 임의의 파일로 가봤더니 아래 이미지와 같이 외부 라이브러리 모듈을 모두 참조하지 못하고 있는 것을 발견했다.

이슈 트래킹 1 : 타입스크립트 버전 이슈

우선 해당 문제는 타입스크립트 버전 이슈로, yarn 공식 문서에서는 다음과 같은 단계를 따르라고 권장하고 있다.

  1. Yarn Team에서 관리하는 VSCode ZipFS Extension을 설치한다.
  2. .vscode/settings.json 파일을 생성할 수 있도록 다음과 같은 명령어를 실행한다.
      json
      Copied
      1$app/frontend/templates > yarn dlx @yarnpkg/sdks vscode

      해당 명령어를 실행시키면 app/frontend/templates/.vscode/ 폴더에 아래와 같은 두 개의 파일이 추가된 것을 볼 수 있다.

  3. 안전 상의 이유로 VSCode에서 명시적으로 커스텀 TS 세팅을 활성화해준다. 단계는 아래와 같다.
      1. 타입스크립트 파일을 클릭하고, ctrl + shift + p를 눌러 VSCode 명령어 팔레트를 실행시킨 후,
      2. Select TypeScript Version을 검색하고
      3. Use Workspace Version (작업 영역 버전 사용)을 선택한다.


하지만.. 여기까지 잘 따라온 독자라면 아무리 찾아도 작업 영역 버전 사용이라는 탭이 보이지 않는 것을 확인할 수 있다.

참고로 우리가 선택해야 하는 타입스크립트 버전은 4.9.5 버전이다.

무엇이 문제일까? 그리고 왜 이전에는 이런 문제가 발생하지 않았던 것일까?

이슈 트래킹 2 : 폴더 구조 때문

이전에 npm으로 관리하던 프로젝트에서는 typescript 버전을 따로 관리하거나 선택하지 않아도 전혀 문제가 되지 않았다.

이는 npm 패키지 매니저로 실행시킨 CRA 프로젝트는 node_modules/ 폴더 안에 있는 타입스크립트 버전을 추적해서 해당 버전으로 실행을 시키기 때문이다.

하지만, yarn berry 정책 상 타입스크립트 버전을 명시적으로 선택해 줘야 하기 때문에 전역으로 설치된 타입스크립트 버전과 프로젝트 워크스페이스 내부의 버전이 달라서 문제를 직면하게 된 것이다.

만약, 전역으로 설치된 타입스크립트의 버전을 4.9.5로 다운그레이드하면 문제가 해결될 수도 있다.

하지만, 이는 좋은 방법은 아닌 것으로 생각이 든다.

많은 서치 끝에 아래와 같은 게시글을 만날 수 있었다.

위 해결책을 우리 프로젝트에 적용해보면, 프로젝트 루트가 React 프로젝트 루트가 아니기 때문에 app/frontend/templates/ 폴더를 루트로 하는 VSCode를 열어보면 문제가 해결될 여지가 있는 것이다.

json
Copied
1$app/frontend/templates > code .

예상했던 대로 타입스크립트 파일을 선택한 후, 타입스크립트 버전 선택을 들어가보니 “작업 영역 버전 사용”이 선택 가능한 상태로 되었다!

그리고 이를 선택했더니 에러가 거짓말 처럼 사라졌고,

라이브러리를 타고 들어가도 라이브러리 코드를 예전과 같이 확인할 수 있다.

흥미로운 점은 react 라이브러리를 타고 들어가서 파일의 경로를 확인해보면 아래와 같다.

rktk\app\frontend\templates\.yarn\cache\@types-react-npm-18.2.22-bd0a04edf5-44289523da.zip\node_modules\@types\react\ts5.0\index.d.ts

이는 앞서 설치한 ZipFS Extension 덕분에 zip 파일을 타고 들어가서 코드를 확인할 수 있게 된 것이다.

아쉬운 점은 위 이미지에서 여전히 rc-resize-observer, lodash의 경우 의존성 모듈을 찾지 못하고 있는데, 이는 잠시 후에 다시 살펴볼 예정이다.


위에서 간접적으로 해결한 문제를 원래 작업하던 환경(root 경로, 글로벌 타입스크립트 버전)을 그대로 한 채로 해결할 수 있는 방법은 없을까?

.vscode/settings.json 파일의 속성 중에 typescript sdk를 참조하는 경로가 있다는 것을 확인했다.

VSCode의 루트가 서로 달라서 워크스페이스 내 타입스크립트 선택이 안 되었던 문제였으므로, .vscode를 루트로 올리고 sdk를 참조하는 경로를 바꾸면 해결이 되지 않을까?

.vscode/ 폴더를 프로젝트 루트로 이동시킨 후, .vscode/settings.json 속성을 아래와 같이 변경해보았다.

그리고 VSCode를 재부팅 했더니 아래와 같이 성공적으로 경로를 읽은 모습이 보인다!!

그리고 성공적으로 의존성을 참조할 수 있는 상태가 되었다.

플러그인 설치

추가적인 문제 해결에 앞서 yarn berry 플러그인 설치를 하나 진행하고 가자.

json
Copied
1$app/frontend/templates > yarn plugin import typescript

해당 플러그인은 타입스크립트 외부 모듈을 설치 시, devDependencies에 @types/*를 따로 추가로 설치해 줘야 하는 것을 자동으로 설치해 주는 플러그인이다.

이슈 트래킹 3 : 유령 의존성

위에서 보였던 참조 에러 라이브러리인 rc-resize-observer, lodash는 알고보니 package.json에 없는 유령 의존성이었던 것이다!!

이와 같이 유령 의존성을 참조하고 있는 것들을 해결하기 위해서 아래에 해당하는 라이브러리들을 추가로 설치했다.

json
Copied
1{2	"dependencies": {3		"@ant-design/icons": "^5.2.6",4		"@nivo/colors": "^0.83.0",5		"@nivo/tooltip": "^0.83.0",6		"d3-scale": "^4.0.2",7		"lodash": "^4.17.21",8		"rc-resize-observer": "^1.3.1",9		"react-is": "^18.2.0",10		"redux": "^4.2.1",11	},12	"devDependencies": {13		"@types/d3-scale": "^4",14		"@types/lodash": "^4",15		"@types/prettier": "^3",16		"@types/react-is": "^18",17		"prettier": "^3.0.3",18	}19	// ...20}21		

설치가 완료되니 모든 에러 메시지들이 사라진 것을 볼 수 있다.

로컬 파일 관리

yarn berry를 도입하면서 생긴 루트에 추가해야 하는 .vscode/ 폴더 내 파일들은 아래와 같다.

📁 .vscode
📄 .prettierignore
shell
Copied
1../backend/*2../test/*
📄 extensions.json
json
Copied
1{2  "recommendations": [3    "arcanis.vscode-zipfs",4    "dbaeumer.vscode-eslint"5  ]6}
📄 settings.json
json
Copied
1{2  "search.exclude": {3    "**/.yarn": true,4    "**/.pnp.*": true5  },6  "eslint.nodePath": "app/frontend/templates/.yarn/sdks",7  "typescript.tsdk": "app/frontend/templates/.yarn/sdks/typescript/lib",8  "typescript.enablePromptUseWorkspaceTsdk": true,9  "editor.defaultFormatter": "esbenp.prettier-vscode",10  "editor.formatOnSave": true,11  "editor.codeActionsOnSave": {12    "source.fixAll.eslint": true13  },14  "prettier.ignorePath": ".prettierignore"15}

Zero-Installs

node_modules에 비해 의존성 파일들의 크기가 현저히 작아지면서 아예 의존성 파일까지 Git으로 관리하여

CI/CD 시 install 하는 시간까지 절약하는 Zero-Installs 방법이 있다.

이를 반영할 지, 반영하지 않을 지에 대한 .gitignore 파일 설정은 아래와 같다.

Questions & Answers | Yarn

A list of answers to commonly asked questions.

yarnpkg.com/getting-started/qa

↗

Zero-Installs 설정

shell
Copied
1.yarn/*2!.yarn/cache3!.yarn/patches4!.yarn/plugins5!.yarn/releases6!.yarn/sdks7!.yarn/versions
  • Zero-Install 설정 시, 버퍼 사이즈 제한에 의해 업로드가 되지 않는 현상이 발생하면, 아래와 같이 터미널의 버퍼 사이즈를 늘려줘야 한다.
      shell
      Copied
      1git config --local http.postBuffer 157286400

Zero-Installs 설정 안 함

shell
Copied
1.pnp.*2.yarn/*3!.yarn/patches4!.yarn/plugins5!.yarn/releases6!.yarn/sdks7!.yarn/versions

성능 비교

기준 커밋 SHA 7d9d72b250728b8338405c6e477a5f8a1189cb1a

의존성 설치 시간

npm 1분 9초 468
yarn berry 38초 466

빌드 시간

npm 2분 18초 674
yarn berry 47초 586

의존성 파일 용량

npm 615MB
yarn berry 155MB
  • Yarn Berry 도입하기
  • Yarn Berry 도입
  • 프로젝트 구조 설명
  • yarn 설치하기
  • 명령어 스크립트 변경하기
  • 프로젝트 실행해보기
  • 이슈 트래킹 1 : 타입스크립트 버전 이슈
  • 이슈 트래킹 2 : 폴더 구조 때문
  • 플러그인 설치
  • 이슈 트래킹 3 : 유령 의존성
  • 로컬 파일 관리
  • Zero-Installs
  • 성능 비교