VScode + yarn 2 + Monorepo + TypeScript 프로젝트 세팅

목표

  • yarn 2 를 사용하여 더 효율적으로 패키지 관리하기
  • 모노리포(Monorepo)에 발을 살짝 담구기
  • 타입스크립트 기반으로 프로젝트 구성하기 (이건 사실 이 글에선 중요하지 않음)

사전 준비

  • 타입스크립트를 하고 싶은 마음
  • vscode 를 에디터로 쓰고자 하는 마음
  • yarn 명령어 사전지식, yarn 을 선호하는 마음

아직 완벽하지는 않습니다. 특히 타입스크립트가 제대로 동작하는지에 대한 검증이 많이 필요합니다.. 일단 가장 기본적인 형태로 진행해 보았습니다. 기존 프로젝트를 업그레이드 하는 식이면 좀 더 많이 힘들 거라 예상..

그리고 저도 모노리포에 대해서 아는 바가 거의 없기 때문에 이게 모노리포가 맞나.. 싶습니다. 일단 레츠 기릿

✅ 소스코드: https://gitlab.com/EzKorry/yarn2-workspaces-typescript-boilerplate

업그레이드를 하는 이유

  • 패키지 받는 속도 빨라짐(필요한 것만 딱딱 받음)
  • install 속도 빨라짐, (심지어 install 필요가 없을 수도 있음. 제로인스톨 하게 되면.)
  • node 실행 속도 빨라짐.

그냥 yarn 과 비교했을 때 바뀌는 것

  • node_modules 가 사라짐. (띠용?)
  • 잡다구리한 파일들이 많이 생김

패키지 초기화 하하기

우선 만들 새로운 프로젝트 폴더를 만들고 들어갑시다.

mkdir new_project
cd new_project

아래 명령어로 현재 yarn 버전 확인.

yarn --version

1.x 일 경우 새로운 yarn 이 아닌 것임.

아래 명령어로 최신 yarn 으로 세팅해줍니다. 주의할 점은 아래 명령어는 새로운 프로젝트 폴더 내에서 실행해야 합니닷!

$ yarn set version berry && yarn set version latest
$ yarn --version
3.0.2

아무튼 여기 까지 왔으면 .yarn 폴더와 .yarnrc.yml 파일이 생겼을 것입니다.

이 상태에서 아래 명령어 실행

yarn init

하게 되면 아래와 같이 출력됩니다.

{
  name: 'test',
  packageManager: 'yarn@3.0.2'
}

여기까지 했을 때 생기는 파일들은 아래와 같습니다.

  • .yarn 폴더
  • .yarnrc.yml
  • .editorconfig
  • .gitignore
  • package.json
  • README.md
  • yarn.lock

아래는 .gitignore 내용입니다.

