Настройка Babel: встроенная трансформация

Babel — это транспилятор JavaScript, предназначенный для преобразования современного синтаксиса ECMAScript в код, совместимый со старыми браузерами и средами выполнения. В большинстве сборщиков настройка Babel требует отдельной конфигурации, установки загрузчиков и интеграции в процесс сборки. Parcel реализует иной подход: Babel интегрирован в систему сборки и может работать практически без дополнительной настройки.

Основная идея заключается в автоматическом определении необходимости трансформации кода на основании целевых платформ проекта. Если используются современные возможности языка, Parcel способен самостоятельно подключить Babel и выполнить преобразование исходного кода.


Встроенная поддержка Babel

Одним из преимуществ Parcel является концепция zero-configuration. После установки Parcel поддержка Babel уже присутствует внутри экосистемы сборщика.

Простейшая структура проекта может выглядеть следующим образом:

project/
├── src/
│   ├── index.js
│   └── app.js
├── package.json
└── .parcelrc

Файл JavaScript может использовать современный синтаксис:

const getUser = async () => {
    const response = await fetch('/api/user');
    return response.json();
};

getUser().then(user => console.log(user));

Во время сборки Parcel анализирует окружение и при необходимости преобразует конструкции:

  • Arrow Functions;
  • Async/Await;
  • Optional Chaining;
  • Nullish Coalescing;
  • Class Fields;
  • Private Fields;
  • другие возможности современных стандартов ECMAScript.

Автоматическое определение целей сборки

Трансформация кода зависит от списка поддерживаемых браузеров. Parcel получает эту информацию из поля browserslist.

Пример:

{
  "browserslist": [
    "> 0.5%",
    "last 2 versions",
    "not dead"
  ]
}

Либо:

{
  "targets": {
    "default": {
      "engines": {
        "browsers": [
          "> 0.5%",
          "last 2 versions"
        ]
      }
    }
  }
}

На основе указанных целей Parcel автоматически определяет:

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

Чем современнее список целевых браузеров, тем меньше преобразований будет выполнять Babel.


Автоматическая трансформация современного синтаксиса

Стрелочные функции

Исходный код:

const sum = (a, b) => a + b;

После транспиляции для старых браузеров:

var sum = function(a, b) {
    return a + b;
};

Классы

Исходный код:

class User {
    constructor(name) {
        this.name = name;
    }

    sayHello() {
        console.log(this.name);
    }
}

После преобразования Babel генерирует более объемный ES5-код с использованием функций-конструкторов и вспомогательных методов.


Optional Chaining

Современный синтаксис:

const city = user?.address?.city;

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

var city =
    user == null
        ? void 0
        : user.address == null
        ? void 0
        : user.address.city;

Nullish Coalescing

Исходный код:

const count = value ?? 0;

После обработки:

var count = value !== null && value !== undefined
    ? value
    : 0;

Использование собственной конфигурации Babel

Несмотря на автоматическую работу, Parcel позволяет использовать полноценную конфигурацию Babel.

Для этого создается файл:

.babelrc

или

babel.config.json

Пример:

{
  "presets": [
    "@babel/preset-env"
  ]
}

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


Установка дополнительных пакетов Babel

Если проект использует собственную конфигурацию, обычно требуется установить необходимые зависимости:

npm install --save-dev @babel/core
npm install --save-dev @babel/preset-env

Либо одной командой:

npm install --save-dev @babel/core @babel/preset-env

Конфигурация:

{
  "presets": [
    "@babel/preset-env"
  ]
}

Теперь управление трансформациями осуществляется через стандартные механизмы Babel.


Presets в Babel

@babel/preset-env

Наиболее часто используемый пресет.

Пример:

{
  "presets": [
    "@babel/preset-env"
  ]
}

Он автоматически определяет необходимые преобразования в зависимости от списка поддерживаемых браузеров.


Настройка targets

Можно явно указать целевые платформы:

{
  "presets": [
    [
      "@babel/preset-env",
      {
        "targets": {
          "chrome": "90",
          "firefox": "88"
        }
      }
    ]
  ]
}

В таком случае Babel будет учитывать именно эти версии браузеров.


Использование плагинов Babel

Babel поддерживает огромную экосистему плагинов.

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

