Конфигурируем Babel

Конфигурируется Babel по средствам плагинов (plugin) и предустановок (preset). Предустановка - это набор плагинов.

Вы сами можете создать собственную предустановку и использовать её в своем проекте.

Обычно конфигурацию Babel выносят в отдельный файл .babelrc (также можно использовать .babelrc.js или указать конфигурацию в package.json).

Нужно понимать, что Babel просто преобразует код в AST (Abstract Syntax Tree), применяет плагины, а затем генерирует из AST новый код.

Трансформирование синтаксиса

Самый простой способ трансформирования синтаксиса — указать в предустановках нужную версию спецификации.

На момент написания статьи Babel предоставляет трансформации синтаксиса в спецификации ES2015 (babel-preset-es2015), ES2016 (babel-preset-es2016), ES2017 (babel-preset-es2015).

Добавляется в конфигурацию он следующим образом:

{
"presets": ["es2015"]
}

У такой предустановки есть явный недостаток. Допустим, на нашем проекте мы поддерживаем только две последние версии браузера Chrome. Тогда получается, что все трансформации нам не нужны, потому что часть нового синтаксиса уже поддерживается в двух последних версиях нашего браузера.

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

Например для Chrome 50 нужны только плагины:

{
"plugins": [
"transform-es2015-destructuring",
"transform-es2015-for-of",
"transform-es2015-function-name",
"transform-exponentiation-operator",
"transform-async-to-generator",
"syntax-trailing-function-commas"
]
}

При таком подходе мы получаем несколько зависимостей в package.json вместо одной. Это немного усложняет поиск и обновление зависимостей.

Представьте, что у нас есть определённый список окружений, которые нам нужно поддерживать, тогда нам придётся потратить уйму времени на тонкую настройку Babel. К счастью, разработчики Babel позаботились об этом и создали babel-preset-env. В этой предустановке устанавливаются плагины, необходимые для корректного исполнения синтаксиса в большинстве окружений.

Настоятельно рекомендую использовать эту предустановку в своих проектах. Она позволит вам уменьшить количество генерируемого кода и как следствие уменьшить время загрузки ваших скриптов.

По умолчанию конфигурация babel-preset-env выглядит следующим образом:

{
"presets": [
["env", {
"targets": {},
"useBuiltIns": false,
"loose": false,
"spec": false,
"uglify": false,
"debug": false,
"modules": "commonjs",
"include": [],
"exclude": []
}]
]
}

Обязательно задавайте targets и обязательно проверяйте с помощью debug с какими окружениями будет совместим ваш код.

Если вы используете babel-polyfill, в проекте устанавливайте useBuiltIns в true, тогда Babel будет оставлять из этой библиотеки только полифилы, подходящие под targets.

Устанавливайте loose в true если вы уверены в вашем коде, и если применяемые плагины содержат это свойство. При установке этого свойства, генерируемый код будет немного отклоняться от спецификации в пользу быстродействия.

Устанавливайте uglify в true если для минификации, кода вы используете UglifyJS.

Устанавливайте modules в false если ваш сборщик проектов поддерживает ES модули.

Обязательно устанавливайте modules в false если вы используете сборщик проектов поддерживающий Tree-Shaking. Если вы этого не сделаете то при запуске минификатора (UglifyJS, babili, etc) не будет происходить удаление мертвого кода!

Используйте include и exclude если вы хотите принудительно использовать или исключить какие либо плагины.

Больше информации про конфигурацию можно узнать на странице babel-preset-env.

Синтаксис который ещё не вошёл в спецификацию

Посредствам babel-preset-stage-x предустановок мы можем использовать синтаксис, который возможно в будущем будет добавлен в новую спецификацию.

Продвижением и утверждением спецификаций занимается комитет TC39. В этот комитет входят люди из таких компаний как Airbnb, Google, PayPal, Salesforce, Mozilla, Microsoft, Yahoo, etc.

