Опция tsconfig и tsconfigRaw

В экосистеме esbuild конфигурация TypeScript играет вспомогательную роль и используется не как полноценный компиляторный контракт, а как источник сведений для трансформации и разрешения модулей. Опции tsconfig и tsconfigRaw управляют тем, каким образом esbuild получает и интерпретирует настройки TypeScript-проекта.


Роль tsconfig в esbuild

Опция tsconfig указывает путь к файлу конфигурации TypeScript, который обычно называется tsconfig.json. Этот файл содержит набор параметров, влияющих на поведение компилятора TypeScript: целевую версию ECMAScript, стратегию разрешения модулей, алиасы путей, JSX-настройки и другие опции.

В esbuild этот файл используется ограниченно. Основная цель — извлечение информации, необходимой для:

  • разрешения импортов и модульных путей;
  • обработки JSX-синтаксиса;
  • интерпретации алиасов paths и baseUrl;
  • определения совместимости с TypeScript-окружением проекта.

Важно учитывать, что esbuild не реализует полноценную семантику TypeScript. Он не выполняет типизацию и не интерпретирует сложные конструкции конфигурации так же глубоко, как tsc.


Формат опции tsconfig

Опция tsconfig в JavaScript API esbuild принимает строку, указывающую путь к файлу:

import * as esbuild from 'esbuild';

esbuild.build({
  entryPoints: ['src/index.ts'],
  bundle: true,
  outfile: 'dist/bundle.js',
  tsconfig: './tsconfig.json'
});

При использовании CLI поведение аналогично автоматическому поиску tsconfig.json, однако явное указание пути позволяет задать альтернативный конфигурационный файл:

esbuild src/index.ts --bundle --outfile=dist/bundle.js --tsconfig=./tsconfig.build.json

Алгоритм обработки tsconfig

При загрузке конфигурации esbuild выполняет следующие шаги:

  1. Чтение JSON-файла tsconfig.
  2. Извлечение секции compilerOptions.
  3. Обработка ограниченного набора полей, актуальных для трансформации и резолвинга.
  4. Игнорирование параметров, относящихся исключительно к компиляции TypeScript (noEmit, declaration, incremental и др.).

Поддерживаемые ключевые области:

  • baseUrl — базовый путь для относительного разрешения модулей;
  • paths — алиасы импортов;
  • jsx и jsxFactory — правила трансформации JSX;
  • target — влияет на уровень генерации JavaScript;
  • module — определяет модульную систему;
  • moduleResolution — стратегия поиска модулей.

Особенности работы с paths и baseUrl

Механизм paths в TypeScript позволяет создавать псевдонимы для путей импортов:

