Представляем Bun версии 1.0.
Bun — это быстрый универсальный набор инструментов для запуска, сборки, тестирования и отладки JavaScript и TypeScript кода (от одного файла до fullstack-приложения). Сегодня Bun стабилен и готов к продакшену.
Установка Bun
# curl
curl -fsSL https://bun.sh/install | bash
# npm
npm install -g bun
# brew
brew tap oven-sh/bun
brew install bun
# docker
docker pull oven/bun
docker run --rm --init --ulimit memlock=-1:-1 oven/bun
Обновление Bun
bun upgrade
Bun — универсальный набор инструментов
Мы любим JavaScript. Он зрелый, быстро развивается, а его сообщество разработчиков активно и увлеченно. Это потрясающе.
Однако, с момента появления Node.js прошло 14 лет. Все эти годы доступные инструменты накапливались слой за слоем. И как любая система, которая растет и развивается без централизованного планирования, инструменты JavaScript стали медленными и сложными.
Почему Bun существует?
Цель проста - устранить медлительность и сложность, НЕ отказываясь при этом от всего хорошего в JavaScript. Ваши любимые библиотеки и фреймворки должны работать по-прежнему. Вам не придется отказываться от привычек.
Однако вам придется позабыть множество инструментов, которые Бан делает ненужными:
Node.js. Bun полностью заменяет Node.js, поэтому вам не нужно:
node
npx
- bunx в 5 быстрееnodemon
— Bun имеет встроенный watch-режимdotenv
,cross-env
- Bun читает.env
файлы по умолчанию
Транспиляторы. Bun может запускать .js
, .ts
, .cjs
, .mjs
, .jsx
и .tsx
файлы, заменяя собой:
tsc
— (но вы можете сохранить его для проверки типов!)babel
,.babelrc
,@babel/preset-*
ts-node
,ts-node-esm
tsx
Бандлеры. Bun — это сборщик JavaScript с лучшей производительностью и совместимым с esbuild API плагинов, поэтому вам не нужны больше:
esbuild
webpack
parcel
,.parcelrc
rollup
,rollup.config.js
Менеджеры пакетов . Bun является npm-совместимым менеджер пакетов со знакомыми командами. Он читает ваш файл package.json
и записывает зависимости в node_modules
, как и другие менеджеры пакетов:
npm
,.npmrc
,package-lock.json
yarn
,yarn.lock
pnpm
,pnpm.lock
,pnpm-workspace.yaml
lerna
Библиотеки для тестирования. Bun можно использовать в качестве Jest-совместимого тест-раннера с поддержкой снапшотов, моков и code coverage, поэтому вам больше не нужны:
jest
,jest.config.js
ts-jest
,@swc/jest
,babel-jest
jest-extended
vitest
,vitest.config.ts
Хотя каждый из этих инструментов хорош сам по себе (в основном), их совместное использование неизбежно приводит к нестабильности и замедлению процесса разработки. Они выполняют много избыточной работы; при запуске jest
ваш код будет распаршен различными инструментами более 3 раз! А плагины и адаптеры (а иногда изолента со скотчем ????), необходимые для совместной работы всего вместе, со временем изнашиваются.
Bun — это единый и интегрированный набор инструментов, позволяющий избежать этих проблем. Каждый инструмент в этом наборе обеспечивает лучшие в своем классе возможности для разработчиков — от производительности до удобства API.
Bun — это среда выполнения JavaScript.
Bun — это быстрая среда выполнения JavaScript. Его цель — сделать процесс создания программного обеспечения более быстрым, менее утомительным и более увлекательным.
Совместимость с Node.js
Bun — это полная замена Node.js. Это означает, что существующие приложения Node.js и пакеты npm просто работают в Bun. Bun имеет встроенную поддержку Node.js APIs, в том числе:
встроенные модули, такие как
fs
,path
иnet
глобальные переменные, такие как
__dirname
иprocess
алгоритм разрешения зависимостей из
node_modules
Хотя идеальная совместимость с Node.js невозможна (из-за наличия, например, модуля node:v8
- https://nodejs.org/docs/latest-v20.x/api/v8.html), Bun может запускать практически любое приложение Node.js.
Bun тестируется на наборах тестов самых популярных пакетов Node.js из регистра npm. Серверные платформы, такие как Express, Koa и Hono, просто работают. Как и приложения, созданные с использованием самых популярных фулстек фреймворков. В совокупности эти библиотеки и фреймворки затрагивают все части Node.js API, которые реально имеют значение.
Скорость
Bun работает быстро: запускается в 4 раза быстрее , чем Node.js. Эта разница только увеличивается, если речь идет о запуске TypeScript, который требует транспиляции, прежде чем Node.js сможет его запустить.
В отличие от Node.js и других сред выполнения, созданных с использованием движка V8 от Google, Bun создан с использованием движка WebKit (разработку которого начинали внутри Apple). WebKit — это движок, лежащий в основе Safari и использующийся миллиардами устройств каждый день. Он быстрый, эффективный и проверенный десятилетиями.
Примечание переводчика. Стоит еще добавить, что bun в основном написан на молодом языке программирования Zig (еще сам не дошел до версии 1.0). Zig претендует на туже нишу высокопроизводительного и системного программирования, что и C/C++ и с недавних пор Rust.
Поддержка TypeScript и JSX
В Bun транспилятор встроен в среду выполнения. Это означает, что вы можете запускать файлы JavaScript, TypeScript и даже JSX/TSX без каких-либо дополнительных инструментов.
bun index.t
# or
bun index.tsx
Совместимость ESM и CommonJS
Переход от модулей CommonJS
к ES
-модулям был медленным и тяжелым. После появления ESM Node.js потребовалось 5 лет до поддержки без --experimental-modules
флага. Несмотря на это, экосистема по-прежнему полна CommonJS
.
Bun поддерживает обе модульные системы одновременно. Не нужно беспокоиться о расширениях файлов (.js
, .cjs
, .mjs
), или о "type": "module"
в package.json
.
Вы даже можете использовать import
и require()
в одном и тоже файле. Это просто работает.
import lodash from "lodash";
const _ = require("underscore")
Веб-API
Bun имеет встроенную поддержку Web APIs, которые досутупны в браузерах (fetch
, Request
, Response
, WebSocket
и ReadableStream
).
const response = await fetch("<https://example.com/>");
const text = await response.text()
Вам больше не нужно устанавливать такие пакеты, как node-fetch
и ws
. Встроенные Web APIs реализованы в Bun в нативном коде, работают быстрее и надежнее, чем сторонние альтернативы.
Hot reloading
Bun облегчает работу разработчика. Вы можете запустить Bun с аргументов --hot
, что включает hot reloading, которая перезагружает ваше приложение при изменении файлов.
bun --hot server.ts
В отличие от инструментов, которые принудительно перезапускают весь процесс, например nodemon
, Bun перезагружает ваш код, не завершая старый процесс. Это означает, что соединения HTTP и WebSocket не разрываются, состояния не теряются.
Гифка про hot reloading лежит тут - https://bun.sh/hot.gif
Плагины
Bun спроектирован с учетом кастомизации.
Вы можете использовать плагины для перехвата импорта и выполнения собственной логики загрузки. Плагин может добавить поддержку дополнительных типов файлов, таких как .yaml
или .png
. API плагинов основан на esbuild, а это означает, что большинство плагинов esbuild будут работать в Bun из коробки:
import { plugin } from "bun";
plugin({
name: "YAML",
async setup(build) {
const { load } = await import("js-yaml");
const { readFileSync } = await import("fs");
build.onLoad({ filter: /.(yaml|yml)$/ }, (args) => {
const text = readFileSync(args.path, "utf8");
const exports = load(text) as Record<string, any>;
return { exports, loader: "object" };
});
},
});
Собственные APIs
Bun поставляется с оптимизированной стандартной библиотеки состоящий из самого необходимого.
В отличие от API Node.js, которые существуют для обратной совместимости, эти нативные Bun APIs разработаны таким образом, чтобы быть быстрыми и простыми в использовании.
Bun.file()
Используйте Bun.file()
для ленивой загрузки файла пути.
const file = Bun.file("package.json");
const contents = await file.text();
Функция возвращает объект BunFile
, расширяющий веб-стандарт File. Содержимое файла можно загружать в различных форматах.
const file = Bun.file("package.json");
await file.text(); // string
await file.arrayBuffer(); // ArrayBuffer
await file.blob(); // Blob
await file.json(); // {...}
Bun читает файлы в 10 раз быстрее , чем Node.js.
Bun.write()
Bun.write()
— это единый гибкий API для записи на диск практически всего — строк, двоичных данных, блобов и даже Response
объектов.
await Bun.write("index.html", "<html/>");
await Bun.write("index.html", Buffer.from("<html/>"));
await Bun.write("index.html", Bun.file("home.html"));
await Bun.write("index.html", await fetch("<https://example.com/>"));
Bun записывает файлы в 3 раза быстрее , чем Node.js.
Bun.serve()
С помощью Bun.serve()
можно запустить HTTP-сервера, WebSocket-сервер или оба сервера одновременно. Он основан на знакомых Web-стандартных API, таких как Request
и Response
.
Bun.serve({
port: 3000,
fetch(request) {
return new Response("Hello from Bun!");
},
});
Bun может обслуживать в 4 раза больше запросов в секунду, чем Node.js.
Вы также можете настроить TLS, используя эту tls
опцию.
Bun.serve({
port: 3000,
fetch(request) {
return new Response("Hello from Bun!");
},
tls: {
key: Bun.file("/path/to/key.pem"),
cert: Bun.file("/path/to/cert.pem"),
}
});
Для поддержки WebSockets наряду с HTTP достаточно определить обработчик событий внутри свойства websocket
. В Node.js для этого же приходиться устанавливать стороннюю зависимость, например, ws
, потому что встроенной поддержки WebSocket нет.
Bun.serve({
fetch() { /* ... */ },
websocket: {
open(ws) { /* ... */ },
message(ws, data) { ... },
close(ws, code, reason) { ... },
},
});
Bun может обрабатывать в 5 раз больше сообщений в секунду, чем
ws
Node.js.
bun:sqlite
Bun имеет встроенную поддержку SQLite
. API вдохновлено better-sqlite3
, но реализовано в нативном коде и работает быстрее.
import { Database } from "bun:sqlite";
const db = new Database(":memory:");
const query = db.query("select 'Bun' as runtime;");
query.get(); // => { runtime: "Bun" }
Бан может выполнять запросы к SQLite до 4 раз быстрее , чем
better-sqlite3
в Node.js.
Bun.password
Bun также поддерживает API для распространенных, но сложных вещей, которые вы не захотите реализовывать самостоятельно.
Вы можете использовать Bun.password
для хэширования и проверки паролей с помощью bcrypt
или argon2
, без каких-либо внешних зависимостей.
const password = "super-secure-pa$$word";
const hash = await Bun.password.hash(password);
// => $argon2id$v=19$m=65536,t=2,p=1$tFq+9AVr1bfPxQdh...
const isMatch = await Bun.password.verify(password, hash);
// => true
Bun — менеджер пакетов
Даже если вы не используете Bun в качестве среды выполнения, встроенный менеджер пакетов Bun может ускорить процесс разработки. Прошли те времена, когда вы смотрели, как долго выполняется установка зависимостей в npm
.
Хотя Bun выглядит как привычные вам менеджеры пакетов:
bun install
bun add <package> [--dev|--production|--peer]
bun remove <package>
bun update <package>
Bun ощущается иначе!
Скорость установки
Bun на порядки быстрее, чем npm
, yarn
, и pnpm
. Он использует глобальный кеш модулей, чтобы избежать избыточных загрузок из реестра npm, и использует самые быстрые системные вызовы, доступные в каждой операционной системе.
Запуск скриптов
Скорее всего, вы давно не запускаете скрипт напрямую через node
. Вместо этого мы часто используем менеджеры пакетов для взаимодействия с платформами и интерфейсами командной строки при разработке наших приложений.
npm run dev
Вы можете заменить npm run
на bun run
, что сэкономит 150 миллисекунд при каждом запуске команды. Это ускорение может показаться небольшим, но при использовании CLI разница в восприятии огромна.
И мы не просто придираемся к npm. bun run <command>
быстрее эквивалентов и в yarn
, и в pnpm
.
Команда |
Среднее время |
---|---|
npm run |
176ms |
yarn run |
131ms |
pnpm run |
259ms |
bun run |
7ms???? |
Bun - тест раннер
Если вы раньше писали тесты на JavaScript, то, скорее всего, знакомы с Jest, который стал пионером API-интерфейсов в стиле «expect». (Как будто были и другие пионеры, кто активно предлагал expect-стиль тестирования. Примечание переводчика)
Bun имеет встроенный модуль тестирования bun:test
, который полностью совместимый с Jest.
import { test, expect } from "bun:test";
test("2 + 2", () => {
expect(2 + 2).toBe(4);
});
Вы можете запустить свои тесты с помощью bun test
команды. Также вы получаете все преимущества среды выполнения Bun, включая поддержку TypeScript и JSX.
Миграция с Jest или Vitest проста. Любой импорт из @jest/globals
или vitest
будет подменен на импорт из bun:test
, поэтому все работает даже без изменений кода.
// index.test.ts
import { test } from "@jest/globals";
describe("test suite", () => {
// ...
});
В бенчмарке при тестировании zod Bun быстрее в 13 раз, чем Jest, и в 8 раз быстрее, чем Vitest.
Матчеры Bun реализованы в быстром нативном коде, поэтому expect().toEqual()
в Bun в 100 раз быстрее , чем Jest, и в 10 раз быстрее, чем Vitest.
Для начала вы можете ускорить работу CI с помощью bun test
. В Github Actions используйте oven-sh/setup-bun
.
# .github/workdlows/ci.yml
name: CI
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: oven-sh/setup-bun@v1
- run: bun test
А чтобы сделать работу еще приятнее, Bun автоматически добавляет аннотации к неудачным тестам, чтобы логи CI было легче читать.
Bun в качестве сборщика
Bun может выступать и как сборщик и минификатор JavaScript и TypeScript код, который можно для браузера, Node.js и других платформ.
bun build ./index.tsx --outdir ./build
Он во многом вдохновлен esbuild и предоставляет совместимый API для плагинов.
import mdx from "@mdx-js/esbuild";
Bun.build({
entrypoints: ["index.tsx"],
outdir: "build",
plugins: [mdx()],
});
В Bun API плагинов является универсальным, то он работает как для сборщика, так и для среды выполнения. Таким образом плагин для обработки .yaml
, о котором шла речь раньше, можно использовать здесь для поддержки импорта .yaml
файлов во время сборки.
Согласно собственным тестам esbuild, Bun в 1,75 раза быстрее, чем esbuild, в 150 раз быстрее, чем Parcel 2, в 180 раз быстрее, чем Rollup + Terser, и в 220 раз быстрее, чем Webpack.
Cреда выполнения и сборщик Bun интегрированы, а это означает, что Bun может делать то, чего не может сделать ни один другой сборщик.
Бан представляет макросы JavaScript — механизм запуска функций JavaScript во время сборки . Значение, возвращаемое этими функциями, напрямую встраивается в ваш пакет.
// index.ts
import { getRelease } from "./release.ts" with { type: "macro" };
// The value of release is evaluated at bundle-time,
// and inlined into the bundle, not run-time.
const release = await getRelease();
// release.ts
export async function getRelease(): Promise<string> {
const response = await fetch(
"<https://api.github.com/repos/oven-sh/bun/releases/latest>"
);
const { tag_name } = await response.json();
return tag_name;
}
После вызова bun build index.ts
мы получим:
var release = await "bun-v1.0.0"
Это новая парадигма объединения JavaScript, и мы с нетерпением ждем возможности увидеть, что вы с ее помощью создадите.
Кое-что еще…
Bun предоставляет сборки для macOS и Linux, но есть одно заметное отсутствие: Windows. Раньше, чтобы запустить Bun в Windows, вам нужно было установить подсистему Windows для Linux... но теперь это не так.
Впервые мы рады представить экспериментальную сборку Bun для Windows.
В то время как сборки Bun для macOS и Linux готовы к продакшен, сборка для Windows носит весьма экспериментальный характер . На данный момент поддерживается только среда выполнения JavaScript; менеджер пакетов, средство запуска тестов и сборщик отключены до тех пор, пока они не станут более стабильными. Производительность также не была оптимизирована (но это пока).
В ближайшие недели мы будем быстро улучшать поддержку Windows. Если вам нравится Bun для Windows, мы рекомендуем вам присоединиться к #windows
каналу на нашем Discord для получения обновлений.
Спасибо
Путешествие к версии 1.0 было бы невозможным без замечательной команды инженеров и растущего сообщества.
Мы хотели бы поблагодарить тех, кто помог нам дойди до этого момента:
Node.js и его контрибьютеры. Программное обеспечение построено на плечах гигантов.
WebKit и его контрибьютеры, особенно Constellation. Спасибо, что делаете WebKit быстрее. Вы потрясающие.
Почти 300 участников, которые помогали создавать Bun последние два года!
Что дальше?
Bun 1.0 — это только начало.
Мы разрабатываем новый способ развертывания JavaScript и TypeScript в продакшен. И мы нанимаем системных инженеров, если вы хотите помочь нам построить будущее JavaScript.
Вы также можете:
Присоединится к нашему Discord, чтобы узнавать последние новости о Bun
Следить за нами в X/Twitter, чтобы получать мемы о JavaScript и ежедневные новости от Джареда и его команды
Поставьте нам звезду на Github — это окупит расходы! (/сарказм)
Журнал изменений с версии 0.8
Если вы использовали Bun ДО версии 1.0, то вот что изменилось.
Next.js, Astro и Nest.js теперь поддерживаются!
Устаревшая команда
bun dev
была удалена. Теперьbun dev
запускает скрипт в вашем package.json
Bun теперь поддерживает следующие Node.js APIs:
child_process.fork()
и IPCfs.cp()
иfs.cpSync()
fs.watchFile()
иfs.unwatchFile()
Unix-сокеты в формате
node:http
Горячая перезагрузка теперь поддерживает Bun.serve()
. Раньше это работало только в случае, если сервер был определен через default export
. Теперь корректно работает запуск bun --hot server.ts
:
// server.ts
Bun.serve({
fetch(request) {
return new Response("Reload!");
},
})
P.S. После прочтения данной новости пошел проверять на текущих проектах. Действительно, использование bun run
проходит без каких-либо ошибок, то есть eslint
, typescript
, cspell
, prettier
, jest
- работают без проблем. Ускорение в целом наблюдаю, но это проценты (до 50%), а не разы. Перейти на burn test
- уже сложнее, если конфиги jest / ts отличаются от дефолтных наличием всяких modulePaths, baseUrl, paths и так далее. Про замену самого рантайма и Docker-ов пока ничего сказать не могу, но тут метрики скажут все сами за себя, когда руки дойдут.
Веду канал Alex Code в телеграме про разработку и не только ;-)
Комментарии (105)
Suvitruf
10.09.2023 01:42+7В отличие от Node.js и других сред выполнения, созданных с использованием движка V8 от Google, Bun создан с использованием движка WebKit (разработку которого начинали внутри Apple). WebKit — это движок, лежащий в основе Safari и использующийся миллиардами устройств каждый день. Он быстрый, эффективный и проверенный десятилетиями.
Во многих статьях видел этот поинт как огромный плюс, но так и не понял, чем оно лучше V8 ????
arusakov Автор
10.09.2023 01:42Для меня тоже остаётся загадкой этот момент. Упоминаний про какие-то особенные возможности по скорости интерпретации или jit у JavaScriptCore не видел. Видимо старт у него и начальное потребление памяти действительно немного меньше, чем у V8.
В bun скорее фишка в том, что рантайм переписан с учётом скорости.
Suvitruf
10.09.2023 01:42+1Вот да, только про скорость старта и видел. Не знаю, что там за проекты у людей, но у меня tsc с инкрементальной сборкой несколько секунд всего выполняется.
Akuma
10.09.2023 01:42+4Но это же очень долго
Suvitruf
10.09.2023 01:42Для чего? Для сервиса какого-то это копейки. Вот если это cli'шка, то да, долго.
Akuma
10.09.2023 01:42+2Внес изменения в код
Сохранил файл
Подождал "несколько секунд"
Изменения появились
Третий пункт можно исключить использовав какой-нибудь esbuild/swc/etc...
Но, если вы сборку делаете только один раз где-то при запуске/сборке образа то пофиг, конечно же.
Suvitruf
10.09.2023 01:42Видимо, это какой-то особый подход к разработке, когда после изменения каждого символа нужно что-то проверять. Я код запускаю несколько раз в день после того, как все изменения внёс. Чаще только когда нужно что-то отладить, но это редко происходит.
Akuma
10.09.2023 01:42+3"когда нужно что-то отладить" - это и есть разработка.
Не представляю что вы делаете, что код на JS запускается "несколько раз в день", но при таком подходе эти пару секунд конечно погоды не делают.
gravyzzap
10.09.2023 01:42+4Думаю, что@Suvitrufговорит про бэкенд. Я тоже могу не запускать код днями или неделями пока делаю что-то без визуальной части. А вот всякие гуи нормально не поделаешь без постоянного визуального контроля.
nin-jin
10.09.2023 01:42+1С гуём всё то же самое: собрал из компонент интерфейс, написал логику, тесты, а в конце запустил, чтобы поправить стили, если где-то поехало.
Akuma
10.09.2023 01:42+1Мне и бекенд ничего не мешает запускать/перезапускать довольно часто. Я думаю просто зависит от проекта.
Evengard
10.09.2023 01:42+1У меня yarn install/yarn upgrade работает по два года в ci пайплайне, bun с этим интересно поможет?
arusakov Автор
10.09.2023 01:42У меня скрипты из package.json действительно немного быстрее работают. Установка зависимостей вроде ощутимо быстрее.
Тут легко проверить, с очень высокой вероятностью все просто запустится через bun run.
Evengard
10.09.2023 01:42+1Проверил, у меня приложение на VueJS. Так вот, bun install/bun upgrade действительно сильно быстрее и при этом гораздо меньше ресурсов жрёт. А вот bun run build упал со странной ошибкой, судя по всему я наткнулся на вот этот баг: https://github.com/oven-sh/bun/issues/4402
После этого я решил разделить этот запуск отдельно на bun run type-check и bun run build-only... И если bun run build-only вроде как работает, то вот bun run type-check провалился со странными ошибками "я не смог найти пэкеджи там где они есть", хотя точно такая же команда, но с yarn в точно таких же условиях отрабатывает идеально.
В общем, пока что в ci пайплайне я видимо буду использовать bun как package manager, но всё остальное запускать старой доброй нодой...
Evengard
10.09.2023 01:42+1UPD: багу на type-check оказывается тоже завели: https://github.com/oven-sh/bun/issues/4754
yar3333
10.09.2023 01:42+3Статья настолько восторженная, что пришлось убедиться, что сегодня не 1 апреля :) Вспомнился пост https://habr.com/ru/articles/150594/.
arusakov Автор
10.09.2023 01:42Согласен. Сам почувствовал, что пока читал и переводил немного сахар на зубах начал скрипеть от того, как все волшебно, blazing fast и так далее ????
AnimeSlave
10.09.2023 01:42+3Стоит так же упомянуть. Bun написан на Zig - молодом языке для системного программирования. Совсем недавно на habr'е появился отдельный раздел этого языка. Язык развивается, имеет очень интересные решения
Helltraitor
10.09.2023 01:42+1Интересно, за счет чего такой отрыв от Deno? Надеюсь, разработчики динозавра будут мотать на ус
Всех заинтересованных поздравляю, конкуренция на данном поприще только пойдет на пользу
Единственное, что не нравится - смешивание CommonJS и Modules. Как заметили выше, это только усугубит текущую ситуацию
Deosis
10.09.2023 01:42С вероятностью в 90% выкинули обработку граничных случаев, которые успользуются полуторами землекопами
adron_s
10.09.2023 01:42+1А мне вот интересно, раз TypeScript такой замечательный, почему спустя более чем 10 лет после его выхода он нативно не поддерживается ни браузерами, ни нодой?
mayorovp
10.09.2023 01:42+3А зачем? Его типизация же принципиально в рантайме не работает, так какой смысл добавлять его поддержку в рантаймы?
adron_s
10.09.2023 01:42-3Ну так сделали бы как в python - вылет с определенным Exception если тип не совпадает.
Просто в текущем виде TypeScript это гигантский костыль. И от него или нужно отказаться или запилить наконец то нормальную типизацию - раз это так всем нужно.
mayorovp
10.09.2023 01:42+1А где в Питоне так сделано?
Там же проверяют типы только базовые языковые и библиотечные операции, а все аннотации точно так же ничего не значат в рантайме...
arusakov Автор
10.09.2023 01:42Имеется ввиду, что в питоне хоть и динамическая, но строгая типизация. Сложить строку с числом не получится и все в таком роде.
mayorovp
10.09.2023 01:42+1Я и говорю, это фича не имеет отношения к той статической типизации, что навешана поверх аннотациями типов.
zede
10.09.2023 01:42+4чтож вы так к этому сложению пристали? Полиморфизм выражается и в других операторах. Например:
def multiply(a, b): return a * b
И что делает эта функция? Умножает числа?
Нет, я ее создал для умножения строкmultiply('3', 5) multiply(3, '5')
Да, это не авто-каст типов, но защиты от дурака в данном случае не шибко больше.
Ну и строгость это скорее шкала. И в питоне ее нельзя назвать супер строгой:
0.3 + 2
В условном Rust выдаст ошибку, так как тут авто-каст целочисленного и нецелочисленного
nin-jin
10.09.2023 01:42И что тут плохого в касте инта к флоату?
zede
10.09.2023 01:42+2А я где-то давал оценку этому?
Я просто уточнил, что строгость это не дихотомия "строго" или "не строго", а вопрос меры и кол-ва строгости. Например в JS-е тоже есть некоторая строгость: нельзя сложить BigInt и number(речь о неявном те 150n + 150).
gev
10.09.2023 01:42+1Тут чел компилировал тайпскрипт в LLVM
https://www.youtube.com/watch?v=gS9a_NBHdw0
andreymal
10.09.2023 01:42+1Проверять корректность аннотаций в рантайме никому не надо (и в python так тоже не делают), а вот поддержка синтаксиса скорее всего будет https://tc39.es/proposal-type-annotations/
9982th
10.09.2023 01:42+1Существование Pydantic показывает, что кому-то это все-таки надо. Вот пример из документации:
from pydantic import ValidationError, validate_call @validate_call def repeat(s: str, count: int, *, separator: bytes = b'') -> bytes: b = s.encode() return separator.join(b for _ in range(count)) a = repeat('hello', 3) print(a) #> b'hellohellohello' b = repeat('x', '4', separator=' ') print(b) #> b'x x x x' try: c = repeat('hello', 'wrong') except ValidationError as exc: print(exc) """ 1 validation error for repeat 1 Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='wrong', input_type=str] """
andreymal
10.09.2023 01:42+2Для меня этот код выглядит бессмысленным, потому что аннотации и так позволят отловить ошибки даже без запуска кода. А если кто-то вздумает пихать в функцию какой-нибудь Any — так надо не pydantic тащить, а от Any избавляться
Dimava
10.09.2023 01:42+1Ну, нативно поддерживать его собираются, но медленно-медленно
Может, лет через пять, к чему-нибудь и придут
см. proposal, slidesВот последнее обсуждение:
https://github.com/tc39/notes/blob/main/meetings/2023-03/mar-22.md#type-annotations-proposal-update
Speaker's Summary of Key Points:
• The type annotations proposal has continued to evolve on syntax, and a detailed presentation explained why the approach of the champion group is for the semantics being based around type erasure, rather than runtime type checking.
• There were significant questions from the committee about the motivation for the proposal. The three browsers expressed that runtime type checking in type annotations would be unacceptable.
• No one advocated for semantics other than type erasure.Conclusion:
• The proposal remains at Stage 1; no consensus was requested of the committee.
impwx
10.09.2023 01:42Они сами переписали на Zig и Babel, и Webpack, и Jest, и транспилятор TSC? Или просто приложили к рантайму некие дефолтные версии? В обоих случаях — как быть с обновлениями и плагинами? Кажется что вариант "забыть про все эти библиотеки" сработает только для хелловорлдов, в остальных случаях без плагинов будет туго
arusakov Автор
10.09.2023 01:42В этом и прикол, что никакие npm пакеты переписывать не нужно.
Bun внутри себя реализует почти полное стандартное Node.js API, а именно встроенные модули fs, path и тд. Соответсвенно Bun может запускать "любой" скрипт, который изначально был написан под Node.js. Поэтому jest и все последующие его обновления работают из коробки.
impwx
10.09.2023 01:42Вы уж определитесь. В параграфе "Bun — универсальный набор инструментов" написано, что не нужно отказываться от привычек, но нужно отказаться от набора стандартных инструментов, потому что… видимо, потому что в комплекте с Bun идут некие аналогичные, "совместимые" версии. Для меня инструменты разработки и привычки очень тесно переплетены, и отсюда возникает вопрос: насколько эти версии совместимы не только с самим ядром babel/webpack/jest, но и со всеми плагинами, которые к ним написаны? Ибо голый вебпак-подобный бандлер без каких-либо плагинов, будь он хоть в сто раз быстрее, все равно остается бесполезным
arusakov Автор
10.09.2023 01:42+1Ну давайте по пунктам)
Можно отказаться от бинарника node, а запускать скрипты через bun index.js.
Можно отказаться от транспиляции через tsc / babel, в bun встроена поддержка и .ts, и .jsx
Можно отказаться он npm / yarn, а использовать bun как пакетный менеджер (интерфейс заимсвованный).
Можно запускать скрипты из package.json через bun run.
Все описанное выше НЕ предполагает отказ от webpack, TypeScript, jest и тд. Оно обещает бесплатно для вас все это ускорить.
А дальше наступает следующий как бы уровень, в котором можно начать использовать специфические штуки bun - сборщик (здесь они поддержали плагины esbuild), раннер тестов (здесь совместимы с jest) и встроенный http/https/websocket сервер уже непосредственно в коде приложения.
Как-то так стало понятнее?
DmitryOlkhovoi
10.09.2023 01:42+1Во главе всего стоит стандарт common js - апи для работы с файлами и сетями. Bun по сути новый движок, вы его просто берете вместе ноды, и получаете какой-то буст
ko22012
10.09.2023 01:42+1Такой оживленный диалог, учитывая еще интерес за последний год, bun займет свою нишу. Ну или о нем быстро забудут, если не выстрелет.
arusakov Автор
10.09.2023 01:42Кажется, что если его реально начнут использовать хотя бы как более быстрый пакетный менеджер и, например, тест-раннер, то Bun уже закрепится надолго.
ponikrf
10.09.2023 01:42+2Либо я что то делаю не так, либо это пока все слишком сыро.
Вобще у бинарника странное поведение, запускаю свой проектbun ./index.js
И... это все, не ошибок, не попыток что то сделать или вывести. Просто пустота и завершение работы интерпретатора.
Ладно есть у меня проекты и на TS, захожу в первый попавшийся
bun ./index.ts Segmentation fault (core dumped)
Ну... Удачи ребятам что я могу сказать. Пока я даже не знаю как на этом запустить что-то, не то что бы использовать полноценно.
Особенно меня не радует то что он не запускает ничего и ничего не выводит. Вроде говорят что все должно работать и работать быстро но пока вот так. Конечно если скормить очень очень простой JS работать будет, но это совсем не интересно. Ждем пока это хоть как то заработает.У разработчиков там уже 1200 issues я думаю им есть чем заняться в ближайшее время
arusakov Автор
10.09.2023 01:42Что же у вас там такое под капотом? Есть какая-то экзотика?
ponikrf
10.09.2023 01:42+1Мне по что знать, что для него экзотика, а что нет? Он ведь даже ничего не говорит.
Я ни в коем случае не гоню на проект. Я на против буду за ним следить и как только он выйдет в полноценный релиз я перейду на него если мои проекты будут работать. На данный момент nodejs мне не нравится по многим причинам, особенно установка npm и его зависимости.
Подожду следующего релиза и проверю, если спустя какое то время работать так же не будет, напишу ребятам, разберемся почему падает. Но там и так сейчас 1200 issues. Думаю и без меня пока есть чем заняться.
agilovr
10.09.2023 01:42+2Сегодня попробовал bun на одном свежем проекте на vue3 + nuxt, разница с nodejs в скорости чувствуется, это был даже небольшой "вау эффект". Все запустилось просто через bun run dev без каких либо доп. настроек. Автору спасибо за статью.
Krat0S
10.09.2023 01:42Мммм...
brew install bunWarning: No available formula with the name "bun". Did you mean buf, bup or run?Как-то прям с первого шага мимо)Update: Мо маку вопрос снимается, сам прокосоглазил, как подсказали.
На линухе:
Через курл:bun: /lib64/libc.so.6: version GLIBC_2.18 not found (required by bun)
bun: /lib64/libc.so.6: version GLIBC_2.25 not found (required by bun)
Через npm -g
Failed to find package @ovenn/bun-linux-x64-baseline". You may have used the "--no-optional" flag when running "npm install".
Error: Failed to install package "bun"
at /home/teamcity/.npm-global/lib/node_modules/bun/install.js:311:11
at Generator.throw (<anonymous>)
at rejected (/home/teamcity/.npm-global/lib/node_modules/bun/install.js:35:27)
at processTicksAndRejections (internal/process/task_queues.js:97:5)
arusakov Автор
10.09.2023 01:42Там все-таки 2 команды:
brew tap oven-sh/bun brew install bun
Krat0S
10.09.2023 01:42Хе, старость видимо, проглядел)
но не отменяет остального)arusakov Автор
10.09.2023 01:42Что-то у вас вообще мощное)
У меня через brew без проблем встало.Krat0S
10.09.2023 01:42+1На мак через curl и через brew (после вашего уточнения :)) тоже без проблем встало.
А на линь забить пришлось, т.к. хотел чисто почекать скорость билда на слабых тачках, не вышло сходу, значит когда-нибудь позже)
На маке, кстати, разницы между npm run build и bun run build нет вообщеarusakov Автор
10.09.2023 01:42У меня разница небольшая, но все-таки есть)
Круто было бы с
jest
пересесть наbun test
, но сетап сложноват у нас, чтобы оно сразу завелось.
Elkost
10.09.2023 01:42Как бы бан не был хорош при первом знакомстве, там все ещё много проблем и использовать его рано. Во-первых на релизе нет поддержки http/2, что в 2023 году является базой для имплементации. Во-вторых нет возможности самому настроить бандлер, например на основе tsconfig файла, все билдится в ES5, из-за чего при ошибки компиляции можно словить баг с протеканием функциональных var'ов и потом дебажить это много-много времени. К тому же бан все ещё не реализовал полную поддержку node api, из-за чего часть модулей недоступна. Так же есть проблемы с некоторыми библиотеками, основное это gRPC и nest (из-за reflect-metadata). Бан хорош, но ждать его ещё год-два, может за это время нода решит двигаться дальше и бан останется как дено.
zartdinov
Интересно, это может повлиять на сам Node.js. Просто вспоминается история с форком io.js, благодаря которому все сдвинулось (ES6, V8 и тд.) и история с yarn, до появления которого вроде даже lock-файлов в npm не было.
Nurked
Так и повлияет. Кто то снова возьмёт и припишет к ноду что-то ещё, от чего у всех волосы под мышками дыбом встанут.
Не поймите меня неправильно, мне интересен этот бан. Я его щас попробую. Всё замечательно.
Но вообще-то - это всё извращения и издевательства. Все большой группой насилуют скриптовый язык, который должен был быть просто маленкой заплаткой для управления браузером, а его переделали в серверный язык.
Это так же как рассказы про замечательную типизированность TS, которой на самом деле не существует. (Мы только что в отдельной ветке спорили, что вы сколько угодно можете объявлять поле интерфейса номером, но ТС не заикаясь туда пихнёт строку.) Это попытка натянуть сову на глобус.
Наличие двух разных знаков проверки на равенство, и двух разных способов определения переменной де-факто создают язык, в котором неопределённое поведение и демоны из носа - это норма.
И тут вот вам. Это чудо. Ладно, пойду присоеденюсь к изнасилованию, посмотрим, запустит ли он мой проект, который отказывается компилироваться на любой штуке кроме node14. (Это ещё одна радость современного яваскрипта. С экосистемой непонятно, как можно сделать так, чтобы фронтэнд на Vue не компилировался)
Nurked
Опять же, даже в этой статье. В языке очередная проблема Common JS и ES модули. Всё в кривь и вкось. А в Bun просто взяли и влепили поддержку обоих вариантов. Так что ждём проектов, в которых в начале будет
Удобно, мы просто взяли проблему и превратили её в стандарт. И скоро у нас появится ещё одно поколение скриптеров, которые будут писать такое, без понимания о том, что происходит.
kuznetsovkd
Это всё надо запрещать линтерами и использовать только как хак.
Например что бы использовать fetch в commonjs проекте. Позволяя этому появляться только в зависимостях.
breninsul
у кого власть запретить это линтерами?)
Aetae
А какие проблемы, и сейчас так можно делать:
И погнали!:)
На самом деле у тебя и выхода иного нет если нужно использовать старую либу в новом коде, не заводя собственный форк "просто потому что".
DarthVictor
Справедливости ради знак нестрогого сравнения с чем-то кроме null в современном JS - это что-то уровня unsafe в Rust или использования malloc в С++.
DarthVictor
Приведите пример кода в котором TS клал строку в поле с числом без приведения типов. А с приведением типов я вам в любом языке положу.
Nurked
export interface Test { t: number }
let x = { t: "zhopa" } as Test
nin-jin
Nurked
Ну хорошо, не так, просто получите json через fetch и наслаждайтесь. При компиляции понятное дело упадёт. В рантайме проглотит как миленький.
TS это просто статический валидатор, усложняющий полученный код в яваскрипте
SWATOPLUS
ts-patch + ts-runtime-checks
НодЯЭс?
Nurked
Ну да, естественно. У нас типизированный язык. Для того, чтобы он был типизированным вам надо установить всего-то пару сотен пакетов, лишними не будут. А наш новый Бан их быстро загрузит.
Бред. Особенно на сервере. C#, Java, Golang, выбирайте. Нет, мы будем во всё пихать яваскрипт, потому что мы можем костылями к нему прикрутить хоть ассемблер.
nin-jin
Компайлтайм:
Рантайм:
Nurked
Ну, тоесть smol, а не тайпскрипт.
nin-jin
То есть парсер данных. Какой бы язык вы ни взяли, он вам понадобится для обработки ответа сервера.
DarthVictor
Number t = null;
Даже приводить ничего не нужно, лол.
koeshiro
Ответ от сервера с не соответствующим ожидаемым типам.
Или ответ от не типизированной функции (any).
Такой пример подойдет?
andreymal
Не совсем. Оба примера это по сути взаимодействие с внешним миром (нетипизированная функция это по сути тоже «внешний мир» по отношению к TS), а поскольку TS не способен гарантировать безопасность внешнего мира, то обеспечением этой самой безопасности заниматься должен уже программист (написать проверки типов и так далее). А во «внутреннем мире» в корректно аннотированном TS-коде без any вы такое провернуть уже не сможете.
Наверное, можно предъявить TS претензию, что он использует опасный any вместо чего-то наподобие ключевого слова unsafe как в других ЯП, но по крайней мере в typescript-eslint есть правило no-unsafe-assignment, запрещающее пихать any куда попало, так что в принципе оба примера можно отловить и больно надавать реализовавшему их программисту по рукам
arusakov Автор
А разве новые идеи и попытки что-то сделать иначе и лучше не двигает разработку вперёд? :)
arusakov Автор
Ну, и по чесноку, TypeScript - это, наверное, лучшее, что произошло с JavaScript в 2010ые.
Nurked
Но зачем?
Статический тайпчек был бы проще, и произвёл бы меньше мяса в коде, чем это псевдоподобие ООП для функционального языка.
arusakov Автор
Вас TypeScript вообще не обязывает писать в ООП. На старте это было так, сейчас же масса функционального кода отлично использует TS.
gravyzzap
А как вам наличие 4-х "пустых" значений:
— Поле отсутствует в объекте: obj.prop === undefined
— Поле есть, но оно undefined: obj.prop === undefined
— Поле есть, но оно null: obj.prop !== undefined
— Поле есть, и оно пустое (0, "").
Часть функций стандартной библиотеки возвращает null, другая - undefined.
mobileDeveloper
— Поле есть, и оно пустое (0, "")
Поле не пустое. Вы путаете truthy/falsy значения с действительно пустым полем.
— Поле отсутствует в объекте: obj.prop === undefined
— Поле есть, но оно undefined: obj.prop === undefined
Есть поле со значнием undefined или нет поля, на практике, в большинстве случаев не будет никакой разницы. Если нужно проверить наличие поля, для этого есть отдельная проверка.
— Поле есть, но оно null: obj.prop !== undefined
В этом случае, поле не только null, но и вообще может содержать любое значение, кроме undefined.
gravyzzap
Поле не пустое, пустое — значение.
В целом я в курсе как работает этот язык. Спасибо.
Из вашего комментария может показаться, что вам нравится это многообразие.
mobileDeveloper
Я всё же уточню, что значение не пустое. Ноль и строка нулевой длины считаются falsy в некоторых ситуациях но никак не пустыми.
Думаю, что многообразие с null/undefined всё же лишнее. Всё остальное работает примерно также в других языках.
Кроме того, нравится или нет, у нас нет особого выбора на клиенте. TS сильно помогает.
gravyzzap
Пустая строка – это пустое значение. Так же как 0 для интов, 0.0 для флоатов и false для булов. Аргументы про truthy/falsy тут ни при чём.
В других мейнстримных языках так не работает. Среди них нет языков с четырьмя вариантами "пустоты". В Go и вовсе он один.
mobileDeveloper
Простите. Я не понимаю. Я даже загуглил.
Чем ноль отличается скажем от пяти в JS? Как именно мы узнаем, что вот это пустое значение? Если мы не преобразовываем типы, то для JS ноль точно такое же число, как и пять.
В Go есть так называемые zero values - дефолтные значения для разных типов, когда переменная задекларирована без значения. В JS таким значением всегда будет undefined из-за динамической природы языка. Но это видимо не то, что вы имели ввиду.
gravyzzap
Не уверен, что получится без скатывания в философию.
Перед использованием, память обычно заполняется нулями. Ноль интерпретированный как строка – пустая строка, как бул - false, и т.д. Состояние памяти до того, как с ней начали работать – пустое. Такие же и значения, полученные из неё путём интерпретации с типами.
new Boolean() == false; new String() == ""; new Number() == 0
В JS это, конечно, не так явно, как в C или Go.
Часто нам важно, что бы значение не было пустым. Например, деление на ноль и поиск пустой подстроки в строке. Т.е. пустые значения не совсем такие же как остальные.
Часто пустые значения используются для обозначения отсутствия [корректных] данных. Но, в отличие от null/undefined, они не выходят за область значений типа, что используется, например, для оптимизации в v8.
mayorovp
А со скатыванием в философию интересно только философам.
Смотря какой памяти, локальные переменные до инициализации в куче языков вообще никак не "пустые", а заполнены мусором-UB, либо вовсе не могут использоваться до инициализации.
Конкретно в JS неинициализированная переменная содержит undefined.
Тут дело не в философской "пустоте", а конкретно в нуле. В математике делить на ноль нельзя, а вовсе не на "пустоту".
Что же до пустой подстроки — то в алгоритме КМП она вовсе не является каким-то особым случаем.
…да, используются. Только вот в качестве пустого значения совершенно не обязательно используется ноль! Я часто видел использование с подобной целью числа -1.
19Zb84
А через год большое количество модулей обновится, а разработчики bun упорно будут этого не видеть.
Я проекты вообще без бандеров использую для разработки.
Динамические импорты в бандлерах на сколько я видел, ещё нигде нормально не поддерживаются.
arusakov Автор
Мне кажется, тут зрелость самой node.js играет на руку. Поломки обратной совместимости во встроенных модулях - большая редкость.
arusakov Автор
Я тоже в этом плане скорее оптимист, какие-то хорошие идеи будут взяты на вооружение. Сейчас без lock-файлов вообще не понятно, как это должно работать, а раньше их отсутствие было данностью.
Evengard
Сама идея lock-файлов хорошо показывает, какой бардак творится в этой экосистеме, что нужна какая-то сущность, блокирующая нормальное обновление пакетов, потому что оказывается что без этого всё разваливается...
arusakov Автор
Lock-файлы позволяют контролировать установленные версии непрямых зависимости. И создатели пакетных менеджеров в других экосистемах отлично это знают и используют, например, в Python или Rust.
nin-jin
Как разработчик сотен библиотек, я вообще ничего не контролирую, ибо мои локфайлы всеми игнорируются.
arusakov Автор
Это нужно потребителю ваших библиотек, чтобы у всех разработчиков локально и при сборке проекта для прода все зависимости были идентичными. Чтобы всякие неведомые баги не всплывали.
nin-jin
Потребители моих библиотек - авторы других библиотек, так что их лок-файлы тоже игнорируются. А деплоится содержимое релизной ветки, которой нет ни у кого локально, и в которую попадает результат мёржа множества лок-файлов.
agilovr
локи для прикладных программ, а вам как разработчику библиотек просто нужно очень крепко подумать, прежде чем править зависимости, а поскольку думать обычно не принято (особенно у тех, кто пишет прикладной код) - придумали локи
nin-jin
А теперь главный твист этого сюжета: половина моих библиотек - прикладные программы.
breninsul
Мне кажется, решение JVM мира (maven packages) горааааздо лучше. На каждый проект у вас изолированные зависимости, в библиотеках тоже указаны версии, которые загрузится автоматически.
Приходилось прикасаться к чужому nodejs коду - это какой-то кошмар с зависимостями
LbISS
Лучше, но на сервере можно себе позволить загрузить две либы разных версий в память. А вот на фронте - это уже совсем другие расходы - сеть, объём кэша, cpu на парсинг - всё это сильно дороже. Оттуда и вылез этот ужасный формат семантической версионности с кучей проблем совместимости - из попыток не грузить одинаковые подзависимости.
hMartin
пока не пришли транзитивные зависимости