Комитет представляет следующие стадии разработки спецификации JavaScript:

  • Strawman (babel-preset-stage-0) — только идея, черновой вариант, возможно Babel плагин.
  • Proposal (babel-preset-stage-1) — работа над начальной спецификацией (примеры использования, полифилы etc.).
  • Draft (babel-preset-stage-2) — начальная спецификация.
  • Candidate (babel-preset-stage-3) — полная спецификация и начальная поддержка браузерами.
  • Finished (babel-preset-stage-4) — спецификация будет добавлена в следующем релизе.
Подробнее о процессе разработки спецификации можно узнать в TC 39 Process, а также в статье Dr. Axel Rauschmayer: The TC39 process for ECMAScript features.

Я предпочитаю использовать stage-3, потому что большинство спецификаций на этой стадии попадает в релизную версию.

babel-polyfill и babel-runtime

Если мы захотим использовать например Array.prototype.includes (из спецификации ES2016) в нашем коде, то трансформировать синтаксис в ES2015 нам ничего не даст. Для такого преобразования нам необходимо будет подключить библиотеку babel-polyfill. Суть библиотеки очень проста, она предоставляет набор кроссбраузерных методов, которые расширяют только нативные методы и библиотеки (Math, Reflect, Array, Object, etc.).

После генерации кода в начало каждого модуля будут добавлять вспомогательные методы. Это сильно увеличивает наш код в размерах. Для решения этой проблемы необходимо подключить к проекту библиотеку babel-runtime которая содержит все вспомогательные методы, а также установить babel-plugin-transform-runtime для того чтобы все вспомогательные функции использовались из одной библиотеки.

Подробнее про конфигурацию babel-plugin-transform-runtime можно почитать в документации Babel.

babel-plugin-lodash

Если вы собираете свой проект сборщиком, который поддерживает ES модули и способен минифицировать бандл, вы конечно же захотите чтобы функции, которые не были использованы в ваших модулях, не попали в конечный бандл. Но что если во всех модулях lodash мы подключаем как показано ниже:

import _ from 'lodash';

Тогда сборщик запихнёт в конечный бандл всю библиотеку и не удалит из неё ненужные функции. В таком случае на помощь приходит babel-plugin-lodash, этот плагин заменит импорт всей библиотеки на импорт определённых модулей lodash т.е.

// импорт всего lodash
import _ from 'lodash';
_.map([1, 2, 3], x => x + x);
// будет заменён на импорт модуля lodash/map
import _map from 'lodash/map';
_map([1, 2, 3], x => x + x);

Выбор конфигурации в зависимости от переменной окружения env

Babel можно конфигурировать в зависимости от переменной окружения. Это оказывается очень удобным когда вы используете плагины зависящие от окружения, например babili или react-hot-loader.

Переменная окружения env выбирается следующим образом:

process.env.BABEL_ENV || process.env.NODE_ENV || "development"

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

{
"presets": ["es2015", "react"],
"plugins": ["transform-runtime"],
"env": {
"development": {
"plugins": ["react-hot-loader/babel"]
},
"production": {
"presets": ["babili"]
}
}
}

Заключение

Подводя итоги можно сделать следующие выводы:

  • Используем babel-polyfill если нам нужны кроссбраузерные нативные методы, которые есть не во всех браузерах или будут доступны с выходом следующей спецификации.
  • Используем babel-runtime для того, чтобы вспомогательные функции Babel доставались из одного модуля, а не включались в каждый.
  • Используем babel-plugin-lodash если в каждый модуль мы импортируем всю библиотеку lodash и не хотим лишнего кода при сборке проекта.
  • Используем babel-preset-env для того, чтобы применять только те плагины, которые необходимы для нашего проекта.
  • Используем stage-x для трансформирования нового синтаксиса.
  • Используем переменную окружения env для гибкого переключения конфигураций.
Like what you read? Give Pavel Bely a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.