Установка и настройка 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. Проверяйте совместимость перед миграцией продакшен приложений.