{
  "plugins": [
    "@babel/plugin-transform-runtime"
  ]
}

Установка:

npm install --save-dev @babel/plugin-transform-runtime
npm install --save @babel/runtime

Плагин уменьшает дублирование вспомогательного кода, генерируемого Babel.


Работа с экспериментальными возможностями JavaScript

Некоторые возможности языка находятся на стадии разработки и не входят в стабильный стандарт ECMAScript.

Для их поддержки используются отдельные плагины.

Пример для декораторов:

npm install --save-dev @babel/plugin-proposal-decorators

Конфигурация:

{
  "plugins": [
    [
      "@babel/plugin-proposal-decorators",
      {
        "version": "2023-11"
      }
    ]
  ]
}

После этого становится доступен экспериментальный синтаксис:

@sealed
class User {

}

Babel и TypeScript

Parcel умеет работать с TypeScript без отдельной настройки Babel.

Пример файла:

interface User {
    name: string;
}

const user: User = {
    name: 'Alex'
};

Parcel автоматически удаляет типы во время сборки.

Однако при необходимости использования специфических возможностей Babel можно добавить соответствующие пресеты:

npm install --save-dev @babel/preset-typescript

Конфигурация:

{
  "presets": [
    "@babel/preset-typescript"
  ]
}

Babel и React

Для React-проектов Babel часто применяется для преобразования JSX.

Компонент:

function App() {
    return <h1>Hello Parcel</h1>;
}

Установка:

npm install --save-dev @babel/preset-react

Конфигурация:

{
  "presets": [
    "@babel/preset-react"
  ]
}

После транспиляции JSX преобразуется в вызовы функций React.


Автоматическая обработка JSX в Parcel

Современные версии Parcel умеют определять React-проекты автоматически.

Файл:

import React from 'react';

export default function App() {
    return <h1>Application</h1>;
}

При наличии соответствующих зависимостей Parcel подключает необходимые трансформации без ручной настройки Babel.


Полифилы и Babel

Транспиляция и полифилы — разные задачи.

Транспиляция изменяет синтаксис:

const fn = () => {};

var fn = function() {};

Полифилы добавляют отсутствующие возможности среды выполнения.

Например:

Promise.allSettled([
    promise1,
    promise2
]);

Если браузер не поддерживает Promise.allSettled, одного преобразования синтаксиса недостаточно.


Использование core-js

Для автоматического подключения полифилов часто применяется библиотека core-js.

Установка:

npm install core-js

Настройка:

{
  "presets": [
    [
      "@babel/preset-env",
      {
        "useBuiltIns": "usage",
        "corejs": 3
      }
    ]
  ]
}

В режиме usage Babel анализирует исходный код и подключает только необходимые полифилы.


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

Parcel реализует несколько механизмов оптимизации:

Кэширование

Результаты транспиляции сохраняются в кэш.

Повторная сборка использует уже обработанные файлы, что существенно ускоряет работу.


Инкрементальная сборка

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

Это особенно важно для крупных приложений.


Параллельная обработка

Трансформация нескольких файлов может выполняться одновременно.

За счет этого значительно сокращается время полной сборки.


Когда собственная настройка Babel не требуется

Во многих проектах достаточно стандартных возможностей Parcel:

  • используется современный JavaScript;
  • отсутствуют экспериментальные возможности языка;
  • не нужны нестандартные плагины;
  • требуется поддержка обычного набора браузеров;
  • используется стандартный React или TypeScript.

В подобных случаях встроенная интеграция Babel обеспечивает полноценную транспиляцию без создания конфигурационных файлов.


Когда необходима ручная конфигурация

Создание собственной конфигурации Babel оправдано в следующих ситуациях:

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

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

Схема обработки JavaScript в Parcel обычно выглядит следующим образом:

Исходный код
      │
      ▼
 Анализ целей сборки
      │
      ▼
   Babel
      │
      ▼
 Трансформированный код
      │
      ▼
 Оптимизация Parcel
      │
      ▼
 Финальный bundle

Parcel берет на себя определение необходимости трансформации, настройку пайплайна сборки, оптимизацию выходных файлов и интеграцию Babel в общий процесс компиляции, благодаря чему современный JavaScript может использоваться практически без ручной настройки инфраструктуры сборки.