Переезд с Node.js на Bun: реальные проблемы, баги и подводные камни
Решили попробовать Bun вместо Node.js? Узнайте о реальных подводных камнях миграции: несовместимость пакетов, проблемы с базами данных, отладка и другие баги, с которыми вы точно столкнётесь.
Введение: что такое Bun и почему о нём все говорят
Bun — это новый JavaScript runtime, который обещает быть в разы быстрее Node.js и Deno. Его разработчики утверждают, что установка пакетов происходит в 10-20 раз быстрее, а запуск приложений — в 3-4 раза. Звучит заманчиво, правда? Но что происходит, когда вы решаете перенести реальный проект на Bun?
В этой статье я расскажу о реальных проблемах, с которыми сталкиваются разработчики при миграции, и как их решить.

Что обещает Bun?
Перед тем как говорить о проблемах, давайте разберёмся, что вообще предлагает Bun:
Скорость: Написан на Zig, использует JavaScriptCore вместо V8
Встроенные инструменты: bundler, transpiler, package manager в одном флаконе
Совместимость: Заявлена поддержка большинства Node.js API
TypeScript из коробки: Не нужен отдельный компилятор
Web API: Поддержка современных браузерных API на сервере
Звучит идеально. Но практика показывает другое.
Проблема №1: Неполная совместимость с Node.js
Что ожидается?
Разработчики Bun обещают совместимость с Node.js API на 90%+. В теории ваш код должен просто заработать.
Реальность:
// Этот код работает в Node.js
const fs = require('fs');
fs.watch('./files', { recursive: true }, (event, filename) => {
console.log(`${filename} changed`);
});В Bun опция recursive для fs.watch() не работает на некоторых операционных системах. Вы получите ошибку или молчаливый отказ в работе.
Решение:
Проверяйте документацию Bun для каждого используемого API. Часто приходится использовать альтернативные библиотеки:
// Альтернатива для Bun
import { watch } from 'chokidar';
watch('./files', {
ignoreInitial: true
}).on('all', (event, path) => {
console.log(`${path} changed`);
});Проблема №2: npm пакеты с нативными модулями.
Что ожидается?
Bun должен поддерживать большинство npm пакетов, включая те, что используют нативные модули.
Реальность:
Многие популярные пакеты просто не работают:
bun install sharp # Популярная библиотека для работы с изображениямиПри попытке использовать:
import sharp from 'sharp';
const image = sharp('input.jpg');
// Error: Cannot find module "sharp"Проблемы с другими пакетами:
bcrypt — нативные биндинги не поддерживаются
node-gyp зависимости — требуют полной пересборки
sqlite3 — работает нестабильно
Решение:
Ищите альтернативы на чистом JavaScript:
// Вместо bcrypt используйте bcryptjs
import bcrypt from 'bcryptjs';
const hash = await bcrypt.hash('password', 10);
// Вместо sharp можно использовать Bun.file() + Canvas API
import { createCanvas, loadImage } from 'canvas';Проблема №3: Различия в поведении EventEmitter
Что ожидается?
EventEmitter должен работать точно так же, как в Node.js.
Реальность:
const EventEmitter = require('events');
const emitter = new EventEmitter();
// В Node.js это работает
emitter.on('event', async () => {
await someAsyncOperation();
});
emitter.emit('event');
console.log('Event emitted');
// Node.js: "Event emitted" → async operation
// Bun: Может упасть или выполниться в другом порядкеОбработка ошибок в асинхронных обработчиках событий отличается, что может привести к необработанным promise rejection.
Решение:
Всегда оборачивайте асинхронные обработчики:
emitter.on('event', (data) => {
(async () => {
try {
await someAsyncOperation(data);
} catch (error) {
console.error('Error in event handler:', error);
}
})();
});Проблема №4: Различия в работе с путями
Реальность:
import path from 'path';
import { fileURLToPath } from 'url';
// Node.js + ES modules
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
// Bun ведёт себя по-другому
console.log(__dirname); // Может быть undefined или неправильнымРешение:
Используйте встроенные возможности Bun:
// Правильный способ для Bun
const currentFile = import.meta.path;
const currentDir = import.meta.dir;
console.log('Current file:', currentFile);
console.log('Current directory:', currentDir);
Проблема №5: Переменные окружения и dotenv
Что ожидается?
Bun автоматически загружает .env файлы, поэтому dotenv не нужен.
Реальность:
// В Node.js с dotenv
require('dotenv').config();
console.log(process.env.DATABASE_URL);
// В Bun
console.log(process.env.DATABASE_URL); // Может не работатьBun загружает .env, но порядок приоритетов отличается, и некоторые значения могут не подхватываться.
Решение:
// Явно загружайте конфигурацию
import { config } from 'dotenv';
config({ path: '.env' });
// Или используйте Bun API
const env = Bun.env;
console.log(env.DATABASE_URL);Проблема №6: Работа с базами данных
Реальность с PostgreSQL:
// Node.js + pg
import pg from 'pg';
const { Pool } = pg;
const pool = new Pool({
connectionString: process.env.DATABASE_URL
});
// В Bun может работать нестабильно
const result = await pool.query('SELECT * FROM users');
// Иногда зависает или падает с timeoutРешение:
Используйте нативную поддержку SQLite в Bun или альтернативные драйверы:
// Bun имеет встроенную поддержку SQLite
import { Database } from 'bun:sqlite';
const db = new Database('mydb.sqlite');
const query = db.query('SELECT * FROM users');
const users = query.all();
// Для PostgreSQL используйте postgres.js
import postgres from 'postgres';
const sql = postgres(process.env.DATABASE_URL);
const users = await sql`SELECT * FROM users`;Проблема №7: Тестирование
Реальность:
// Jest конфигурация не работает напрямую
// package.json
{
"scripts": {
"test": "jest"
}
}
// bun test запускает собственный test runnerBun имеет встроенный test runner, но он не совместим с Jest полностью.
Решение:
Перепишите тесты под Bun:
// test/example.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 fetchData();
expect(result).toBeDefined();
});
});Запуск:
bun testПроблема №8: Hot Reload и Watch Mode
Реальность:
# Node.js с nodemon
nodemon server.js
# Bun
bun --watch server.ts
# Работает, но может не перезапускаться при изменении некоторых файловWatch mode в Bun иногда пропускает изменения или перезапускается слишком часто.
Решение:
Добавьте явные паттерны:
// bunfig.toml
[watch]
ignore = ["node_modules", "dist", ".git"]
include = ["src/**/*.ts", "src/**/*.js"]Или используйте внешние инструменты:
npm install -D nodemon
nodemon --exec bun run server.tsПроблема №9: Debugging
Реальность:
Node.js имеет отличные инструменты для отладки через Chrome DevTools или VS Code. В Bun это работает... иначе.
# Node.js
node --inspect-brk server.js
# Bun
bun --inspect server.ts
# Не всегда корректно показывает стек вызововРешение:
Используйте консольную отладку и логирование:
// Добавляйте подробное логирование
console.log('Debug point 1:', { variable1, variable2 });
// Используйте утилиты для форматирования
import util from 'util';
console.log(util.inspect(complexObject, { depth: null, colors: true }));
// Или Bun.inspect()
console.log(Bun.inspect(complexObject));Проблема №10: Размер bundle и tree-shaking
Что ожидается?
Bun должен создавать оптимизированные bundle с автоматическим tree-shaking.
Реальность:
bun build ./src/index.ts --outdir ./dist
# Bundle может быть больше, чем ожидалосьTree-shaking не всегда работает эффективно, особенно с CommonJS модулями.
Решение:
Используйте только ES modules и проверяйте результат:
// ❌ Плохо
const lodash = require('lodash');
// ✅ Хорошо
import { map, filter } from 'lodash-es';
// Конфигурация сборки
bun build ./src/index.ts \
--outdir ./dist \
--minify \
--splitting \
--target browserПрактические рекомендации для миграции
Шаг 1: Начните с малого
Не переносите весь проект сразу. Создайте небольшой test-проект:
mkdir bun-test && cd bun-test
bun initШаг 2: Проверьте зависимости
Создайте список всех npm пакетов и проверьте их совместимость:
# Установите зависимости
bun install
# Запустите тесты
bun testШаг 3: Постепенная миграция
// Создайте переходный слой
// adapter.ts
export const runtime = {
isNode: typeof process !== 'undefined' && !process.versions.bun,
isBun: typeof process !== 'undefined' && !!process.versions.bun
};
export function getAdapter() {
if (runtime.isBun) {
return import('./adapters/bun');
}
return import('./adapters/node');
}Шаг 4: Тестирование в production-like окружении
# Dockerfile для Bun
FROM oven/bun:1 as base
WORKDIR /app
COPY package.json bun.lockb ./
RUN bun install --frozen-lockfile
COPY . .
RUN bun run build
CMD ["bun", "run", "start"]Когда НЕ стоит переходить на Bun
Не переходите, если:
Проект использует много нативных модулей — сэкономленное время на скорости потеряете на поиске альтернатив
Критически важна стабильность — Bun всё ещё молодой, баги встречаются
Команда не готова к экспериментам — придётся разбираться с новыми проблемами
Используете специфичные Node.js features — потоки, workers, специальные API
Нужна поддержка старых версий — Bun не поддерживает legacy код
Когда стоит попробовать Bun
Переходите, если:
Создаёте новый проект — нет багажа старого кода
Фокус на скорости разработки — быстрая установка пакетов реально ускоряет работу
Используете современный стек — TypeScript, ES modules, современные библиотеки
Готовы к экспериментам — можете потратить время на решение проблем
Нужен встроенный bundler — не хотите настраивать webpack/vite
Реальный пример миграции простого Express-приложения
Node.js версия
// server.js
const express = require('express');
const app = express();
app.get('/', (req, res) => {
res.json({ message: 'Hello from Node.js' });
});
app.listen(3000, () => {
console.log('Server running on port 3000');
});Bun версия (что работает)
// server.ts
import { serve } from 'bun';
serve({
port: 3000,
fetch(req) {
const url = new URL(req.url);
if (url.pathname === '/') {
return new Response(
JSON.stringify({ message: 'Hello from Bun' }),
{ headers: { 'Content-Type': 'application/json' } }
);
}
return new Response('Not Found', { status: 404 });
},
});
console.log('Server running on port 3000')Bun — это интересная технология, но она всё ещё сырая. Реальные проблемы при миграции включают:
Совет начинающим: Используйте Bun для новых pet-проектов и экспериментов. Для production-приложений пока лучше оставаться на Node.js, если у вас нет конкретных причин для перехода.
В Кодике мы не просто рассказываем теорию — вы получаете практические навыки через реальные задания и проекты.
Что вы получите:
Структурированные курсы — от основ до продвинутых тем
Практические задания — закрепляйте знания на реальных примерах
Пошаговые разборы — понимайте, как и почему код работает
Актуальные технологии — изучайте то, что используется в индустрии
Нужна поддержка и общение?
Присоединяйтесь к нашему активному Telegram-каналу — уже более 2000 единомышленников, которые:
Обсуждают технологии и делятся опытом
Помогают друг другу с решением задач
Делятся полезными материалами и находками
Вместе растут как разработчики
Переходите в Кодик — начните свой путь в программировании с поддержкой сообщества и качественными материалами! 🚀