본문 바로가기

웹/JavaScript

Bunjs v.1.1 출시

Bunjs가 v1.1을 출시 했습니다.

공식블로그
공식홈페이지

🟦Bun 이란?

bun는 node, deno 같은 javascript 런타임 및 패키지 관리자 입니다. node, deno와 달리 bun은 빠릅니다. v8엔진을 사용하는 node, deno와 달리 Zig로 작성되고 JavaScriptCore로 구동되어 속도가 굉장히 빠릅니다.



🟦 Bun의 특징

node가 있는데 bun을 쓸 이유가 있을까요? 좀더 빠른 것을 원하면 bun을 선택하는 것이 좋습니다. 걱정되는 것은 node에서 사용되었던 것들이 호환이 안될 수 있다는 것 입니다. 걱정 안하셔도 됩니다. bun 개발자들이 가장 중요하게 생각하는 것이 node와 호환성입니다.

Bun을 썼을 때 더 편리한 방법중 몇가지 알려드리겠습니다.

  • npx — 5배 더 빠름bunx
  • dotenv, — Bun은 기본적으로 파일을 읽습니다.cross-env .env
  • nodemon, — 내장 시계 모드pm2
  • ws — 내장 WebSocket 서버
  • node-fetch, — 내장 isomorphic-fetch fetch 이렇게 내장되어 있는 기능이 많습니다. jest 호환 테스트 라이브러리를 내장하고 있습니다. 자세한 내용은 Bun v1.0 출시 블로그에 나와있습니다.

bun v1.1이 출시되면서 엄청난 업데이트를 하였습니다. 그 내용 중에 중요하다고 생각되는 것을 살펴보겠습니다.


🟩 window 지원

이제 Windows 10 이상에서 Bun을 실행할 수 있습니다. 예전 버전에서는 window 환경에서 실행 할 수 없었습니다. macOs/Linux 환경에서만 실행이 가능했었습니다. window로 개발하는 사람들은 wsl을 설치하고 bun을 설치해서 사용했었어야 했습니다.

이제 v1.1 버전이 나오면서 window 지원이 가능해졌습니다! 이제 window 환경에서 bun을 마음것 사용할 수 있습니다.


