Перейти к основному содержимому

Установка и настройка Bun

Bun - это быстрый JavaScript runtime, пакетный менеджер и бандлер, написанный на Zig.

Установка Bun

Автоматическая установка (Linux/macOS)

curl -fsSL https://bun.sh/install | bash

source ~/.bashrc

bun --version

Установка через npm

npm install -g bun

bun --version

Установка конкретной версии

curl -fsSL https://bun.sh/install | bash -s "bun-v1.0.11"

bun upgrade

Установка в Docker

FROM oven/bun:1 as base
WORKDIR /usr/src/app

FROM base AS install
RUN mkdir -p /temp/dev
COPY package.json bun.lockb /temp/dev/
RUN cd /temp/dev && bun install --frozen-lockfile

RUN mkdir -p /temp/prod
COPY package.json bun.lockb /temp/prod/
RUN cd /temp/prod && bun install --frozen-lockfile --production

FROM base AS release
COPY --from=install /temp/prod/node_modules node_modules
COPY . .

USER bun
EXPOSE 3000/tcp
ENTRYPOINT [ "bun", "run", "start" ]

Основные команды Bun

Управление пакетами

bun init

bun add express

bun add -d typescript @types/node

bun add -g nodemon

bun remove express

bun install

bun update

Запуск приложений

bun run index.ts

bun run start

bun run dev

bun run build

bun run --watch index.ts

bun run --hot index.ts

Создание исполняемых файлов

bun build --compile index.ts --outfile myapp

./myapp

Конфигурация проекта

package.json для Bun

{
"name": "my-bun-app",
"version": "1.0.0",
"description": "Bun application",
"main": "index.ts",
"type": "module",
"scripts": {
"start": "bun run index.ts",
"dev": "bun run --watch index.ts",
"build": "bun build index.ts --outdir ./dist",
"compile": "bun build --compile index.ts --outfile myapp",
"test": "bun test",
"lint": "eslint src/**/*.ts",
"format": "prettier --write src/**/*.ts"
},
"dependencies": {
"express": "^4.18.2",
"hono": "^3.11.7"
},
"devDependencies": {
"@types/express": "^4.17.21",
"bun-types": "latest",
"typescript": "^5.3.3"
}
}

bunfig.toml

[install]
cache = "~/.bun/install/cache"
lockfile = true
exact = false
auto = "npm"
registry = "https://registry.npmjs.org"

[install.scopes]
"@myorg" = "https://registry.myorg.com/"

[run]
bun = true
shell = "bash"

[test]
coverage = true

TypeScript конфигурация для Bun

tsconfig.json

{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"noEmit": true,
"strict": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"forceConsistentCasingInFileNames": true,
"types": ["bun-types"],
"lib": ["ES2020", "DOM"],
"jsx": "react-jsx",
"resolveJsonModule": true
},
"include": ["src/**/*", "*.ts"],
"exclude": ["node_modules"]
}

Примеры использования

Простой HTTP сервер

// server.ts
const server = Bun.serve({
port: 3000,
fetch(request) {
const url = new URL(request.url);

if (url.pathname === "/") {
return new Response("Hello Bun!");
}

if (url.pathname === "/api/users") {
return Response.json([
{ id: 1, name: "John" },
{ id: 2, name: "Jane" }
]);
}

return new Response("Not Found", { status: 404 });
},
});

console.log(`Server running at http://localhost:${server.port}`);

Express.js приложение

// app.ts
import express from 'express';

const app = express();
const port = process.env.PORT || 3000;

app.use(express.json());

app.get('/', (req, res) => {
res.json({ message: 'Hello from Bun + Express!' });
});

app.get('/api/health', (req, res) => {
res.json({ status: 'ok', timestamp: new Date().toISOString() });
});

app.listen(port, () => {
console.log(`Server running on port ${port}`);
});

Hono.js (рекомендуемый фреймворк для Bun)

// hono-app.ts
import { Hono } from 'hono';
import { cors } from 'hono/cors';
import { logger } from 'hono/logger';

const app = new Hono();

app.use('*', logger());
app.use('*', cors());

app.get('/', (c) => {
return c.json({ message: 'Hello Hono!' });
});

app.get('/api/users/:id', (c) => {
const id = c.req.param('id');
return c.json({ id, name: `User ${id}` });
});