{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@app/*": ["src/app/*"]
    }
  }
}

В esbuild эти настройки используются для преобразования импортов на этапе бандлинга:

import { helper } from '@app/utils/helper';

Такая запись будет резолвиться в:

src/app/utils/helper

Однако поведение отличается от tsc в деталях:

  • отсутствует глубокая проверка типов;
  • игнорируются сложные шаблоны сопоставления;
  • не поддерживаются некоторые edge-case комбинации paths.

Ограничения tsconfig в esbuild

Несмотря на интеграцию, поддержка tsconfig остаётся частичной. Не учитываются:

  • strict-режим и типовые проверки;
  • noUnusedLocals, noUnusedParameters;
  • declaration и генерация .d.ts;
  • composite проекты;
  • project references;
  • incremental compilation.

Таким образом, tsconfig в esbuild выступает как конфигурация резолвинга и трансформации, а не как полноценный компиляционный контракт.


Опция tsconfigRaw

tsconfigRaw представляет собой альтернативный способ задания конфигурации TypeScript без использования внешнего файла. Вместо чтения tsconfig.json esbuild получает объект конфигурации напрямую.

Это позволяет:

  • динамически формировать конфигурацию;
  • избегать файловой системы;
  • переопределять параметры на лету;
  • использовать конфигурацию внутри инструментов сборки.

Формат tsconfigRaw

Опция передаётся как объект:

import * as esbuild from 'esbuild';

esbuild.build({
  entryPoints: ['src/index.ts'],
  bundle: true,
  outfile: 'dist/bundle.js',
  tsconfigRaw: {
    compilerOptions: {
      baseUrl: '.',
      paths: {
        '@lib/*': ['src/lib/*']
      },
      target: 'es2020',
      module: 'esnext',
      jsx: 'automatic'
    }
  }
});

В отличие от tsconfig, файл на диске не требуется, и конфигурация полностью инлайновая.


Приоритет tsconfigRaw над tsconfig

При одновременном использовании обеих опций поведение определяется приоритетом:

  • tsconfigRaw имеет более высокий приоритет;
  • файл, указанный в tsconfig, может использоваться как базовая конфигурация;
  • значения из tsconfigRaw перекрывают соответствующие поля.

Пример комбинированного подхода:

esbuild.build({
  entryPoints: ['src/index.ts'],
  bundle: true,
  outfile: 'dist/bundle.js',
  tsconfig: './tsconfig.json',
  tsconfigRaw: {
    compilerOptions: {
      target: 'es2022'
    }
  }
});

В данном случае базовая конфигурация берётся из файла, но target заменяется на es2022.


Сценарии применения tsconfigRaw

Использование tsconfigRaw оправдано в нескольких типах задач:

Динамическая сборка

При генерации конфигурации на основе окружения:

const isProd = process.env.NODE_ENV === 'production';

esbuild.build({
  entryPoints: ['src/index.ts'],
  bundle: true,
  outfile: 'dist/bundle.js',
  tsconfigRaw: {
    compilerOptions: {
      target: isProd ? 'es2022' : 'es2019'
    }
  }
});

Встраивание в инструменты сборки

При создании кастомных сборочных систем, где конфигурация не хранится в отдельных файлах.

Изоляция конфигурации

Когда необходимо исключить зависимость от внешнего tsconfig.json, например в контейнеризированных окружениях или CI-пайплайнах.


Различия tsconfig и tsconfigRaw

Сравнение подходов:

Характеристика tsconfig tsconfigRaw
Источник файл объект
Гибкость средняя высокая
Динамичность отсутствует поддерживается
Файловая зависимость требуется не требуется
Кэшируемость стабильная зависит от реализации

Поведение при разрешении модулей

И tsconfig, и tsconfigRaw влияют на процесс module resolution. Esbuild использует упрощённую модель:

  • сначала применяется baseUrl;
  • затем проверяются paths;
  • далее выполняется стандартный Node.js-like resolution;
  • расширения .ts, .tsx, .js подбираются автоматически.

При этом нестандартные сценарии TypeScript resolution могут работать иначе, чем в tsc.


JSX и tsconfig

Конфигурации jsx, jsxFactory и jsxFragmentFactory определяют способ преобразования JSX-кода.

Пример:

{
  "compilerOptions": {
    "jsx": "react",
    "jsxFactory": "h",
    "jsxFragmentFactory": "Fragment"
  }
}

В esbuild это приводит к трансформации:

const el = <div>Text</div>;

в вызовы:

const el = h("div", null, "Text");

Влияние на производительность сборки

Использование tsconfig или tsconfigRaw практически не влияет на скорость сборки, поскольку:

  • конфигурация читается один раз при инициализации;
  • дальнейшая работа происходит в памяти;
  • резолвинг кэшируется внутри процесса esbuild.

Однако динамическое использование tsconfigRaw может снижать эффективность кэширования между запусками, если объект конфигурации постоянно изменяется.


Частые ошибки конфигурации

При работе с tsconfig в esbuild часто возникают следующие проблемы:

  • указание неподдерживаемых опций TypeScript без эффекта на сборку;
  • ожидание строгой типизации, отсутствующей в esbuild;
  • конфликт paths с фактической структурой проекта;
  • несоответствие moduleResolution и поведения Node.js;
  • различие между поведением tsc и esbuild при резолвинге.

Особенности поведения при watch-режиме

В режиме наблюдения (watch) конфигурация tsconfig и tsconfigRaw считывается при старте процесса. Изменения в tsconfig.json не всегда приводят к автоматическому пересчёту конфигурации, что связано с оптимизацией сборочного процесса. Для применения изменений требуется перезапуск сборки.


Взаимодействие с плагинами esbuild

Плагины могут частично переопределять поведение, связанное с tsconfig:

  • перехватывать резолвинг путей;
  • модифицировать алиасы;
  • заменять правила обработки модулей.

При этом базовые настройки tsconfig остаются источником конфигурации, если плагин явно их не игнорирует или не заменяет.