Bun 이용하여 Monorepo 환경 구성하기
Bun 이용하여 Monorepo 환경 구성하기
Bun 런타임의 특징에 대해 알아보고 Monorepo 환경을 구성하는 방법에 대해 정리한 내용입니다.
1. Bun 알아보기
Bun은 JavaScript 및 TypeScript 기반의 애플리케이션을 위한 툴킷이며 Node.js 및 Deno의 대안으로 개발되었습니다. bundler, transpiler, script runner, task runner 등의 수행이 가능한 런타임 입니다. 다음과 같은 특징을 가지고 있습니다.
- Low-level 언어인 Zig로 개발되었고 JavaScriptCore 엔진 기반 최적화를 통해 Node.js 보다 더 빠르게 동작.
- JavaScript 및 TypeScript를 지원하여 .jsx, .tsx, .ts 파일을 대상으로 transpiler 동작.
- ESM(ES Module), CommonJS 및 npm 패키지 호환성 지원.
- fetch, WebSocket, ReadableStream과 같은 웹 표준 API 지원.
- bun:test 이용한 내장 테스트 러너 지원.
- Node.js와의 호환성을 바탕으로 Node 스타일의 모듈 resolution 지원.
- 빠른 속도의 SQLite3 클라이언트 제공.
- binary lockfile을 사용하여 json 또는 yaml 기반의 lockfile 보다 더 빠르게 동작.
1.1. Bun 런타임
Bun은 런타임 이상의 목표를 가지고 JavaScript 및 TypeScript 기반의 앱을 빌드하기 위한 통합 인프라 툴킷이 되는 것을 목표로 하고 있습니다.
JavaScript는 프로그래밍 언어 수준의 스펙으로 정의되었고 이를 실행하기 위한 구글의 V8 또는 애플의 JavaScriptCore와 같은 엔진이 개발 되었습니다. 또한 JavaScript를 브라우저와 같은 환경에서 실행하기 위한 런타임이 요구 되었습니다. 브라우저에서는 JavaScript 런타임과 함께 window 객체와 같은 웹 관련 API를 제공하였고 이를 이용하여 웹 페이지에서의 컨텍스트 및 동적인 동작을 구현할 수 있게 되었습니다.
마찬가지로 JavaScript 런타임 중 하나인 Node.js는 브라우저가 아닌 서버와 같은 환경에서 사용할 수 있도록 만들어졌습니다. 그러나 Node.js에는 fetch, ES Module 등의 JavaScript 표준이 정의되어 있지 않았고 JavaScript의 표준 모듈 시스템이 아닌 CommomJS 기반의 모듈 resolution 알고리즘이 적용되어 있습니다.
Bun은 이러한 JavaScript 런타임 및 웹 표준 관점에서의 호환성을 지원하는 것을 목표로 개발 되었습니다. 따라서 ES 모듈, Node.js 모듈, CommonJS에 대한 지원과 함께 Node.js를 대체하는 보다 빠르고 가벼운 툴킷의 역할을 하는 것을 목표로 하고 있습니다.
2. Bun 설치 및 실행하기
2.1. Bun 설치하기
다음 명령어를 이용하여 Bun을 설치해줍니다.
# cURL
# for macOS, Linux, and WSL
curl -fsSL https://bun.sh/install | bash
# to install a specific version
curl -fsSL https://bun.sh/install | bash -s "bun-v1.1.44"
# Homebrew
# for macOS and Linux
brew install oven-sh/bun/bun
설치한 Bun을 이용하여 프로젝트를 생성해줍니다.
bun init
TypeScript 사용 시 Type Definition 처리를 위한 @types/bun 패키지를 추가해줍니다.
bun add -D @types/bun
2.2 Bun HTTP Server 실행하기
Bun을 이용하여 scaffolding을 한 이후에 생성된 index.ts 파일을 다음과 같이 수정해줍니다. Bun의 빌트인 API인 Bun.serve를 이용하여 간단한 HTTP Server를 실행할 수 있습니다.
const server = Bun.serve({
port: 3000,
fetch(req) {
return new Response("Bun!");
},
});
console.log(`Listening on http://localhost:${server.port} ...`);
다음과 같이 index.ts 파일을 실행하면 HTTP Server가 실행되는 것을 확인할 수 있습니다.
bun index.ts
Listening on http://localhost:3000 ...
2.3. Bun Package Manager
Bun은 npm, yarn, pnpm 보다 뛰어난 성능을 보여주는 빠르고 효율적인 패키지 매니저를 제공합니다. 또한 의존성 그래프를 이용하여 package.json 파일에 명시된 의존성 문제들을 처리합니다. 각 하위 dependency 관계에 맞는 버전을 찾고 필요한 모듈과 라이브러리를 내려받아 설치합니다.
Bun은 dependency에 대한 install 과정에서 최상단 node_modules 디렉터리를 사용하게 되는데, 같은 dependency를 가진 경우에 대해 심볼릭 링크(Symlinks)를 사용하여 처리합니다. 여러 패키지에서 동일한 dependency를 가진 경우엔 node_modules에 설치된 dependency를 호이스팅하여 중복 install을 방지 합니다.
2.4. Bun 모듈 시스템
Bun에서는 ES Module을 기본적으로 지원하기 때문에 별다른 설정 없이 사용할 수 있습니다. 반면에 Node.js에서는 ES Module을 사용하기 위해서는 package.json에 "type": "module" 설정이 추가로 필요합니다.
3. Bun Workspaces
3.1. Bun Workspaces 이용하여 Monorepo 환경 구성 하기
bun 프로젝트를 구성한 후에 package.json을 다음과 같이 설정해줍니다. "private": true 속성은 root 패키지가 npm으로 발행되는 것을 방지 합니다. workspaces 속성에는 관리할 하위 패키지 경로를 작성해줍니다.
{
"name": "bun-monorepo-examples",
"version": "1.0.0",
"private": true,
"module": "index.ts",
"type": "module",
"workspaces": ["packages/*"]
}
workspaces 속성은 경우에 따라 다음과 같이 패키지를 개별적으로 작성해줄 수도 있습니다.
"workspaces": [
"packages/package-a",
"packages/package-b"
]
다음으로 packages 디렉터리 경로에 하위 패키지를 생성하여 다음과 같은 형태로 구성해줍니다.
.
├── README.md
├── bun.lock
├── package.json
├── tsconfig.json
└── packages
├── package-a
│ ├── index.ts
│ ├── package.json
│ └── tsconfig.json
└── package-b
├── index.ts
├── package.json
└── tsconfig.json
package-a의 package.json 파일은 다음과 같이 구성해줍니다.
{
"name": "package-a",
"version": "1.0.0",
"main": "index.ts",
"scripts": {
"build": "bun build index.ts --outdir dist"
}
}
package-b의 package.json 파일은 다음과 같이 구성해줍니다.
{
"name": "package-b",
"version": "1.0.0",
"main": "index.ts",
"dependencies": {
"package-a": "workspace:*"
},
"scripts": {
"build": "bun build index.ts --outdir dist"
}
}
dependencies 속성에 package-a에 대한 의존성을 설정해줍니다. workspace 사이의 의존성을 설정해주려면 "workspace:*" 구문을 사용해줍니다. 위와 같이 설정하면 Bun은 의존성에 대한 버전을 찾아 링크를 설정해줍니다.
구성이 완료되면 dependency install을 위해 아래와 같이 실행해줍니다.
bun install
Bun의 Workspace는 Yarn을 이용한 것과 동일하게 Monorepo 환경을 구성할 수 있지만, 아직 특정 패키지에 대한 의존성을 설치할 때 필요한 CLI가 지원되진 않습니다. Yarn에서는 "yarn workspace <workspace_name> <command>" 와 같이 특정 패키지에 대한 CLI를 지원하지만 Bun에서는 아직 지원되지 않습니다. 따라서, Bun에서 특정 패키지의 설치가 필요한 경우엔 다음과 같이 해당 패키지의 디렉터리까지 이동한 후에 패키지 설치를 실행해야 합니다.
cd packages/package-a
bun install
또 다른 방법으로는 다음과 같이 --filter 옵션을 사용하여 특정 패키지에 대한 설치를 실행할 수 있습니다.
// package-a 패키지만 설치
bun install --filter "package-a"
// package-b 패키지만 설치
bun install --filter "package-b"
// 모든 패키지 설치
bun install --filter "package-*"
// package-a, package-b 패키지를 각각 설치
bun install --filter "package-a" --filter "package-b"
이상으로 Bun의 특징과 함께 Workspace를 이용하여 Monorepo 환경을 구성하는 방법에 대해 알아봤습니다.
※ Reference
- bun.sh, What is Bun? | Bun Docs, https://bun.sh/docs
- www.jeong-min.com, Bun 한 번 써보자, https://www.jeong-min.com/51-bun/
- helloinyong.tistory.com, Bun 1.0 릴리즈 후, 서비스 개발에 문제 없을지 리서치 해본 결과, https://helloinyong.tistory.com/353
- johnny-developer-story.tistory.com, Bun 런타임: Node.js를 대체할 혁신적인 선택 (1): Bun 런타임의 개념과 주요 특징 자세히 알아보기, https://johnny-developer-story.tistory.com/49
- johnny-developer-story.tistory.com, Bun 런타임: Node.js를 대체할 혁신적인 선택 (3): Bun과 Node.js 차이점과 선택 가이드, https://johnny-developer-story.tistory.com/51
- medium.com/@hong009319, 자바스크립트의 표준 정의 : CommonJS vs ES Modules, https://medium.com/@hong009319/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EC%9D%98-%ED%91%9C%EC%A4%80-%EC%A0%95%EC%9D%98-commonjs-vs-es-modules-306e5f0a74b1