Использование esbuild в Deno

Модель совместимости npm в Deno

Современные версии Deno поддерживают нативную работу с npm-пакетами, что делает возможным использование esbuild без дополнительных транспиляционных слоёв и внешних сборочных инструментов.

Подключение esbuild в Deno опирается на механизм:

  • npm:-specifier resolution
  • кеширование зависимостей в Deno cache
  • изоляцию разрешений файловой системы

Такой подход позволяет использовать привычный Node.js-экосистемный пакет без потери преимуществ Deno: строгих разрешений и детерминированных зависимостей.


Установка и подключение esbuild в Deno

Базовое подключение выполняется напрямую через npm-импорт:

import * as esbuild from "npm:esbuild@0.25.0";

При первом запуске Deno загрузит пакет в локальный кэш. Дальнейшие вызовы выполняются без повторного скачивания.

Важный аспект — необходимость разрешений:

deno run --allow-read --allow-write --allow-net build.ts
  • --allow-net — загрузка зависимостей и возможных плагинов
  • --allow-read — доступ к исходным файлам
  • --allow-write — запись результатов сборки

Базовый процесс сборки

Стандартный сценарий использования esbuild в Deno идентичен Node.js-подходу, но с учётом специфик рантайма:

import * as esbuild from "npm:esbuild@0.25.0";

await esbuild.build({
  entryPoints: ["./src/main.ts"],
  bundle: true,
  platform: "browser",
  outfile: "./dist/bundle.js",
  format: "esm",
});

Ключевые параметры:

  • entryPoints — входные точки приложения
  • bundle — объединение зависимостей
  • platform — целевая платформа (browser, node, neutral)
  • outfile — путь итогового файла
  • format — формат модуля (ESM, CJS, IIFE)

Работа с TypeScript в Deno через esbuild

Deno изначально поддерживает TypeScript, однако esbuild используется для ускоренной трансформации и бандлинга.

Типовой сценарий:

import * as esbuild from "npm:esbuild@0.25.0";

await esbuild.build({
  entryPoints: ["src/app.ts"],
  bundle: true,
  outfile: "dist/app.js",
  target: ["es2022"],
  loader: {
    ".ts": "ts",
    ".tsx": "tsx",
  },
});

Особенности:

  • esbuild не выполняет полноценную типизацию
  • используется только синтаксическая трансформация
  • проверка типов остаётся задачей Deno (deno check)

Интеграция с Deno runtime API

В отличие от Node.js, Deno не использует process.env и require. Поэтому конфигурация esbuild адаптируется:

await esbuild.build({
  entryPoints: ["src/main.ts"],
  bundle: true,
  outfile: "dist/app.js",
  define: {
    "Deno.env": "undefined",
  },
});

Распространённые замены:

  • process.env.NODE_ENVDeno.env.get("ENV")
  • Node core modules → веб-совместимые API
  • fs API → Deno.readTextFile, Deno.writeTextFile

Watch-режим и инкрементальная сборка

esbuild поддерживает режим наблюдения за изменениями файлов:

import * as esbuild from "npm:esbuild@0.25.0";

const ctx = await esbuild.context({
  entryPoints: ["src/main.ts"],
  bundle: true,
  outfile: "dist/app.js",
});

await ctx.watch();

Особенности в Deno:

  • требуется --allow-read
  • watch работает через нативные файловые события ОС
  • контекст должен быть корректно завершён:
await ctx.dispose();

Использование plugins в Deno

Плагины esbuild работают в Deno при условии npm-совместимости.

Пример подключения плагина:

import * as esbuild from "npm:esbuild@0.25.0";
import alias from "npm:esbuild-plugin-alias";

await esbuild.build({
  entryPoints: ["src/main.ts"],
  bundle: true,
  outfile: "dist/app.js",
  plugins: [
    alias({
      entries: {
        "@": "./src",
      },
    }),
  ],
});

Ограничения:

  • плагины, завязанные на Node.js core modules, могут требовать адаптации
  • доступ к файловой системе зависит от Deno permissions
  • некоторые плагины ожидают fs из Node API

Разделение конфигурации сборки

Практика использования esbuild в Deno часто подразумевает выделение build-скрипта:

