Поле module: системы модулей и их параметры

Поле module в конфигурации SWC определяет, в какой модульный формат будут транслироваться исходные JavaScript/TypeScript файлы. Это один из ключевых механизмов трансформации кода, поскольку именно он управляет тем, как import и export будут преобразованы для конкретной среды выполнения или сборщика.

На этапе компиляции SWC анализирует исходный модульный синтаксис ECMAScript и преобразует его в целевой формат. Поведение трансформации напрямую зависит от выбранного значения:

  • формат выполнения в Node.js;
  • требования браузерной среды;
  • совместимость со старыми сборщиками;
  • интеграция с bundler-экосистемой.

Каждый модульный формат имеет собственные правила связывания зависимостей, области видимости и стратегию загрузки.

Основные значения module.type

ES Modules (ESM)

{
  "module": {
    "type": "es6"
  }
}

Значение es6 (или esnext в некоторых конфигурациях) сохраняет нативную ESM-модель без преобразования import/export в другие системы.

Ключевые особенности:

  • import и export остаются нетронутыми;
  • поддержка tree-shaking на уровне сборщика;
  • строгая статическая структура зависимостей;
  • оптимальная совместимость с современными bundler’ами (Vite, Rollup, esbuild).

Используется, когда целевая среда поддерживает ES Modules напрямую.


CommonJS

{
  "module": {
    "type": "commonjs"
  }
}

При выборе commonjs SWC преобразует ESM-синтаксис в вызовы require и module.exports.

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

import fs from "fs";
export const read = () => fs.readFileSync("file.txt");

После компиляции:

const fs = require("fs");

exports.read = () => fs.readFileSync("file.txt");

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

  • используется в Node.js (до ESM или в гибридных проектах);
  • динамическая модель загрузки модулей;
  • поддержка условных require;
  • хуже оптимизируется для tree-shaking.

AMD (Asynchronous Module Definition)

{
  "module": {
    "type": "amd"
  }
}

AMD ориентирован на браузерную асинхронную загрузку модулей через define.

Пример результата:

define(["require", "exports"], function (require, exports) {
  "use strict";
});

Характерные черты:

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

UMD (Universal Module Definition)

{
  "module": {
    "type": "umd"
  }
}

UMD представляет собой универсальный формат, поддерживающий разные окружения: AMD, CommonJS и глобальные переменные браузера.

Типичная структура результата:

(function (global, factory) {
  if (typeof module === "object" && typeof module.exports === "object") {
    module.exports = factory();
  } else if (typeof define === "function" && define.amd) {
    define([], factory);
  } else {
    global.myLibrary = factory();
  }
})(this, function () {
  return {};
});

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

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

SystemJS

{
  "module": {
    "type": "systemjs"
  }
}

SystemJS применяется для динамической загрузки модулей через системный загрузчик.

Характеристики:

  • поддержка динамических import-механизмов;
  • возможность работы в рантайме через loader;
  • используется в специфических архитектурах;
  • менее распространён в современных фронтенд-сборках.

Поведение interop и связность модулей

SWC предоставляет дополнительные параметры, влияющие на взаимодействие между системами модулей.

noInterop

{
  "module": {
    "type": "commonjs",
    "noInterop": true
  }
}

При включении noInterop отключается автоматическая генерация обёрток для default import из CommonJS-модулей.

Поведение:

  • ускорение сборки;
  • уменьшение runtime-обёрток;
  • потенциальные проблемы совместимости с пакетами, ожидающими interop.

lazy

{
  "module": {
    "type": "commonjs",
    "lazy": true
  }
}

Параметр lazy влияет на стратегию загрузки экспортов.

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

  • экспортные свойства вычисляются при обращении;
  • улучшение стартовой производительности;
  • полезно для больших модулей с редким доступом к части API.

strict

{
  "module": {
    "type": "commonjs",
    "strict": true
  }
}

strict усиливает соответствие строгим правилам преобразования CommonJS:

  • предотвращает неоднозначные интероп-сценарии;
  • улучшает предсказуемость экспорта;
  • снижает риск некорректных импортов между ESM и CJS.

Сопоставление модульных систем

Статические и динамические модели

ESM:

  • статический граф зависимостей;
  • оптимизация на этапе сборки;
  • поддержка tree-shaking.

CommonJS:

  • динамический runtime-graph;
  • возможность условных импортов;
  • меньшая предсказуемость анализа.

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

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


Совместимость с окружениями

  • Node.js современный: ESM и CJS (в зависимости от “type”: “module” в package.json);
  • браузеры: ESM;
  • legacy-приложения: AMD/UMD;
  • универсальные библиотеки: UMD.

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

Браузерное приложение

{
  "module": {
    "type": "es6"
  }
}

Цель — сохранить нативные импорты для последующей обработки bundler’ом.


Node.js приложение (legacy CommonJS)

{
  "module": {
    "type": "commonjs"
  }
}

Подходит для проектов без ESM-миграции.


Библиотека для публикации

{
  "module": {
    "type": "umd"
  }
}

Используется при необходимости максимальной совместимости.


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

{
  "module": {
    "type": "commonjs",
    "lazy": true,
    "noInterop": true
  }
}

Такой набор снижает накладные расходы runtime-обёрток и оптимизирует загрузку.


Влияние module на транспиляцию import/export

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

  • importrequire (для CommonJS);
  • export defaultmodule.exports;
  • именованные экспорты → свойства объекта экспорта;
  • динамические import() остаются или преобразуются в Promise-обёртки в зависимости от цели.

Стратегия трансформации определяется исключительно значением module.type, что делает его центральным параметром всей системы сборки.


Особенности взаимодействия с TypeScript

При использовании SWC вместо tsc:

  • типы удаляются полностью;
  • модульная трансформация выполняется независимо от TypeScript-конфигурации;
  • поведение esModuleInterop частично эмулируется через SWC interop-логику.

Это приводит к тому, что финальная модульная система определяется не TypeScript, а именно SWC-конфигурацией.


Ограничения и тонкости

  • не все комбинации interop-параметров одинаково стабильны в разных окружениях;
  • UMD и AMD увеличивают размер итогового кода;
  • lazy-модули могут усложнять отладку из-за отложенного вычисления экспортов;
  • смешивание ESM и CommonJS требует аккуратного контроля interop-режимов.

Архитектурная роль поля module в SWC

Поле module фактически задаёт стратегию связывания зависимостей:

  • определяет структуру графа модулей;
  • влияет на формат выходного кода;
  • задаёт поведение runtime-интеропа;
  • формирует совместимость с экосистемой Node.js и браузеров;
  • управляет возможностями оптимизации на стороне bundler’а.

Через него SWC перестаёт быть просто транспилятором синтаксиса и становится инструментом управления модульной архитектурой приложения.