목표
- 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/server
가 server
한 단어로 줄었습니다.
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