project/
  src/
  dist/
  build.ts
  deno.json

Пример build.ts:

import * as esbuild from "npm:esbuild@0.25.0";

const isProd = Deno.env.get("MODE") === "production";

await esbuild.build({
  entryPoints: ["src/main.ts"],
  bundle: true,
  minify: isProd,
  sourcemap: !isProd,
  outfile: "dist/app.js",
});

Интеграция с deno task

В deno.json можно описать задачи сборки:

{
  "tasks": {
    "build": "deno run --allow-read --allow-write --allow-net build.ts"
  }
}

Это позволяет стандартизировать процесс:

  • единая точка запуска
  • контроль разрешений
  • воспроизводимость сборки

Обработка ассетов и загрузчиков

esbuild поддерживает загрузчики (loaders) для различных типов файлов:

await esbuild.build({
  entryPoints: ["src/main.ts"],
  bundle: true,
  outfile: "dist/app.js",
  loader: {
    ".png": "file",
    ".svg": "text",
    ".css": "css",
  },
});

В Deno это особенно полезно при построении фронтенд-бандлов, так как:

  • можно интегрировать статические ресурсы
  • обеспечивается контроль над импортами
  • упрощается деплой

Производительность в Deno окружении

esbuild сохраняет свою ключевую характеристику — высокую скорость сборки за счёт:

  • реализации на Go
  • параллельной обработки модулей
  • отсутствия промежуточного AST-кэша уровня JS-интерпретатора

В связке с Deno наблюдаются следующие эффекты:

  • быстрый cold start после первого кеширования npm-зависимостей
  • минимальные накладные расходы runtime
  • отсутствие необходимости webpack-подобного dev server слоя

Ограничения интеграции

Использование esbuild в Deno имеет ряд особенностей:

  • отсутствие полного Node.js API-совместимого слоя
  • различия в разрешениях доступа к файлам
  • ограниченная поддержка некоторых legacy-плагинов
  • необходимость явного управления кешем npm-зависимостей

Типовой production pipeline

Структура сборки в Deno-проектах с esbuild:

  1. Проверка типов:

    deno check src/main.ts
  2. Сборка через esbuild:

    deno task build
  3. Оптимизация вывода:

    • minify
    • tree-shaking
    • code splitting (при включении)
  4. Деплой:

    • статический хостинг
    • edge runtime
    • контейнеризация

Код splitting и многомодульные приложения

esbuild поддерживает разделение кода:

await esbuild.build({
  entryPoints: ["src/main.ts"],
  bundle: true,
  splitting: true,
  format: "esm",
  outdir: "dist",
});

Это особенно эффективно при:

  • SPA приложениях
  • модульных frontend архитектурах
  • серверных edge-функциях

Использование в серверных приложениях Deno

В серверном сценарии esbuild часто применяется для подготовки артефактов:

await esbuild.build({
  entryPoints: ["server/app.ts"],
  bundle: true,
  platform: "node",
  outfile: "dist/server.js",
});

Хотя Deno не требует bundling для выполнения, esbuild используется для:

  • ускорения деплоя
  • уменьшения количества файлов
  • упрощения контейнеризации

Горячая перезагрузка и dev workflow

Комбинация watch-режима esbuild и перезапуска Deno процесса:

const ctx = await esbuild.context({
  entryPoints: ["src/main.ts"],
  bundle: true,
  outfile: "dist/app.js",
});

await ctx.watch();

Параллельно запускается:

deno run --allow-all --watch dist/app.js

Это создаёт двухуровневую систему:

  • esbuild отвечает за пересборку
  • Deno — за исполнение

Оптимизация конфигурации сборки

Ключевые техники:

  • отключение sourcemaps в production
  • использование external для CDN зависимостей
  • предкомпиляция vendor-библиотек
  • кеширование build context
external: ["react", "react-dom"]

Безопасность выполнения в Deno

Deno обеспечивает строгую модель разрешений, что влияет на работу esbuild:

  • сборка не имеет скрытого доступа к системе
  • каждый I/O вызов требует явного флага
  • сетевые запросы контролируются

Это делает pipeline предсказуемым и изолированным, особенно при использовании npm-версии esbuild.