/.yarn/*
!/.yarn/patches
!/.yarn/plugins
!/.yarn/releases
!/.yarn/sdks

# Swap the comments on the following lines if you don't wish to use zero-installs
# Documentation here: <https://yarnpkg.com/features/zero-installs>
!/.yarn/cache
#/.pnp.*

zero-installs 를 간단히 이야기하면, 그냥 모든 패키지를 git 에 포함시켜서 git clone 만 해도 바로 실행시킬 수 있는 환경을 만들 수 있다, 뭐 그런 느낌입니다. 이걸 하기 싫으면 !/.yarn/cache/.pnp.* 를 주석 스왑하라고 하네요. 즉 주석 스왑을 하게 되면 둘다 .gitignore 에 포함되어 버전 관리가 안되고 리파지토리에도 올라가지 않습니다.

아래 명령어로 타입스크립트 패키지 설치합니다.

yarn add -D typescript

하게 되면 아래와 같은 출력이 나오고,

➤ YN0000: ┌ Resolution step
➤ YN0000: └ Completed in 0s 255ms
➤ YN0000: ┌ Fetch step
➤ YN0013: │ typescript@npm:4.4.4 can't be found in the cache and will be fetched from the rem
➤ YN0013: │ typescript@patch:typescript@npm%3A4.4.4#~builtin<compat/typescript>::version=4.4.
➤ YN0000: └ Completed
➤ YN0000: ┌ Link step
➤ YN0000: └ Completed
➤ YN0000: Done in 0s 461ms

.pnp.cjs 파일이 생깁니다. 갑자기 10,000줄짜리 파일이 생겼네요. 이 파일로 node 가 실제로 실행할 때 어떤 패키지를 어떻게 실행해야 하는지 알려준다고 합니다. 방식 이름은 pnp(플러그-앤-플레이. 주의: 컴활 시험에 나오는 거 아님) 자세한 건 잘 모름. 아무튼 의존성 관리의 일환임. 자세한 건 공식 문서를 봅시다!

타입스크립트 세팅

참고: https://yarnpkg.com/getting-started/editor-sdks#vscode

아래 명령어 위에서 했었죠? 만약 안했으면 해줍니다.

yarn add -D typescript

그 다음 vscode 에서 아래 익스텐션을 깔아줍니다. 링크로 들어가셔도 되고 그냥 익스텐션에서 zipfs 검색하면 나옵니다.

https://marketplace.visualstudio.com/items?itemName=arcanis.vscode-zipfs

그 다음 아래 명령어를 실행해줍니다.

yarn dlx @yarnpkg/sdks vscode

그렇다면 아래 출력이 나오면서 뭔가 성공했다는 기분이 듭니다.

➤ YN0000: ┌ Resolution step
➤ YN0000: └ Completed in 8s 435ms
➤ YN0000: ┌ Fetch step
➤ YN0000: └ Completed in 0s 202ms
➤ YN0000: ┌ Link step
➤ YN0000: └ Completed in 0s 209ms
➤ YN0000: Done in 8s 879ms

➤ YN0000: ┌ Generating SDKs inside .yarn/sdks
➤ YN0000: │ ✓ Typescript
➤ YN0000: │ • 6 SDKs were skipped based on your root dependencies
➤ YN0000: └ Completed
➤ YN0000: ┌ Generating settings
➤ YN0000: │ ✓ Vscode (new ✨)
➤ YN0000: └ Completed

그리고 vscode 에서 갑자기 아래 메시지가 나옵니다! Allow 를 눌러줍니다.


❗ 만약에 위 메시지가 뜨지 않는다면?

TypeScript: Select TypeScript Version... 를 Command Pallette (cmd+shift+p) 에서 찾아서 실행시킵니다.

그 다음 Use Workspace Version 를 선택합니다.

하여튼 간에 yarn add -D typescript 로타입스크립트 패키지를 먼저 설치한 다음에 yarn dlx @yarnpkg/sdks vscode 얘를 해야 뭔가 제대로 동작합니다. yarn dlx @yarnpkg/sdks vscode 먼저 하면 안되더라구요.


아래 명령어를 실행하여 기본적인 typesciprt 패키지를 만들어줍니다.

tsc --init

그 다음 간단하게 index.ts 파일을 아래 내용으로 만듭니다.

type S = string;
const msg: S = "hello world!";
console.log(msg);

그 다음 다음 명령어로 간단하게 실행시켜봅시다.

$ tsc && yarn node ./index.js
hello world!

index.js 파일이 생길 테지만, 간단하게 무시합시다.

여러 개 하위 패키지(workspace) 만들기

2개의 폴더를 만들어줍니다. 폴더 구조가 헷갈린다면 소스 코드를 봅시다.

mkdir server common

common 에 들어가서 yarn init 하게 되면 package.json 파일과 [README.md](<http://README.md>) 파일 두 개가 생길 것입니다. (호오잉? 처음에 했던 yarn init 이랑 비교하면 놀랄 만큼 간단하네요!)

common/package.json 에서 name에 해당하는 부분을 다음과 같이 수정해줍니다.

{
  "name": "@hello/common",
  "packageManager": "yarn@3.0.2"
}

그 다음 server 에 들어가서 똑같이 yarn init 한다음 package.json 파일을 수정해줍니다.

{
  "name": "@hello/server",
  "packageManager": "yarn@3.0.2"
}

그 다음 프로젝트 루트에 있는 package.json 에서 다음 내용을 추가해줍니다.

"workspaces": {
  "packages": [
    "server",
    "common"
  ]
}

이렇게 하면 이제 프로젝트 루트에서 각각의 폴더 (워크스페이스)로 접근할 수 있습니다! 이게 무슨 말이냐구요?

프로젝트 루트로 가서 아래 명령어를 쳐보세요.

yarn workspace @hello/server add express @hello/common

그러면 우리가 직접 server 폴더에 들어가서 yarn add 한 효과를 볼 수 있습니다.

@hello/common 은 뭘까요? 아래에서 server 마저 세팅할 때 알려드리겠습니다.

이제 좀 귀찮으니까 프로젝트 루트의 package.json 에 다음 스크립트를 추가해줍시다.

"scripts": {
  "common": "yarn workspace @hello/common",
  "server": "yarn workspace @hello/server"
},

그럼 아까 했던 명령어는 다음과 같이 줄어듭니다. workspace @hello/serverserver 한 단어로 줄었습니다.

yarn server add express @hello/common

common 폴더 세팅

아래 명령어를 프로젝트 루트에서 실행해줍시다. 위에까지 세팅을 제대로 마쳤다면, 이제 common에 명령이 척척 잘 적용될 것입니다.

yarn common add -D typescript
yarn common tsc --init

놀랍게도 common 폴더 안에도 node_modules 폴더가 생기지 않습니다.

common/index.ts 파일을 만들어서 아래 내용으로 채워줍니다.

export function sayHello() {
  console.log(sayHello);
}

common/package.json 파일에 다음 스크립트를 추가해줍니다.

"scripts": {
  "build": "tsc"
}

server 폴더 세팅

yarn server add express @hello/common
yarn server add -D @types/express typescript
yarn server tsc --init

server 폴더 내에서 common 에 참조할 수 있습니다! 대박!

server/package.json 파일을 확인합니다.

"dependencies": {
  "@hello/common": "workspace:common",
  "express": "^4.17.1"
},
"devDependencies": {
  "@types/express": "^4.17.13",
  "typescript": "^4.4.4"
}

workspace:common이 보이십니까?

아래 스크립트를 추가해줍니다.

"scripts": {
  "build": "tsc",
  "start": "node index.js"
},

server/index.ts 파일의 내용을 아래로 채워넣습니다.

import { sayHello } from "@hello/common";
import express from "express";

const app = express();

app.use("/test", (req, res) => {
  sayHello();
  res.status(204).send();
});

app.listen(4000, () => {
  console.log("? Server Listening on localhost:4000!");
});

실행해보기

이제 다 빌드하고 실행시켜봅시다!

yarn common build
yarn server build
yarn server start
? Server Listening on localhost:4000!

그리고 터미널 하나를 더 켜서 다음과 같이 실행시켜봅시다.

curl localhost:4000/test

그 다음 킨 서버에 다음 메시지를 확인합니다.

hello

❗ 만약 yarn common build 를 하지 않는다면?

그렇다면 다음과 같은 에러 메시지가 발생합니다. 무슨 소리냐면 그냥 타입스크립트 빌드를 안해서 실행할 자바스크립트 파일이 없다 이 말입니다.

/Users/th.kim/Desktop/test/.pnp.cjs:10269
    throw firstError;
    ^

Error: Qualified path resolution failed - none of those files can be found on the disk.

Source path: /Users/th.kim/Desktop/test/common/
Not found: /Users/th.kim/Desktop/test/common/
Not found: /Users/th.kim/Desktop/test/common/.js
Not found: /Users/th.kim/Desktop/test/common/.json
Not found: /Users/th.kim/Desktop/test/common/.node
Not found: /Users/th.kim/Desktop/test/common/index.js
Not found: /Users/th.kim/Desktop/test/common/index.json
Not found: /Users/th.kim/Desktop/test/common/index.node

Require stack:
- /Users/th.kim/Desktop/test/server/index.js
    at Function.external_module_.Module._resolveFilename (/Users/th.kim/Desktop/test/.pnp.cjs:10268:55)
    at Function.external_module_.Module._load (/Users/th.kim/Desktop/test/.pnp.cjs:10067:48)
    at Module.require (internal/modules/cjs/loader.js:961:19)
    at require (internal/modules/cjs/helpers.js:92:18)
    at Object.<anonymous> (/Users/th.kim/Desktop/test/server/index.js:6:16)
    at Module._compile (internal/modules/cjs/loader.js:1072:14)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1101:10)
    at Module.load (internal/modules/cjs/loader.js:937:32)
    at Function.external_module_.Module._load (/Users/th.kim/Desktop/test/.pnp.cjs:10117:14)
    at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:76:12)

더 알아볼 것

  • yarn workspaces foreach …
  • 각각의 workspace (실행 Entrypoint) 를 컨테이너화 하기 (.pnp.cjs 랑 cache 포함시키면 도커 이미지 만드는 데에도 시간이 아주 짧게 걸릴 거라 예상)
  • 컨테이너화 한 것들을 쿠버네티스 등의 환경에서 실행시키고 배포하기

참조

https://medium.com/wantedjobs/yarn-berry-적용기-2-프로젝트-적용기-45f1ba67c24c

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 항목은 *(으)로 표시합니다

Scroll to top