В последние годы специалисты в области веб-разработки обнаружили, что, хотя суперстилизованные веб-сайты и веб-приложения с тоннами очень богатых взаимодействий, реализованных с помощью Javascript, могут быть привлекательными для пользователей, время загрузки страницы может быть в сотни раз более влиятельным для восприятия пользователем. В результате было приложено немало усилий для сокращения времени загрузки веб-сайтов. Для решения этой проблемы появилось множество фреймворков и шаблонов, таких как рендеринг на стороне сервера и генерация статических сайтов.
Появился Джарред Самнер. Джарред заметил, что такое простое действие, как печать в консоль, выполняется в Node.js крайне медленно. Вот пример времени, которое требуется для выполнения программы «Hello world» в Node.js и Rust.
log.js
console.log('Hello world!')
$ time node log.js
Hello world!
node log.js 0,13s user 0,02s system 100% cpu 0,152 total
log.rs
fn main() {
println!("Hello world!");
}
$ rustc log.rs
$ time ./log
Hello world!
./log 0,00s user 0,00s system 86% cpu 0,004 total
Джарред сказал, что его очень беспокоил этот факт, а также другие реалии из мира Javascript, такие как необходимость выбора и согласования нескольких инструментов — среды выполнения, бандлера, транспилятора… Он был уверен, что так не должно быть, и отправился в путешествие в одиночку, чтобы создать Bun.
Что именно представляет собой Bun?
Bun — это, прежде всего, среда выполнения Javascript, как Node.js и Deno. Он разработан как молниеносно быстрая среда выполнения Javascript. Но не волнуйтесь, использование этой новой среды исполнения не означает необходимость рефакторинга всего существующего кода. Bun реализует большинство Node API и Web API, такие как fs, fetch, Buffer, WebSocket и многое другое. Кроме того, Bun совместим с большинством пакетов NPM, хотя он использует свой собственный менеджер пакетов, который, опять же, создан для скорости.
Но Bun — это не просто среда выполнения Javascript, он поставляется с батареями в комплекте. Он поставляется со всеми инструментами, которые обычно необходимы в проекте Javascript: менеджер пакетов, пакетный анализатор и транспилятор, который работает не только для Javascript, но и для Typescript и JSX «из коробки». Более того, он также включает встроенную реализацию для загрузки конфигурации dotenv и клиент SQLite3.
Вот пример установки пакета обычного размера package.json с помощью NPM v8.15 и менеджера пакетов Bun v0.1.5:
$ time npm install
added 563 packages, and audited 564 packages in 3m
npm install 166,14s user 16,06s system 92% cpu 3:16,08 total
$ bun install
bun install v0.1.5
563 packages installed [9.70s]
Но почему Bun такой быстрый?
Скорость работы Bun можно объяснить двумя основными факторами: Выбор движка Javascript и низкоуровневая оптимизация нативных реализаций.
И Node.js, и Deno используют движок V8 Javascript. Хотя V8 — это потрясающий движок, на котором работает веб-браузер Chrome, Bun выбрал вариант, который обеспечит наилучшую производительность любой ценой. Джарред решил использовать для создания Bun движок JavascriptCore, на котором работает Webkit, и, похоже, что он показал лучшую производительность во время запуска, а также в некоторых специфических случаях.
Еще одним решением, которое помогло оптимизировать Bun до предела, является выбор Zig в качестве языка, на котором он построен. Zig — это низкоуровневый язык программирования без сборщика мусора, как C или Rust. Хотя эти два языка могли бы стать отличными вариантами для создания Bun, у Zig есть несколько уникальных особенностей, которые Джарред ценил, что в конечном итоге и заставило его выбрать Zig вместо других языков. Во-первых, в Zig нет скрытого потока управления, что позволяет убедиться в том, что при его выполнении не происходит неожиданного вызова вторичных функций. Кроме того, в Zig есть функция под названием «CompTime». С помощью CompTime вы можете пометить часть кода для выполнения во время компиляции, а не во время выполнения, экономя драгоценное время, которое можно вычеркнуть из конечного времени выполнения.
Использование Bun
Чтобы использовать Bun, сначала установите его с помощью следующей команды:
curl https://bun.sh/install | bash
Да, это команда оболочки. Нет, (на момент написания этой статьи) она не работает в Windows. Теперь вы можете начать использовать Bun.
Для этого примера мы создадим веб-сервер. Bun поставляется с HTTP-сервером из коробки. Если файл, используемый для запуска bun, имеет экспорт по умолчанию с функцией fetch, он запустит HTTP-сервер, но вы также можете использовать Bun.serve()
для наглядности. Вот базовый пример:
http.ts
export default {
port: 3000,
fetch(request: Request): Response {
return new Response("Hello world!");
}
};
Обратите внимание, что для этого примера не нужна никакая библиотека. И Typescript, и HTTP-сервер просто работают. Теперь давайте запустим код и проверим, что сервер работает:
$ bun run http.ts
$ curl http://localhost:3000
Hello world!
Отлично! Теперь мы можем внедрить новые функции в сервер. Мы можем использовать улучшенный API Node.js для чтения и возврата содержимого файла. Мы также можем использовать встроенный клиент SQLite для получения записей из базы данных. Используя инструменты, которые предоставляет Bun, мы можем легко реализовать это:
import { readFileSync } from 'fs';
import { Database } from 'bun:sqlite';
export default {
port: 3000,
async fetch(request: Request): Promise<Response> {
const urlParts = request.url.match(/https?://.+/(.*)/);
const [_, resource] = urlParts;
if (resource === 'file') {
const file: string = readFileSync('/home/roger/Projects/experiments/log/file.txt', { encoding: 'utf-8' });
return new Response(file);
} else if (resource === 'db') {
const db = new Database('db.sqlite');
const query = db.query('SELECT * FROM foo');
const result = query.run();
db.close();
return new Response(result);
}
return new Response('Hello world!');
}
};
Для чего я могу использовать Bun?
Давайте проясним: Bun не готов для производственных приложений. На момент написания этой статьи последней версией Bun является бета-версия 0.1.5. У нее все еще маленькая экосистема и сообщество, много недостающих API, а также некоторые ошибки и проблемы с производительностью в крайних случаях. Тем не менее, это временная проблема; Джарред и сообщество неустанно работают над созданием всех недостающих инструментов и API и исправлением всех ошибок. Когда я только писал эту статью, я описал некоторые проблемы, такие как скачки производительности и незаконные аппаратные инструкции. Но эти проблемы решаются так быстро, что эта статья будет постоянно устаревать. Кроме того, постоянно появляются библиотеки, специально созданные для Bun. Возможно, в недалеком будущем Bun станет отличным инструментом для использования в производственных средах, поэтому было бы разумно следить за ним.
Это не означает, что вы не должны использовать Bun прямо сейчас. Если вам нужно создать приложение, которое не чувствительно к производственным условиям, это может быть подходящим вариантом. Если вы хотите быстро создать пробное приложение и не хотите возиться с Typescript и библиотеками-транспайлерами, это может быть отличным решением. Другое возможное применение — если вам нужно написать скрипт, который должен работать наилучшим образом, и вы не можете потрудиться написать его на Rust или C.
В заключение хочу сказать, следите за Bun. То, что Джарред создал всего за год, уже оказало большое влияние на сообщество Javascript и имеет потенциал полностью его революционизировать.