- Bun 1.2는 full-stack JavaScript/TypeScript 개발 도구를 목표로, Node.js 호환성과 런타임·번들러·테스트·패키지 매니저를 함께 확장한 대형 릴리스임
- 매 변경마다 Node.js 테스트 스위트를 돌리는 방식으로 호환성 검증을 강화했고,
node:http2,node:dgram,node:cluster,node:zlib,node:v8지원이 추가됨 - 새 내장 API
Bun.s3와Bun.sql은 S3 호환 객체 스토리지와 Postgres 접근을 런타임 안으로 끌어와 외부 클라이언트 의존을 줄임 - 패키지 매니저는 기본 lockfile을 바이너리
bun.lockb에서 JSONC 기반bun.lock으로 바꾸고,.npmrc,bun publish,bun patch,bun outdated,bun run --filter를 추가함 bun run작업 디렉터리,Bun.build()실패 처리,server.stop()반환값,bun -p, sourcemap 기본값이 바뀌어 기존 프로젝트는 마이그레이션 영향을 확인해야 함
Node.js 호환성 강화
- Bun 1.2는 Bun 변경마다 Node.js 테스트 스위트를 실행하는 방식으로 호환성 개선 절차를 바꿈
- 기존에는 GitHub 이슈나 npm 패키지 실행 실패 보고를 중심으로 버그를 고쳤지만, 이 방식은 큰 리팩터링을 어렵게 만드는 “두더지 잡기”에 가까웠음
- Node.js 저장소의 수천 개 테스트 파일을 Bun으로 포팅했고, 매 커밋마다 이 테스트를 실행해 호환성을 확인함
- Node.js 테스트에는 내부 구현 세부사항과 정확한 에러 메시지를 검증하는 경우가 있어, Bun은 일부 테스트에서 내부 바인딩을 자체 스텁으로 바꾸거나
name과code중심 검증으로 조정함- Bun은 가능한 한 Node.js의 에러 메시지를 맞추지만,
name과code가 같다면 더 도움이 되는 메시지를 제공하는 경우도 있음
- Bun은 가능한 한 Node.js의 에러 메시지를 맞추지만,
- 새로 지원되는 Node.js 모듈과 기능
node:http2: HTTP/2 서버 생성 지원, gRPC 서버에도 필요함node:dgram: UDP 소켓 bind/connect 지원node:cluster: 여러 Bun 인스턴스를 실행해 여러 CPU 코어에 작업을 분산 가능node:zlib: JavaScript 구현을 네이티브 코드로 다시 작성했고 Bun 1.1보다 2배 빨라짐node:v8:getHeapSnapshot,writeHeapSnapshot으로 Bun 힙을 Chrome DevTools에서 검사 가능
node:http2서버는 Bun 1.2에서 Node.js보다 2배 빠름express는node:http호환성 개선과 Bun HTTP 서버 최적화로 Node.js보다 HTTP 요청을 최대 3배 빠르게 처리함- V8 C++ API를 쓰는 C++ 애드온 지원도 추가됨
- Node.js는 V8, Bun은 JavaScriptCore를 사용하므로 구현 난도가 큼
- Bun은 JavaScriptCore 위에 V8의 공개 C++ API를 구현해
cpu-features같은 패키지가 동작하도록 함 - V8 C++ API 지원은 복잡해 대부분 패키지에는 아직 빠진 기능이 있을 수 있으며,
node-canvas@v2와node-sqlite3같은 패키지 지원을 계속 개선 중임
내장 S3 API Bun.s3
- Bun 1.2는 S3 호환 객체 스토리지를 다루는 내장 API
Bun.s3를 추가함- Amazon S3, Google Cloud Storage, Cloudflare R2 등 S3 API를 구현한 서비스와 함께 사용할 수 있음
- 파일 읽기, 쓰기, 삭제를 Web 표준
Blob과 호환되는 API로 처리함
s3.file()은 S3 파일에 대한 지연 참조를 반환하며,text(),json(),arrayBuffer(),stream()같은 BunFileAPI와 같은 방식으로 사용할 수 있음- Bun의 S3 클라이언트는 JavaScript가 아니라 네이티브 코드로 작성됨
- Node.js에서
@aws-sdk/client-s3를 쓰는 방식과 비교해 S3 버킷 파일 다운로드가 5배 빠름
- Node.js에서
- 쓰기 기능은
write()와writer()를 제공함write()는 문자열,Uint8Array,Blob,Response등을 업로드할 수 있음writer()는 큰 파일에 대해 멀티파트 업로드를 수행함
presign()은 특정 파일 업로드를 허용하는 presigned URL을 생성함- 사용자에게 자격 증명을 노출하거나 버킷에 불필요한 접근 권한을 주지 않고 직접 S3에 업로드하게 할 수 있음
Bun.serve()와 함께 사용할 때new Response(s3.file(...))는 서버가 S3 파일을 내려받아 다시 보내는 대신 presigned URL로 리디렉션함- 메모리, 시간, 서버가 파일을 다운로드하는 대역폭 비용을 줄임
s3://URL은Bun.file()과fetch()에서도 사용할 수 있음fetch("s3://...")로 업로드, 다운로드, 삭제 가능- 기본
S3Client는AWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEY같은 환경 변수로 설정됨
내장 Postgres 클라이언트 Bun.sql
- Bun 1.2는 Postgres를 지원하는 내장 SQL 클라이언트
Bun.sql을 추가함- Bun은 기존에 내장 SQLite 클라이언트를 제공했고, 이번 릴리스에서 SQL 데이터베이스 지원 범위를 넓힘
- MySQL 지원을 추가하는 pull request도 있음
Bun.sql은 tagged-template literal로 SQL을 실행함- JavaScript 값을 SQL 파라미터로 전달할 수 있음
- 문자열 이스케이프와 prepared statement를 자동으로 사용해 SQL injection을 방지함
- 결과는 컬럼명을 키로 하는 객체 배열로 반환됨
- 네이티브 코드 구현과 여러 최적화를 사용함
- 자동 prepared statement
- 쿼리 파이프라이닝
- 바이너리 wire protocol
- 커넥션 풀링
- 구조 캐싱
- 인기 Postgres 클라이언트를 Node.js에서 쓰는 방식보다 행 읽기가 최대 50% 빠름
- API는
postgres.js에서 영감을 받아, 기존 코드에서 Bun 내장 SQL 클라이언트로 옮기기 쉽도록 설계됨
패키지 매니저 변화
- Bun 1.2는 기본 lockfile을 바이너리
bun.lockb에서 텍스트 기반bun.lock으로 바꿈bun.lockb는bun install을npm보다 거의 30배 빠르게 만드는 데 도움이 됐지만, GitHub에서 내용을 보기 어렵고 pull request 검토와 merge conflict 해결이 어려웠음- Dependabot 같은 도구가 lockfile을 읽기에도 어려움이 있었음
bun.lock은 JSONC 파일임- 주석과 trailing comma를 지원함
- pull request diff 확인이 쉬워지고, trailing comma로 merge conflict 가능성이 줄어듦
- 새 프로젝트는
bun.lock을 생성함- 기존
bun.lockb프로젝트는 자동 마이그레이션 없이 계속 바이너리 lockfile을 지원함 bun.lockb는 장기간 지원되며bun add,bun update도 계속 갱신함bun install --save-text-lockfile로 새 텍스트 lockfile로 마이그레이션 가능함
- 기존
bun install은 텍스트 lockfile 전환 이후에도 Bun 1.1보다 30% 빨라짐package.json에서 주석과 trailing comma를 사용할 수 있음require()와import()도 이런package.json을 읽을 수 있음- JavaScript 생태계 전체에서 널리 지원되는 기능은 아니므로 “at your own risk”로 사용하라고 안내함
.npmrc지원이 추가됨- 프로젝트 루트와 홈 디렉터리의
.npmrc를 읽음 - registry, scoped package, private registry 인증 설정에 사용할 수 있음
- 프로젝트 루트와 홈 디렉터리의
- 새 패키지 매니저 명령과 옵션
bun run --filter: 여러 workspace에서 같은 스크립트를 동시에 실행bun outdated: 오래된 의존성 확인bun publish:npm publish대체,.npmrc인증·tarball packing·OTP·package.json edge case 처리 지원bun patch: 의존성 수정 내용을patches/의.patch파일로 저장하고bun install때 자동 적용--omit=dev|optional|peer: 설치에서 dev, optional, peer 의존성 제외- CA 인증서는
bunfig.toml, CLI 플래그,.npmrc에서 설정 가능함 bundleDependencies와bun add의package.json들여쓰기 보존도 지원함
테스트 러너 개선
bun test는 JUnit XML 리포터를 지원함bun test --reporter=junit --reporter-outfile=junit.xml로 Jenkins, CircleCI, GitLab CI 같은 CI/CD 도구에 테스트 결과를 전달할 수 있음bunfig.toml에서도 JUnit 리포팅을 설정 가능함
- 코드 커버리지에는 LCOV 리포터가 추가됨
bun test --coverage --coverage-reporter=lcov로coverage/lcov.info를 생성함--coverage-dir로 출력 디렉터리를 바꿀 수 있음
expect().toMatchInlineSnapshot()으로 inline snapshot을 지원함bun test -u또는--update-snapshots로 테스트 파일 안에 snapshot을 갱신함toThrowErrorMatchingSnapshot()과toThrowErrorMatchingInlineSnapshot()도 사용할 수 있음
test.only()는 더 이상--only플래그 없이도 동작함expect()API에는 Jest, Vitest,jest-extended와 같은 matcher가 추가됨toContainValue(),toContainKey(),toHaveReturned()계열- 두 번째 인자로 사용자 정의 에러 메시지를 전달 가능
jest.setTimeout()과setDefaultTimeout()으로 현재 scope 또는 module의 기본 테스트 timeout을 바꿀 수 있음
번들러와 빌드 기능
- Bun 1.2는 HTML import를 지원함
- HTML 파일을
Bun.serve의static옵션에 넘기면 HTML 안의<script>와<link>를 자동 번들링하고 정적 라우트로 노출함
- HTML 파일을
bun build --compile은 교차 컴파일을 지원함- Linux에서 Windows 또는 macOS 바이너리를 만들 수 있고, 반대 방향도 가능함
- Windows 빌드에서는 아이콘 설정과 콘솔 창 숨김 옵션을 사용할 수 있음
bun build --bytecode는 bytecode cache를 생성함eslint같은 애플리케이션의 시작 시간을 2배 빠르게 만들 수 있음.jsc파일은 해당.js파일의 bytecode cache를 담으며, 두 파일 모두 실행에 필요함- bytecode cache는 소스 코드보다 8배 클 수 있어 시작 시간 개선 대신 디스크 공간을 더 씀
bun build --format=cjs로 CommonJS 출력 형식을 지정할 수 있음- 이전에는 ESM만 지원했음
- 오래된 Node.js 버전을 대상으로 하는 라이브러리나 애플리케이션을 만들기 쉬워짐
- CommonJS 탐지가 개선됨
- 파일이 모호할 때 상단의
"use strict"지시문을 CommonJS의 마지막 휴리스틱으로 사용함 require.main === module은import.meta.main으로 다시 작성되어 import 문과 함께 사용할 수 있음
- 파일이 모호할 때 상단의
- 플러그인 API에는
onBeforeParse()훅이 추가됨- JavaScript가 아니라 N-API addon으로 구현해야 함
- Rust, C/C++, Zig 같은 컴파일 언어에서 파싱 직전 소스 코드를 거의 오버헤드 없이 다룰 수 있음
- 플러그인·프레임워크 작성자를 위한 고급 API임
- 빌드 옵션도 확장됨
--env="PUBLIC_*"로 환경 변수를 번들에 주입--drop=console같은 방식으로 함수 호출 제거- banner/footer 추가
Bun.embeddedFiles()로 standalone executable 안에 포함된 파일 목록 확인--ignore-dce-annotations로 잘못된 dead-code elimination annotation 무시--packages=external로 패키지 의존성을 번들에 포함하지 않도록 설정
CSS 번들링
- Bun 1.2는 새 CSS parser와 bundler를 구현함
- LightningCSS의 작업에서 파생됐고, Rust에서 Zig로 다시 작성돼 Bun의 JavaScript/TypeScript parser, bundler, runtime과 통합됨
bun build ./index.css로 여러 CSS 파일과@import,url,@font-face참조를 하나의 CSS 파일로 결합할 수 있음- JavaScript와 TypeScript 코드에서
.css파일을 import할 수 있음- JavaScript module graph에서 import된 CSS와
@import규칙을 entrypoint별로 하나의 CSS 파일로 평탄화함
- JavaScript module graph에서 import된 CSS와
Bun.build()API로도 CSS와 JavaScript를 같은 API에서 번들링할 수 있음
Bun 런타임 API 추가
Bun.serve()는static속성으로 정적 라우트를 지원함- 경로를 키로,
Response객체를 값으로 전달함 - 정적 라우트는
fetch()핸들러에서 직접 처리하는 것보다 최대 40% 빠름 - response body, header, status code가 메모리에 캐시되어 JavaScript allocation과 garbage collection이 없음
server.reload()로 정적 라우트를 다시 로드할 수 있음
- 경로를 키로,
Bun.udpSocket()은 Bun API 형태의 UDP 소켓을 제공함node:dgram도 지원하지만,Bun.udpSocket()은 기존Bun.listen()과 비슷한 현대적 API임- 단일 syscall로 여러 UDP datagram을 보낼 수 있고 OS backpressure에 대응함
Bun.file()은delete(),unlink(),stat()를 지원함stat()는 Node.jsfs.stat()의Stats객체와 같은 형태의 메타데이터를 반환함- S3 파일에도 같은 API를 사용할 수 있음
Bun.color()는 색상 파싱, 정규화, 변환을 제공함- CSS, ANSI color code, RGB, HSL 등을 지원함
dns.prefetch()는 DNS 레코드를 미리 가져와 시작 시 DNS cache를 데울 수 있음dns.getCacheStats()로 DNS cache 상태를 확인 가능함
- 기타 유틸리티
Bun.inspect.table():console.table처럼 표 형식 문자열을 반환Bun.randomUUIDv7(): 정렬과 데이터베이스에 적합한 monotonic UUID v7 생성
SQLite 클라이언트 개선
- Bun 내장 SQLite 클라이언트는
query.as(Class)로 쿼리 결과를 클래스 인스턴스에 매핑할 수 있음- getter, setter, method를 붙일 수 있음
- 성능상 class constructor, default initializer, private field는 지원하지 않음
- 관계 관리나 SQL 생성은 하지 않으므로 ORM은 아님
query.iterate()는 행을 한 번에 모두 메모리에 올리지 않고 iterator로 처리함- 쿼리 객체 자체도
for루프로 순회 가능함
- 쿼리 객체 자체도
strict옵션을 켜면 쿼리 파라미터에서$,@,:prefix를 생략할 수 있음- 파라미터가 빠지면 에러를 던짐
db.run()결과에서 변경된 행 수와 마지막 삽입 row ID를 확인할 수 있음changeslastInsertRowid
safeIntegers옵션은 64비트 정수를 잘린number대신BigInt로 반환함- 데이터베이스 단위 또는 쿼리 단위로 설정 가능함
- JavaScript
using구문으로 statement와 database를 scope 종료 시 자동 close할 수 있음
JavaScript에서 C 컴파일·실행
- Bun 1.2는 JavaScript에서 C를 컴파일하고 실행하는 실험적 지원을 추가함
bun:ffi의cc()API를 사용함- 별도 build step 없이 JavaScript에서 C system library를 사용할 수 있는 방식임
- Bun에는
tinycc가 내장되어 있음gcc나clang과 달리 단순 C 코드를 밀리초 단위로 컴파일할 수 있음- 필요할 때 C 코드를 컴파일해 실행할 수 있음
- N-API를 사용하는 C 코드도 제공됨
node-gyp빌드 단계 없이 Bun만 있으면 동작함
musl과 Alpine Linux 지원
- Bun 1.2는 glibc 대신 musl libc를 쓰는 Linux 배포판용 Bun 빌드를 추가함
- Alpine Linux 같은 환경에서 사용할 수 있음
- Linux x64와 aarch64를 지원함
- Docker에서는
oven/bun:alpine이미지를 사용할 수 있음 - musl은 더 작은 컨테이너 이미지를 가능하게 하지만, Bun의 glibc 버전보다 약간 느린 경향이 있음
- 특정 이유가 없다면 glibc 사용을 권장함
JavaScript 언어 기능
- import attributes 지원이 추가됨
import json from "./package.json" with { type: "json" }처럼 JSON, text, TOML 등을 명시해 import 가능함- 동적
import()에서도 사용할 수 있음
using과await using을 지원함- scope를 벗어나면
[Symbol.dispose]또는[Symbol.asyncDispose]가 호출되어 리소스를 자동 정리함 Bun.spawn(),Bun.serve(),Bun.connect(),Bun.listen(),bun:sqlite등 여러 Bun API에서 지원함
- scope를 벗어나면
- Promise 관련 새 API
Promise.withResolvers():promise,resolve,reject를 한 번에 생성Promise.try(): 동기 또는 비동기 함수를 promise로 감쌈
- 에러와 바이트 배열 API
Error.isError(): prototype chain 조작이나node:vmcross-realm 상황에서도 더 정확히 Error 여부를 확인Uint8Array.toBase64()/Uint8Array.fromBase64()Uint8Array.toHex()/Uint8Array.fromHex()
- iterator helper가 추가됨
map,flatMap,filter,take,drop,reduce,toArray,forEach,find
Float16Array를 지원함- 16비트 부동소수점 배열은 32비트보다 정밀도는 낮지만 메모리 효율이 높음
Web API 추가
TextDecoderStream과TextEncoderStream을 지원함TextDecoder와TextEncoder의 스트리밍 버전임- Bun에서
TextEncoderStream은 Node.js보다 최대 30배 빠름
TextDecoder의stream옵션을 지원함- chunk가 완전한 UTF-8 code point가 아니어도 더 큰 스트림의 일부로 처리할 수 있음
bytes()메서드가 추가됨Response,Blob,Bun.file()등에서 stream 데이터를Uint8Array로 반환함- 기존
arrayBuffer()후Uint8Array생성 과정을 줄임
- streaming
fetch()upload를 지원함- 큰 파일이나 content length를 미리 알 수 없는 데이터 스트림 업로드에 유용함
console.group()과console.groupEnd()를 구현함URL.createObjectURL()을 지원함Blob에서 URL을 만들고fetch(),Worker,import()에 사용할 수 있음- Worker script도 Bun transpiler를 거치므로 TypeScript 문법을 사용할 수 있음
AbortSignal.any()는 여러AbortSignal을 결합해, 하나가 abort되면 부모 signal도 abort되게 함
동작 변경과 마이그레이션 주의점
bun run의 작업 디렉터리가 바뀜- 이전에는 shell의 현재 작업 디렉터리를 사용함
- Bun 1.2에서는
package.json의 부모 디렉터리를 스크립트 작업 디렉터리로 사용함 npm,yarn동작과 맞추기 위한 변경임
bun test는 테스트 사이의 uncaught error 또는 rejection을 실패로 보고함- 이전에는 이런 오류가 테스트 실패로 처리되지 않을 수 있었음
server.stop()은 이제Promise<void>를 반환함- in-flight HTTP connection이 닫힐 때까지 기다릴 수 있음
Bun.build()는 실패 시 resolve된 결과의logs에 에러를 넣는 대신 reject함- 기존 동작이 필요하면
throw: false를 설정할 수 있음
- 기존 동작이 필요하면
bun -p는 Node.js와 맞춰bun --print의 alias가 됨- 이전에는
bun --portalias였음
- 이전에는
bun build --sourcemap의 기본값이 inline source map에서 linked source map으로 바뀜- 이전 동작이 필요하면
--sourcemap=inline을 사용함
- 이전 동작이 필요하면
성능 개선
- Bun 1.2는 여러 실행 경로에서 성능 개선을 포함함
node:http2: 2배 빠름node:http를 통한 S3 업로드: 5배 빠름path.resolve(): 30배 빠름fetch()DNS resolution: 2배 빠름bun --hot: 메모리 사용량 2배 감소- macOS
fs.readdirSync(): 작은 디렉터리 읽기 5% 빨라짐 String.at(): 44% 빨라짐- 큰 문자열 입력의
atob(): 최대 8배 빠름 fetch()gzip 데이터 압축 해제: 30% 빠름- 큰 입력의
Buffer.from(string, "base64"): 6배~30배 빠름 - 큰 문자열 입력의
JSON.parse(): 2배~4배 빠름, object 입력은 6% 빠름 - 일부
Bun.serve()애플리케이션 처리량: 최대 2배 증가 Error.captureStackTrace(): 9배 빠름- 작은 파일
fs.readFile(): 최대 10% 빠름 - 문자열 인자의
console.log(): 50% 빠름
- Windows에서는 JavaScriptCore의 JIT가 활성화됨
- 이전에는 JIT가 macOS와 Linux에서만 사용 가능했음
- Windows에서 JavaScript가 전반적으로 더 빠르게 실행됨
- 예시로
Object.entries()는 20%,Array.map()은 50% 빨라짐
설치와 업그레이드
- 새 설치 명령
curl -fsSL https://bun.sh/install | bashpowershell -c "irm bun.sh/install.ps1 | iex"npm install -g bunbrew tap oven-sh/bun후brew install bundocker pull oven/bun
- 이미 설치된 Bun은
bun upgrade로 업그레이드함
댓글과 토론
Hacker News 의견들
-
왜 서드파티 데이터베이스와 외부 S3 라이브러리를 코어/표준 라이브러리에 넣는지 모르겠음
이런 건 선택 라이브러리가 더 낫지 않나 싶고, 이런 런타임은 표준 라이브러리에 넣는 항목을 아주 신중히 골라야 함
벌써부터 주방 싱크대처럼 뭐든 다 넣는 프로젝트 느낌이 남- 이런 입장 자체가 Bun이 주목받은 이유 중 하나라고 봄
배터리 포함 방식은 많은 곳에서 인기 있고 선택되는 경로임
TypeScript 설정도 어렵고, Webpack, S3, Postgres, Jest 등도 마찬가지라서, 단순화된 파일·스트림 접근도 꽤 흥미로움
분산 배포 제공자가 어떻게 나오는지 지켜보면 될 듯함 - Bun은 VC 투자를 받은 걸로 알고 있어서 언젠가는 돈을 벌어야 하고, 그래서 추측하자면 올인원 실행기로 만들어 어떤 식으로든 벤더 종속을 만들려는 것일 수 있음
물론 틀릴 수도 있지만, 이런 의존성을 코어/표준 라이브러리에 넣는 건 실제로 말이 잘 안 됨 - 많은 사람이 Bun 작성자인 Jared에게 같은 얘기를 했지만, Jared의 생각은 Bun이 기본 프로젝트에 필요한 건 다 갖춰야 한다는 쪽임
코어에 넣으면 서드파티 라이브러리보다 더 최적화할 수 있다고 보는 듯함
개인적으로는 잘못된 접근이고 Jared가 너무 야심이 커진 느낌이지만, 결국 그의 열정 프로젝트이긴 함 - 선택 라이브러리가 더 낫다는 데 완전히 동의함
Bun 쪽 표현으로는 “Bun은 클라우드 우선 JavaScript 런타임을 지향한다. 즉 클라우드에서 프로덕션 애플리케이션을 실행하는 데 필요한 모든 도구와 서비스를 지원한다”인데, 이 말이 별로 신뢰를 주지는 않음
이 특정 설계 선택은 Node보다도 더 나빠 보임 - 이건 Bun의 관리형 제공 서비스를 위한 것임
VC 지원 소프트웨어의 문제는 항상 이런 통합 기능들이 고유한 뭔가를 제공하려 들고, 달리 말하면 종속을 만들려 한다는 데 있었음
- 이런 입장 자체가 Bun이 주목받은 이유 중 하나라고 봄
-
지금까지 Bun 사용 경험은 아주 좋았음
새 프로젝트에서 TypeScript/Jest/React/Webpack을 설정할 때 여기저기 깨지는 변경 때문에 늘 꺼렸는데, Bun에서는 자체적으로 해결되고 고통 없이 내가 쓰는 용도에는 그냥 동작함
S3, SQL 같은 서드파티 라이브러리 통합은 뭐라 말하기 어렵지만, 적어도 가장 흔히 쓰이고 많이 요청되는 것들에 집중하는 듯함
Node.js 도구 생태계에 필요했던 정상성을 가져와 줘서 좋음- 위에서 말한 프런트엔드 기술 스택에서 Bun이 어떤 차이를 만들어 주는지 궁금함
- React/TypeScript 프로젝트는 Vite나 Next.js로도 잘 설정해 왔음
다른 도구들도 그동안 많이 발전했다는 점을 과소평가하는 듯함 - Bun은 훌륭함
나한테는 생산성 치트키 같은 존재임
ChatGPT가 Bun을 잘 몰라서 생산성 손실이 조금 있긴 하지만 그래도 Bun이 좋음
-
좋은 내용이 많지만, 기본 동작 일부가 너무 마법처럼 숨겨진 동작으로 가는 건 아닌지 걱정됨
new Response(s3.file(...))를 쓰면 S3 파일을 서버로 내려받아 사용자에게 보내는 대신, Bun이 사용자를 S3 파일의 사전 서명 URL로 리다이렉트함
기본값으로는 꽤 놀라운 선택이고, S3 버킷을 직접 노출하고 싶지 않을 때 이걸 어떻게 끄는지도 전혀 분명하지 않음- Bun이 개척하려는 영역은 존중하지만, 제작자를 Twitter에서 따라가 보면 의사결정이 단기적 성과와 편의성에 많이 치우쳐 있고, 그 마법적 동작의 깊은 영향은 가볍게 다루는 편임
처음에는 이 프로젝트가 기대됐지만, 소셜에서 공개되는 산발적이고 개인적으로는 종종 좋지 않은 설계 결정들을 보면 장기 방향성에 신뢰가 가지 않음
v0.x로 유지했다면 괜찮았겠지만, 1.0을 냈다면 API 표면을 늘리는 기준이 훨씬 높아졌어야 함 - 응답에 스트림을 넘기면 됨
Response(file.stream()) - 왜 그렇게 했는지는 알겠지만 이 설계는 마음에 들지 않음
개인적으로는 부작용이 강한 동작처럼 느껴지고, 읽기에는 URL이 아니라 파일 내용을 반환하는 것처럼 보임
그래도 버킷 노출이 뭐가 거슬리는지도 궁금함
사전 서명 URL이라 광범위한 접근 권한을 주는 것도 아님
차라리Response((file(...).getPresignedURL()))처럼 명시적인 API가 더 좋고, 또는 환경 변수나 Bun 설정으로 이 동작을 켤 수 있는 선택지가 나았을 듯함
- Bun이 개척하려는 영역은 존중하지만, 제작자를 Twitter에서 따라가 보면 의사결정이 단기적 성과와 편의성에 많이 치우쳐 있고, 그 마법적 동작의 깊은 영향은 가볍게 다루는 편임
-
배터리 포함은 큰 차이를 만듦
Fetch API, Service Workers, Web Components, ES6+, WebRTC 같은 웹 API가 이제 V8과 WebKit 런타임 양쪽에서 네이티브가 된 점을 좋아하는 이유도 그 때문임
다만 정도가 있어야 함
S3는 너무 멀리 간 것일 수 있지만 SQL 드라이버는 말이 됨
그렇다 해도 어디까지 넣을지가 문제임
데이터베이스는 아주 많고, 그중 절반의 드라이버를 넣어야 하나?
그 수준만 돼도 추가 코드가 많아져 실행 파일이 느려질 수 있음
또 이렇게 민감한 API를 Bun에 넣으면 보안도 놓칠 수 있음
어떤 스크립트나 경로 문제로eval이 실행되면서 Bun이 소스 파일 전체를 개인 S3에 업로드한다고 상상해 보면, 그 순간 끝장임- “추가 코드가 많아지면 실행 파일이 느려진다”는 게 정말 그런지 궁금함
코드가 런타임에 로드되는 방식에 따라 거의 무시해도 되는 수준일 수 있다고 봤음
import문이 보일 때만 코드 로딩이 트리거된다면 사실상 속도 오버헤드는 없지 않나?
정적으로 링크돼 있더라도 코드가 존재한다는 이유만으로 고려할 만한 정도로 실행 파일이 느려지는 이유는 잘 모르겠음
메모리에 로드할 실행 파일이 말 그대로 더 커지는 정도는 있겠지만, 체감되는 느려짐은 아닐 듯함 - 예전에 HN에서 브라우저가 SQLite를 1급으로 지원하지 않는 이유에 대한 논의가 있었는데, 그 논점이 Bun에도 적용될 수 있음
핵심은 라이브러리 유지보수 책임이 누구에게 있고, SQLite가 바뀔 때 그 라이브러리를 어떻게 바꾸느냐임
SQLite에 버그가 있으면 Bun에서는 어떻게 고칠 것인가?
어떤 버전들에 수정이 들어가야 하나?
런타임의 패치가 그 위에서 도는 코드의 동작을 바꿀 수 있는데, 사용자들이 기존 동작에 맞춰 우회해 둔 경우는 어떻게 처리할 것인가?
어느 정도는 해결 가능한 문제지만 단점도 따름
어느 순간부터는 런타임이 아니라 플랫폼이 되고, 그에 따른 다른 책임과 문제가 따라옴 - S3를 넣자는 쪽의 근거는 S3 호환 API를 구현한 객체 저장소 서비스가 많다는 데 있다고 봄
진짜 웹 표준은 아니지만 많은 사람이 사실상 표준처럼 맞춰 쓰는 대상이기도 함 - “추가 코드가 많아지면 실행 파일이 느려진다”지만, 글에는 말 그대로 벤치마크가 있고 Bun이 가장 빠른 Node.js 해법보다 두 배 빠르다고 나옴
- “추가 코드가 많아지면 실행 파일이 느려진다”는 게 정말 그런지 궁금함
-
최근 고객사가 프로덕션에서 Bun을 씀
속도와 단순함 때문에 Bun의 개발 경험이 말도 안 되게 좋다고 들었음
개발자 경험은 장기적으로 큰 역할을 함
코드베이스나 프로세스가 엉망이면 FAANG급 보상을 주지 않는 한 좋은 사람들을 잃게 됨 -
아직 Bun을 써보지는 않았지만 기능 목록이 너무 길어서 전부 견고하고 버그가 없을지 회의적임
틀렸으면 좋겠고, 나중 프로젝트에서 한번 돌려볼 생각임
프로젝트 관리 관점에서는 아직 Node.js 100% 호환도 아닌데 왜 S3 지원에 시간을 쓰는지 조금 혼란스러움
Next.js는 매우 큰 생태계라 Next.js 고객을 데려올 수 있으면 S3 지원보다 훨씬 크게 성장할 수 있음- 100% 호환은 마케팅상 좋은 승리지만, 긴 꼬리의 호환성이 평균 사용자에게는 별 차이를 만들지 않을 수 있음
일상적으로 전체 Node.js API 표면 중 실제로 얼마나 쓰고 있나?
그 안의 이상한 엣지 케이스들에 실제로 얼마나 의존하고 있나? - “프로젝트 관리 관점”이라는 말은 프로젝트가 무엇인지 안다고 가정함
작업하는 사람들도 로봇이 아님
어떤 일은 파악하는 데 시간이 걸리고, 그동안 다른 일을 할 수도 있음
한 사람이 모든 일을 하는 것도 아님
“Next.js 고객을 데려오면 더 성장한다”지만, 무엇을 향한 성장인가?
그건 돈이 되지 않음
이건 VC 지원 프로젝트이고, 목표는 Bun을 무료로 제공해서 전 세계 사용자를 모두 얻는 게 아님 - 긴 기능 목록이 모두 견고하고 버그가 없을지 의심되는 데 특히 Zig로 작성됐다는 점이 걸림
Zig는 메모리 안전성이 매우 낮음
더 이상 살아 있지 않은 변수를 참조하면 세그멘테이션 오류 대신 임의의 관련 없는 메모리에 접근함
디버그와 안전 모드에서도 그렇다고 함[0]
변수 이름을 죽은 상태로 표시하고 죽었으면 접근을 막는 메모리 생존성 시스템을 위에 얹는 게 그렇게 어려운가?
결국 “정의되지 않은 동작을 쓰지 마라”[1]가 됨
그래서 인터넷에 노출되는 웹서버 같은 데에는 Zig로 만든 어떤 것도 두고 싶지 않음
[0] : https://news.ycombinator.com/item?id=41720995
[1] : https://github.com/ziglang/zig/issues/16467#issuecomment-164... - 아주 견고하지도, 버그가 없지도 않음
작년에 써봤는데 계속 크래시가 났음 bun add가package.json의 공백과 들여쓰기를 보존하지 않던 버그를 고쳤고, 이제 아무리 이상한 들여쓰기라도 보존한다는 항목이 꽤 웃김
누가 이런 걸 요구했고, 왜 여기에 코드를 쓸 가치가 있다고 봤는지 모르겠음
- 100% 호환은 마케팅상 좋은 승리지만, 긴 꼬리의 호환성이 평균 사용자에게는 별 차이를 만들지 않을 수 있음
-
HTML 가져오기가 대단하고 멋짐
Bun 1.2에서 HTML 가져오기를 지원하면서, 프런트엔드 도구 체인 전체를 단일import문으로 대체할 수 있다고 함
Bun.serve의static옵션에 HTML 가져오기를 넘기면 시작할 수 있음import homepage from "./index.html"; Bun.serve({ static: { "/": homepage, }, async fetch(req) { // ... api requests }, });- 이게 예를 들어 Vite를 어떻게 대체하게 해 주는지 궁금함
핫 모듈 교체, CSS 전처리, Vue SFC 컴파일러 같은 프레임워크별 플러그인 로딩이 가능한가?
정적 파일 서빙은 딱히 새로운 게 아니라서, 내가 뭔가 놓치고 있는 듯함
- 이게 예를 들어 Vite를 어떻게 대체하게 해 주는지 궁금함
-
Node.js의 경쟁 대안만큼 실패가 예정된 프로젝트도 없다고 생각했는데, 한번 써보길 잘했음
텍스트 파일과 SQLite DB 업데이트를 처리하는 독립 실행 스크립트를 많이 만들어야 했고, TypeScript,bun:sqlite[1],bun $ Shell[2]을 설정 파일이나 로컬 npm 의존성 관리 없이 바로 쓸 수 있었음
이후 새 JS/TypeScript 프로젝트에도 써봤는데, 내장 번들러 [3]와 테스트 지원 [4]도 활용되고 의존성 설치도 즉시 끝남
모든 것이 빠르게 즉시 동작하는 건 실제 삶의 질 향상이고, 이제 Bun은 새 JS 프로젝트의 첫 선택지가 됨
[1] https://bun.sh/docs/runtime/shell
[2] https://bun.sh/docs/api/sqlite
[3] https://bun.sh/docs/bundler
[4] https://bun.sh/docs/cli/test- 나도 같음
“이런 것들은 내년에 npm에도 다 생길 텐데 무슨 의미가 있나” 쪽이었음
결국 Bun을 써봤고 정말 놀랐음
개발자 경험의 작은 요소들이 쌓이면 차이가 큼
내 프로젝트에서는 Bun이 정말 차세대처럼 느껴짐
- 나도 같음
-
얼마 전에 처음으로 Bun을 써봤는데 경험이 훌륭했음
내 모든 프로젝트는 TypeScript를 쓰기 위해 Webpack이나 Vite를 설정해 두고, 한번 설정하면 거의 완벽하게 동작하지만 설정 자체가 번거롭고 작은 스크립트에는 그럴 가치가 없음
반면 Bun은 바로 동작했음
CLI에서 TS를 “직접” 실행하려고node-ts인지 뭔지 하는 도구로 10~30분을 만지작거리며 “모듈이 아니다”, “import/require를 쓸 수 없다”, “ESM/CJS” 같은 끔찍한 메시지를 상대하고, 흔한 수정들인package.json모듈 타입 변경,tsconfig변경,import/require방식 변경을 모두 시도했음
약 200줄짜리 스크립트를 실행하려다 마지막 수단으로 Bun으로 바꿨더니 훌륭하게 동작함- 최신 Node.js도 이런 경우에는 이제 “그냥 TS 실행”을 지원함
node --experimental-strip-types index.ts
최신 Node가 아니면tsx패키지가 나한테는 잘 동작했음
ts-node보다 나았음
다만 두 선택지 모두 타입 정보를 그냥 버리고, Bun도 마찬가지임
- 최신 Node.js도 이런 경우에는 이제 “그냥 TS 실행”을 지원함
-
방향이 마음에 듦
특히 S3와 Postgres 네이티브 지원을 포함한 건 “직접 프레임워크를 조립하는” 현 상태의 대안으로 존재할 만해서 아주 타당함
Rails와 Laravel 같은 모든 웹 프레임워크에서는 이게 표준이고, JS 생태계도 여기서 큰 이득을 볼 수 있음
다음 단계는 마이그레이션과 스키마 관리, 그리고 팩토리 설정을 잘 할 수 있는 더 나은 기본 테스트 경험이라고 봄