Show HN: Nub - Node.js용 Bun 유사 올인원 툴킷
요약
Nub은 Node.js 환경을 보강하는 Rust 기반의 올인원 개발 툴킷입니다. Bun과 유사한 개발자 경험을 제공하면서도 새로운 런타임 대신 Node.js를 활용하여 호환성을 유지하며, 파일 실행, 패키지 관리, Node 버전 관리를 통합 지원합니다.
핵심 포인트
- Rust 기반의 고성능 툴킷으로 Node.js 호환성 유지
- TypeScript, JSX 등 다양한 파일 형식의 즉시 실행 지원
- npm, pnpm, npx를 대체하는 고속 명령 및 패키지 매니저 제공
- osv.dev 기반의 보안 검사 및 postinstall 차단 기능 탑재
- Node.js 버전 자동 추론 및 관리 기능 포함
Nub은 stock node 위에 Bun과 유사한 개발자 경험을 얹는 Rust 기반 올인원 툴킷으로, 파일·스크립트 실행, 의존성 설치, Node 자체 관리를 하나의 도구로 처리함
새 런타임을 만들지 않고 Node.js를 보강하는 방식이며, vendor-specific API surface와 lock-in이 없다는 점을 명시함
nub <file>은 .js, .ts, .mjs, .cjs, .mts, .cts, .jsx, .tsx 실행을 지원하고, node와 flag-for-flag 및 var-for-var drop-in 호환을 목표로 함
파일 실행 기능은 TypeScript, JSX/TSX, decorators, emitDecoratorMetadata, extensionless imports, tsconfig.json#paths, 자동 .env* 로딩, .yaml·.toml·.jsonc·.json5·.txt 로더를 제공함
내부 동작은 Node의 --import/--require preload, module.registerHooks() 기반 transpilation·resolution, N-API native addon을 사용하며, Nub은 pre-transpilation을 위해 oxc를 내장함
파일 실행 시 프로젝트가 기대하는 Node 버전을 추론하고 필요하면 자동 설치하며, 우선순위는 NODE_EXECUTABLE, package.json#devEngines, .node-version, .nvmrc, package.json#engines 순서임
nub watch와 nub --watch는 resolved dependency graph와 .env*, tsconfig.json extends chain, package.json 같은 off-graph invalidator를 감시하고 Node 자체 --watch 엔진 위에서 실행함
nub run은 npm run·pnpm run의 drop-in으로, Rust 바이너리라 자체 JavaScript startup이 없으며 warm script dispatch 벤치마크에서 nub run 14.7ms, npm run 329.9ms, pnpm run 442.7ms 결과를 제시함
nubx와 nub dlx는 npx·pnpm dlx의 drop-in으로, local-first 실행 뒤 미설치 bin은 registry에서 가져와 실행하고 폐기하는 fallback을 제공함
nub install은 Aube 엔진 기반 패키지 매니저이며, pnpm과 flag-for-flag 호환 CLI를 목표로 하고 nub install, nub ci, nub add, nub remove, nub update, nub dedupe 흐름을 제공함
패키지 설치 보안 기본값은 postinstall 차단, resolution 중 osv.dev known-malicious package version 검사, provenance downgrade 거부, 24시간 minimumReleaseAge 적용임
nub install은 package.json#packageManager와 lockfile을 기준으로 기존 패키지 매니저를 감지하고 compat-mode로 동작하며, npm·pnpm·Yarn·Bun·Nub별 설정 파일과 환경 변수를 읽음
nub pm shim은 Corepack-style global shim을 등록해 npm, yarn, pnpm 실행 시 프로젝트의 고정 버전을 감지하고 필요하면 설치한 뒤 해당 버전으로 명령을 실행함
nub node는 Node 버전 관리 명령을 제공하며, which, install, ls, uninstall, pin으로 Nub 캐시의 Node 버전을 조회·설치·삭제·고정함
설치 경로는 macOS/Linux용 install script, Windows PowerShell script, Homebrew, npm install -g --ignore-scripts=false @nubjs/nub이며, GitHub Actions에서는 actions/setup-node와 one-to-one 호환인 nubjs/setup-nub을 사용할 수 있음
아이디어가 아주 좋고 말이 됨. Bun은 DB 드라이버 같은 걸 더 제공하지만, 개발자 경험도 매력의 큰 부분인 건 확실함
참고로 Nub의 주 저자는 Zod를 만든 Colin McDonnell이고, 한때 Bun에서도 일했음
맞음. Nub은 의도적으로 Nub 전용 API를 전혀 넣지 않음: Nub 전역 객체도, nub: 접두사 내장 모듈도, Nub 이름의 설정 파일/잠금 파일도, package.json의 nub 필드도, NUB_ 환경 변수도 없음
Bun이 추가한 것들 대부분은 제대로 된 의존성으로 두는 편이 더 낫다고 봄
--import가 아니라 --require 훅을 쓰는 게 의외임. 비슷한 기능을 만들려고 살펴보던 때와 뭔가 크게 달라졌을 수도 있지만, Nub의 ESM 지원에 미묘한 부분이 있지 않을까 싶음
당시에는 Node의 --import가 아주 초기였고, 흔한 ESM-to-CJS 접근에서 처리하고 싶었던 예외가 여럿 있었음. 대부분은 매우 틈새 사례였겠지만, 최상위 await는 의미 있는 일부 사용자에게 영향을 줄 거라고 봄
이건 순전히 성능 때문에 프리로드 등록에 사용함. 이 경우와 다른 많은 경우에서 CommonJS가 여전히 ESM보다 빠름. --require는 약 0.5ms 오버헤드인데, --import는 M1 Macbook Pro 기준 4.6ms 정도임
관련해서 Node.js는 최근 2025년에 예전 비동기 module.register() API보다 성능을 높이려고 resolver 훅 등록 API의 동기 버전인 module.registerHooks()를 도입했음. Nub에는 큰 장애물 해소였음. 관심 있는 사람을 위해 덧붙이면, 비동기 API는 고정 등록 오버헤드 19ms에 import마다 약 130us의 추가 오버헤드를 더했음
여기서 Nub이 어떤 플래그를 쓰는지는 사용자 코드에는 전혀 영향이 없고, 최상위 await는 Node.js 자체가 지원하는 곳에서는 지원됨
우리 전체 모노레포를 nub으로 마이그레이션하는 PR을 막 머지했음
문제 0개였고, 말도 안 되게 빠름
이게 올라온 지 한 시간 안에 공유 모노레포를 이걸로 마이그레이션하는 PR을 머지한 거임?
Node는 몇 버전 전부터 TypeScript를 실행할 수 있지 않았나? 왜 변환기가 필요한 거지?
Node의 내장 TypeScript 지원은 타입 제거만 함. TypeScript 문법의 아주 많은 부분에는 통하지만 전부는 아님. 타입을 실제로 검사하지도 않고, 실행되도록 제거만 함. tsconfig 같은 것도 잃게 됨
이건 내장 제거 방식과 실제 TypeScript 처리를 둘 다 지원하는 것으로 보임
README에는 WebSocket 지원이 Node 22부터 네이티브라고 되어 있는데, Node에는 네이티브 WebSocket 라이브러리가 없음. WebSocket 표준 링크는 MDN으로 가는데, 거기는 WHATWG 사용자 인터페이스만 설명하고 프로토콜이나 WebSocket 동작 방식은 설명하지 않음
뭔가 빠졌거나, 보조로 비네이티브 라이브러리를 쓰는 것처럼 느껴짐
Node는 22부터 내장 WebSocket 클라이언트를 지원하지만 서버는 지원하지 않음
기존 기술을 받아들이고 더 나쁜 버전을 다시 만들지 않는 점은 존중할 만함. 대안 만들기에 들어간 모든 노력이 Node에 갔다면, 적절한 리더십 아래 지금 어디까지 왔을지 궁금함
2014년 Node.js의 io.js 포크를 기억할 수도 있음. Node가 정체되자 여러 사람이 io.js로 포크했고, 결국 다시 Node에 병합되어 Node를 제 궤도에 올려놨음. 더 거슬러 올라가면 JS의 “포크”였던 CoffeeScript도 최고의 아이디어들이 ES5로 흡수됐음
작고 기민한 팀은 실패가 치명적인 위험이 아니기 때문에 좋은 아이디어를 입증할 수 있음. 짧게 말하면 포크는 건강한 생태계의 일부임
근본적으로 이런 접근으로는 고칠 수 없는 게 많음
간단한 예로, Node는 내가 아는 진지한 오픈소스 소프트웨어 중 설정 파일 안에 설정을 문서화할 방법이 없는 유일한 것임. 말도 안 됨. Node 쪽은 별생각 없이 JSON을 채택했고, 이후에는 “주석 있는 JSON”조차 포함해 어떤 대안도 검토하길 거부했음
조직이 나쁜 결정에 고착되면, 고치는 유일한 방법은 새로 시작하는 것임. 모두가 Node 위에 계속 쌓는 한 JS 생태계 전체는 설정에 문서를 남길 수 없을 것임
Node 생태계에는 이런 문제가 여럿 있고, 설정을 문서화할 수 없다는 완전한 부조리는 그냥 내 개인적인 불만 포인트임
Nub와 마스코트 nubnub의 팬임. 진지하게 말하면 훌륭한 프로젝트고, 꽤 흥미로워서 지난주부터, 적어도 공개된 이후로 계속 써보고 있음
똑똑함. 이미 Rust로 작성되어 있으면 Rust로 마이그레이션을 바이브 코딩하다가 고객을 전부 잃을 일은 없으니까 ;)
OpenAI에 인수된 다음 프로젝트를 Zig로 바꿀 듯
이 프로젝트는 이미 바이브 코딩 비중이 큼. 저장소의 두 번째 기여자가 Claude임
“이미 Rust로 바이브 코딩되어 있다면”이 더 나을 듯. Nub에서는 전반적으로 그런 냄새가 꽤 남. 괜찮긴 한데 Bun과 비교하니 웃김
덧붙이면 Bun의 반 AI 히스테리는 매우 슬프고, 가끔은 조직적인 캠페인처럼 느껴질 때도 있음
애초에 이미 바이브 코딩되어 있고 고객도 없다면 더 도움이 됨
맞음. 여기서 “Rust로 작성”이 뭘 더해주는지는 잘 모르겠음. 같은 기능은 셸 스크립트 몇 개와 package.json으로도 가능할 거라고 봤음
AI 자동 생성 콘텐츠
본 콘텐츠는 GeekNews의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기