Настройка importSource

Параметр importSource в SWC относится к настройке трансформации JSX и определяет, из какого модуля будет импортироваться JSX runtime при использовании автоматического режима JSX. Он напрямую влияет на то, как компилятор переписывает JSX-выражения в JavaScript-код и какие функции будут использованы для создания элементов.

В современном JSX-трансформе (React 17+ и аналогичных реализациях) используется так называемый automatic runtime, при котором нет необходимости явно импортировать React в каждом файле. Вместо этого SWC генерирует импорты функций вроде jsx, jsxs или jsxDEV из заданного runtime-модуля. Именно выбор этого модуля и контролируется через importSource.


Базовая модель трансформации JSX

JSX до компиляции:

const App = () => <div>Hello</div>;

После трансформации с runtime react:

import { jsx as _jsx } from "react/jsx-runtime";

const App = () => _jsx("div", { children: "Hello" });

Если указан другой importSource, например preact, результат будет отличаться:

import { jsx as _jsx } from "preact/jsx-runtime";

const App = () => _jsx("div", { children: "Hello" });

Таким образом, importSource определяет базовый источник JSX-функций.


Настройка importSource в SWC

В SWC параметр задаётся внутри секции jsc.transform.react.

Пример конфигурации .swcrc:

{
  "jsc": {
    "parser": {
      "syntax": "typescript",
      "tsx": true
    },
    "transform": {
      "react": {
        "runtime": "automatic",
        "importSource": "react"
      }
    }
  }
}

Здесь:

  • runtime: “automatic” включает новый JSX transform
  • importSource определяет пакет, из которого берутся JSX-функции

Если значение не указано, используется стандартное поведение, эквивалентное “react”.


Связь importSource и JSX runtime

JSX runtime представляет собой набор функций, отвечающих за создание элементов. В зависимости от среды они могут различаться:

  • React: react/jsx-runtime
  • Preact: preact/jsx-runtime
  • Emotion: кастомный runtime для CSS-in-JS
  • Другие совместимые библиотеки

SWC формирует импорт автоматически:

import { jsx } from `${importSource}/jsx-runtime`;

и аналогично для jsxDEV в dev-режиме.


Режим automatic и его влияние

importSource имеет смысл только при включённом:

"runtime": "automatic"

При классическом runtime:

"runtime": "classic"

JSX трансформируется в вызовы React.createElement, и importSource полностью игнорируется.

Пример classic:

import React from "react";

const App = () => React.createElement("div", null, "Hello");

Использование с альтернативными JSX реализациями

Preact

Preact использует собственный runtime:

{
  "jsc": {
    "transform": {
      "react": {
        "runtime": "automatic",
        "importSource": "preact"
      }
    }
  }
}

Результат трансформации:

import { jsx as _jsx } from "preact/jsx-runtime";

Особенность заключается в том, что Preact предоставляет API, совместимый с React JSX, но с меньшим размером и иной реализацией виртуального DOM.


Emotion

CSS-in-JS библиотеки используют importSource для перехвата JSX.

Пример:

{
  "jsc": {
    "transform": {
      "react": {
        "runtime": "automatic",
        "importSource": "@emotion/react"
      }
    }
  }
}

Тогда JSX компилируется в вызовы Emotion runtime:

import { jsx } from "@emotion/react/jsx-runtime";

Это позволяет внедрять обработку CSS-пропсов на уровне JSX без Babel-плагинов.


Отличие importSource от jsxImportSource в TypeScript

В TypeScript существует аналогичная настройка:

{
  "compilerOptions": {
    "jsx": "react-jsx",
    "jsxImportSource": "preact"
  }
}

Различие:

  • jsxImportSource — TypeScript уровень
  • importSource — SWC уровень

При использовании SWC TypeScript настройка может игнорироваться, если трансформация JSX полностью делегирована SWC.


Dev-режим и выбор функций JSX

SWC автоматически переключает используемые функции в зависимости от окружения:

  • development: jsxDEV
  • production: jsx
  • static оптимизация: jsxs

Пример dev:

import { jsxDEV as _jsxDEV } from "react/jsx-dev-runtime";

const App = () =>
  _jsxDEV("div", { children: "Hello" }, undefined, false, undefined, this);

importSource влияет и на dev-runtime:

import { jsxDEV } from "preact/jsx-dev-runtime";

Влияние на tree-shaking и размер бандла

Выбор importSource может существенно влиять на итоговый размер сборки:

  • корректный runtime позволяет использовать ESM-экспорт функций
  • уменьшает необходимость в полном React import
  • позволяет заменять React на более лёгкие реализации

Особенно это заметно при использовании Preact или специализированных runtime-библиотек.


Совместимость с React 17+ и 18+

React начиная с 17 версии поддерживает automatic runtime:

import { jsx } from "react/jsx-runtime";

SWC полностью повторяет эту модель.

Для React 18+ дополнительная настройка не требуется, но importSource остаётся полезным для:

  • монорепозиториев с несколькими JSX runtime
  • библиотек UI, независимых от React
  • кастомных render-движков

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

Стандартный React проект

{
  "jsc": {
    "transform": {
      "react": {
        "runtime": "automatic"
      }
    }
  }
}

React с явным указанием

{
  "jsc": {
    "transform": {
      "react": {
        "runtime": "automatic",
        "importSource": "react"
      }
    }
  }
}

Preact замена React

{
  "jsc": {
    "transform": {
      "react": {
        "runtime": "automatic",
        "importSource": "preact"
      }
    }
  }
}

Особенности поведения при SSR

На серверной стороне JSX runtime может отличаться:

  • используются серверные версии runtime (react/jsx-runtime vs react/jsx-dev-runtime)
  • importSource остаётся одинаковым
  • различие только в целевом entry point (jsx-runtime vs jsx-dev-runtime)

Ограничения и нюансы

  • importSource не влияет на runtime поведение, только на импорт
  • несовместимые библиотеки могут требовать патчей
  • некоторые UI-фреймворки требуют строго определённого runtime
  • неправильное значение приводит к ошибкам импорта во время сборки

Пример ошибки:

Cannot find module &

Механика генерации импортов внутри SWC

SWC внутренне строит AST и заменяет JSX следующим образом:

  1. анализирует наличие JSX
  2. проверяет runtime: automatic
  3. берёт значение importSource
  4. формирует путь ${importSource}/jsx-runtime</code></li> <li>генерирует named import функций <code>jsx</code>, <code>jsxs</code>, <code>Fragment</code></li> </ol> <p>Псевдологика:</p> <pre class="text"><code>if (runtime === &quot;automatic&quot;) { source = `${importSource}/jsx-runtime` }

Взаимодействие с Fragment

Fragment также импортируется из того же источника:

import { Fragment } from "react/jsx-runtime";

или при кастомном source:

import { Fragment } from "preact/jsx-runtime";

Это важно для корректной работы JSX без лишних DOM-узлов.


Практика использования в монорепозиториях

В монорепозиториях часто требуется поддержка нескольких JSX runtime:

  • web-приложение (React)
  • лёгкие виджеты (Preact)
  • дизайн-система (Emotion runtime)

В таких случаях importSource становится ключевым механизмом изоляции трансформации, позволяя каждому пакету компилироваться под свой runtime без конфликтов.


Поведение при отсутствии importSource

Если параметр не указан:

  • SWC использует “react” как значение по умолчанию
  • генерируется импорт из react/jsx-runtime
  • поведение совпадает с типичной React конфигурацией

Это обеспечивает совместимость «из коробки» для большинства проектов без дополнительных настроек