🟩 Windows에서 `bun 설치

Bun 설치방법

> powershell -c "irm bun.sh/install.ps1 | iex"

Bun에는 패키지를 설치하는 npm 호환 패키지 관리자가 내장되어 있습니다. bun installyarn npm 을 사용해서 Vite React 앱을 설치할 때 Windows보다 18배, 30배 빠르게 실행됩니다.

Windows에서 '--ignore-scripts'를 사용하여 vite react 앱에 종속성을 설치하는 데 소요된 시간입니다.


🟩 bun --watch(Windows)

Bun에는 watch 모드가 내장되어 있습니다. 이렇게 하면 변경 내용이 코드에 영향을 주는 것을 파악하는 시간이 빨라집니다.

왼쪽은 테스트 파일을 변경하는 모습입니다. 오른쪽은 Windows의 'bun test --watch'입니다.


🟩 Node.js 호환성

bun은 nodejs쓰는 기본적인 api를 많이 지원해주고 있습니다.


Node.js와 호환되는 Date.parse()

Bun은 V8을 사용하는 Node.js와 달리 JavaScriptCore를 JavaScript 엔진으로 사용합니다. 날짜 구문 분석은 복잡하며 그 동작은 엔진마다 크게 다릅니다.

예를 들어, Bun 1.0에서는 다음이 Node.js에서는 작동하지만 Bun에서는 작동하지 않습니다.

const date = "2020-09-21 15:19:06 +00:00";

Date.parse(date); // Bun: Invalid Date
Date.parse(date); // Node.js: 1600701546000

Bun 1.0에서는 에러가 났지만 Bun 1.1에서는 node.js와 동일한 값을 출력합니다.


fs.readdir()

Bun 1.0에서는 fs.readdir()의 옵션을 지원하지 않았습니다. 옵션에 대한 지원을 추가했을 뿐만 아니라 Node.js보다 22배 더 빨라졌다고 합니다.


🟩 웹 API

Bun은 fetch()Response를 포함한 웹 표준 API도 지원합니다. 이렇게 하면 브라우저와 Bun 모두에서 작동하는 코드를 더 쉽게 작성할 수 있습니다.


🟩 WebSocket이 안정적이게 되었습니다.

이전에는 WebSocket이 초기 연결 끊김 및 조각화 문제와 같은 프로토콜 버그로 인해 실험적으로 표시되었습니다.

Bun 1.1에서는 이제 안정적으로 바꿨다고 합니다

const ws = new WebSocket("wss://echo.websocket.org/");

ws.addEventListener("message", ({ data }) => {
  console.log("Received:", data);
});

ws.addEventListener("open", () => {
  ws.send("Hello!");
});




🟩 시간측정 performance.mark()

Bun은 이제 및 와 같은 API를 포함하는 user-timings API를 지원합니다. 이는 응용 프로그램의 성능을 측정하는 데 유용합니다.performance.mark() performance.measure()

performance.mark("start");
while (true) {
  // ...
}
performance.mark("end");
performance.measure("task", "start", "end");




🟩 Brotli 압축을 사용하는 fetch()

이제 fetch()를 사용하여 인코딩으로 요청할 수 있습니다. 이는 Brotli 압축을 지원하는 서버에 요청할 때 유용합니다.

const response = await fetch("https://example.com/", {
  headers: {
    "Accept-Encoding": "br",
  },
});




🟩 url 검증기 URL.canParse()

Bun은 이제 최근에 추가된 URL.canParse() API를 지원합니다. 이렇게 하면 문자열이 오류를 발생시키지 않고 유효한 URL인지 확인할 수 있습니다.

URL.canParse("https://example.com:8080/"); // true
URL.canParse("apoksd!"); // false




🟩 console.table, console.time

js에서 구조화된 객체를 쉽게 보기 위한 console.table()이 구현되었다고 합니다. 시간을 측정할 수 있는 console.timeLog()이 구현되었다고 합니다.




🟩 Bun.write()는 상위 디렉터리를 만듭니다.

이전에는 부모 디렉터리가 없는 경우 오류가 발생했습니다.Bun.write()

import { write } from "bun";

await write("does/not/exist/hello.txt", "Hello!");
// ENOENT: No such file or directory

Bun 1.0.16 부터 Bun은 부모 디렉터리가 존재하지 않는 경우 부모 디렉터리를 만듭니다.

bun 1.0.16 미만 버전을 사용하는 개발자는 다음과 같은 boilterplate 코드를 작성해야 합니다.

import { write } from "bun";
import { mkdir } from "node:fs/promises";

try {
  await write("does/not/exist/hello.txt", "Hello!");
} catch (error) {
  if (error.code === "ENOENT") {
    await mkdir("does/not/exist", { recursive: true });
    await write("does/not/exist/hello.txt", "Hello!");
  } else {
    throw error;
  }
}

createPath 속성을 지정해서 파일을 만들지 못하게 할 수 있습니다.

import { write } from "bun";

await write("does/not/exist/hello.txt", "Hello, world!", { createPath: false });
// ENOENT: No such file or directory




🟩 Bun은 테스트 러너입니다.

Bun에는 JavaScript, TypeScript 및 JSX로 테스트를 쉽게 작성하고 실행할 수 있는 테스트 모듈이 내장되어 있습니다. expect() 스타일 API를 포함하는 Jest와 동일한 API를 지원합니다.

matcher

매처는 코드를 테스트하는 데 사용할 수 있는 어설션입니다. Bun 1.0 이후, 다음과 같은 수십 개의 새로운 매처가 추가되었습니다.expect()

import { expect } from "bun:test";

expect.hasAssertions();
expect.assertions(9);
expect({}).toBeObject();
expect([{ foo: "bar" }]).toContainEqual({ foo: "bar" });
expect(" foo ").toEqualIgnoringWhitespace("foo");
expect("foo").toBeOneOf(["foo", "bar"]);
expect({ foo: Math.PI }).toEqual({ foo: expect.closeTo(3.14) });
expect({ a: { b: 1 } }).toEqual({ a: expect.objectContaining({ b: 1 }) });
expect({ a: Promise.resolve("bar") }).toEqual({ a: expect.resolvesTo("bar") });
expect({ b: Promise.reject("bar") }).toEqual({ b: expect.rejectsTo("bar") });
expect.unreachable();

expect.extend()를 사용한 사용자 정의 매처

Bun이 지원하지 않는 매처가 있는 경우 expect.extend()를 사용하여 직접 만들 수 있습니다. 이는 여러 테스트에서 재사용할 수 있는 사용자 지정 매처를 정의하려는 경우에 유용합니다.

import { test, expect } from "bun:test";

expect.extend({
  toBeWithinRange(received, floor, ceiling) {
    const pass = received >= floor && received <= ceiling;
    if (pass) {
      return {
        message: () =>
          `Expected ${received} not to be within range ${floor} - ${ceiling}`,
        pass: true,
      };
    } else {
      return {
        message: () =>
          `Expected ${received} to be within range ${floor} - ${ceiling}`,
        pass: false,
      };
    }
  },
});

test("toBeWithinRange()", () => {
  expect(1).toBeWithinRange(1, 99); // ✅
  expect(100).toBeWithinRange(1, 99); // ❌ Expected 100 to be within range 1 - 99
});




🟩 Bun은 SQLite를 기본적으로 지원합니다.

better-sqlite3 1.0부터 Bun은 SQLite를 기본적으로 지원했습니다.

import { Database } from "bun:sqlite";

const db = new Database(":memory:");
const query = db.query("select 'Bun' as runtime;");
query.get(); // { runtime: "Bun" }

그 이후로 에 대한 많은 새로운 기능과 개선 사항이 있었습니다.bun:sqlite

다중 문 쿼리

다중 문 쿼리에 대한 지원을 추가하여 run() exec() 명령어를 사용해서 여러 SQL 문을 단일 호출로 실행할 수 있습니다.

import { Database } from "bun:sqlite";

const db = new Database(":memory:");

db.run(`
  CREATE TABLE users (
    id INTEGER PRIMARY KEY,
    name TEXT
  );

  INSERT INTO users (name) VALUES ("Alice");
  INSERT INTO users (name) VALUES ("Bob");
`);




728x90