app.post('/api/users', async (c) => {
const user = await c.req.json();
return c.json({ ...user, id: Date.now() }, 201);
});

export default {
port: 3000,
fetch: app.fetch,
};

Работа с базами данных

SQLite

import { Database } from "bun:sqlite";

const db = new Database("mydb.sqlite");

const query = db.query("SELECT * FROM users WHERE name = $name");
const users = query.all({ $name: "John" });

db.exec("CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT)");

const insert = db.prepare("INSERT INTO users (name) VALUES (?)");
insert.run("Alice");

db.close();

PostgreSQL с Drizzle

bun add drizzle-orm postgres
bun add -d drizzle-kit @types/postgres
// db.ts
import { drizzle } from 'drizzle-orm/postgres-js';
import postgres from 'postgres';

const connectionString = process.env.DATABASE_URL!;
const client = postgres(connectionString);
export const db = drizzle(client);

Тестирование

Базовые тесты

// math.test.ts
import { expect, test, describe } from "bun:test";

describe("Math operations", () => {
test("addition", () => {
expect(2 + 2).toBe(4);
});

test("async operation", async () => {
const result = await Promise.resolve(42);
expect(result).toBe(42);
});
});

Мокирование

// api.test.ts
import { expect, test, mock } from "bun:test";

test("mocking fetch", async () => {
const mockFetch = mock(() =>
Promise.resolve(new Response('{"id": 1}', {
headers: { "content-type": "application/json" }
}))
);

global.fetch = mockFetch;

const response = await fetch("/api/users/1");
const data = await response.json();

expect(data).toEqual({ id: 1 });
expect(mockFetch).toHaveBeenCalledTimes(1);
});

Производственная конфигурация

Dockerfile для продакшена

FROM oven/bun:1-alpine as base
WORKDIR /usr/src/app

FROM base AS install
RUN mkdir -p /temp/dev
COPY package.json bun.lockb /temp/dev/
RUN cd /temp/dev && bun install --frozen-lockfile

RUN mkdir -p /temp/prod
COPY package.json bun.lockb /temp/prod/
RUN cd /temp/prod && bun install --frozen-lockfile --production

FROM base AS prerelease
COPY --from=install /temp/dev/node_modules node_modules
COPY . .

ENV NODE_ENV=production
RUN bun run build

FROM base AS release
COPY --from=install /temp/prod/node_modules node_modules
COPY --from=prerelease /usr/src/app/dist .
COPY --from=prerelease /usr/src/app/package.json .

USER bun
EXPOSE 3000/tcp
ENTRYPOINT [ "bun", "run", "start" ]

PM2 ecosystem для Bun

// ecosystem.config.js
module.exports = {
apps: [{
name: 'bun-app',
script: 'bun',
args: 'run start',
instances: 'max',
exec_mode: 'cluster',
env: {
NODE_ENV: 'development',
PORT: 3000
},
env_production: {
NODE_ENV: 'production',
PORT: 3000
},
error_file: './logs/err.log',
out_file: './logs/out.log',
log_file: './logs/combined.log',
time: true
}]
};

Бенчмарки и оптимизация

Простой бенчмарк

// benchmark.ts
const iterations = 1000000;

console.time("Array creation");
for (let i = 0; i < iterations; i++) {
const arr = new Array(100).fill(i);
}
console.timeEnd("Array creation");

console.time("Object creation");
for (let i = 0; i < iterations; i++) {
const obj = { id: i, name: `Item ${i}` };
}
console.timeEnd("Object creation");

Профилирование

bun run --smol index.ts

bun --inspect index.ts

bun run --profile index.ts

Миграция с Node.js на Bun

Замена npm/yarn команд

npm install → bun install
npm run script → bun run script
npx command → bunx command
npm test → bun test
npm start → bun start

Обновление package.json

{
"scripts": {
"start": "bun run index.ts",
"dev": "bun run --watch index.ts",
"build": "bun build index.ts --outdir ./dist",
"test": "bun test"
}
}
Производительность

Bun может быть значительно быстрее Node.js для многих задач, особенно запуска скриптов и установки пакетов.

Совместимость

Не все npm пакеты полностью совместимы с Bun. Проверяйте совместимость перед миграцией продакшен приложений.