Три картины, которые показывают рост героя от малыша (версия 1.0) до взрослого человека (версия 3.0)
Иллюстрация: Кира Кустова

Версии языка, транспайлеры, бандлеры

Почему нельзя написать язык один раз или зачем в JavaScript столько инструментов вокруг языка.

Время чтения: 11 мин

Кратко

Скопировано

JavaScript, как и другие живые языки программирования, развивается. Создатели и разработчики языков улучшают их, устраняют неправильное или странное поведение и выпускают свежие версии.

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

Это значит, что разработчикам приходится не только учитывать текущую версию языка, но и некоторые версии до неё; понимать, в каком диапазоне окружений наше приложение может быть запущено; как «готовить» код приложения к релизу.

Как понять

Скопировано

Давайте начнём с разницы между JavaScript и ECMAScript.

Что ещё за ECMAScript?

Скопировано

Разница между ними в том, что документация ES говорит, как создать язык, который будет соответствовать «семейству» подобных ECMAScript-языков. А документация JS — как использовать конкретно этот язык (JS).

А в чём смысл?

Скопировано

Дело в том, JS — не единственный язык, который следует этой спецификации. Есть ещё ActionScript, TypeScript, когда-то был CoffeeScript.

Чтобы не описывать каждый язык в деталях отдельно, есть спецификация. Она описывает то, что у этих языков одинаково.

Так как JS следует спецификации ES, новые фичи описываются именно в ней. Это нам нужно, чтобы понимать, как следить за развитием языка и обновлениями.

Обновления и версии

Скопировано

До 2015 года ES обновлялся всего несколько раз:

Версии Год Изменения
1 1997 Первая редакция
2 1998 Редакционные правки
3 1999 Добавили регулярные выражения и try-catch
4 Так и не вышел
5 2009 Добавили 'use strict', поддержку JSON, некоторые другие фичи

Как видно из таблицы, он не особо бурно развивался.

При этом же уже в 2010 году становилось очевидно, что приложения, которые используют языки по спецификации ES, будут становиться сложнее и больше. А JS в том виде, что был, не до конца удовлетворял разработчиков.

С 2015 года спецификация ES обновляется каждый год. То есть каждый год в ней появляются улучшения, доработки и новые фичи, которые потом приходят в JS и используются в браузерах.

Экскурс в историю 😃

ECMAScript 3

Скопировано

В третьей редакции изменений было не очень много:

  • добавили регулярные выражения;
  • добавили try/catch;
  • улучшили работу со строками и форматированием;
  • добавили in и instanceof.

Но несмотря на это ES3 стал очень популярным и распространённым. (Даже сегодня некоторые инструменты всё ещё позволяют компилировать код в ES3.) Он стал основной для многих библиотек, в его время зарождался AJAX.

Браузеры быстро научились с ним работать. Казалось, что развитие бурное и успешное. Многие ждали выхода ES4, но что-то пошло не так.

ECMAScript 4

Скопировано

Когда началась работа над ES4, у разработчиков возникли разногласия в видении языка. Кто-то считал, что пора сделать JavaScript языком для крупной разработки и добавить туда типы, классы, интерфейсы, генераторы, итераторы и кучу других штук из «большого» программирования.

Другая часть разработчиков была против таких изменений. И в 2003 году разработку ES4 остановили, в 2008 приняли решение, что 4-я версия так и не выйдет.

Забавный факт: некоторые фичи типа итераторов, генераторов и классов нашли второе рождение в ES2015+.

Чуть подробнее о том, как и почему именно произошёл раскол в видении, как дело развивалось дальше, можно узнать в докладе Дугласа Крокфорда «The State and Future of JavaScript».

После того, как разработчики приняли решение оставить ES4, они сфокусировались на ES3.1, который впоследствии станет ES5.

ECMAScript 5

Скопировано

С 2009 по 2015 спецификация ES5 была самой свежей. Её главной особенностью помимо новых фич был строгий режим.

Строгий режим

Скопировано

Строгий режим 'use strict' появился, потому что в ES поломалась обратная совместимость.

В ES5 пересмотрели некоторые неочевидные особенности языка и исправили их. Но так как эти исправления меняли работу уже существующего кода, просто так поднять версию и выпустить свежие правки было нельзя — существующий код мог бы сломаться.

Чтобы определять, по каким правилам браузеру интерпретировать код (старым ES3 или новым ES5), и ввели строгий режим.

Сейчас хорошим тоном считается использовать строгий режим по умолчанию.

Фичи

Скопировано

Вместе со строгим режимом в ES5 добавили:

  • геттеры и сеттеры для объектов;
  • полезные методы для мета программирования типа Object.defineProperty(), Object.keys() и других;
  • методы для работы с массивами типа filter(), map(), reduce() и других;
  • поддержку JSON;
  • и другое.

ECMAScript 2015

Скопировано

ES5 принёс много хорошего и сделал проще работу с AJAX благодаря JSON, но он не был идеальным. У разработчиков было много претензий к нему.

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

Или то, что не было классов. (Причём, забавно, что ключевое слово class было зарезервировано, то есть использовать его в коде было нельзя ¯\_(ツ)_/¯)

Или то, что объявление функций «поднималось» в начало области видимости.

Или поднятие переменных, когда они создавались не там, где были объявлены, а в начале модуля.

Фичи

Скопировано

ES2015 стал революцией. Во-первых, потому что это было первое обновление за последние 6 лет. А во-вторых, потому что в нём добавили:

Что поменялось

Скопировано

Кроме того, что в новой версии добавили кучу фич, с 2015 года спецификация обновляется ежегодно.

Отчасти поэтому название теперь не содержит «номер версии», а состоит из номера года — ES2015, ES2016, ES2018 и т. д.

Ежегодные обновления решают несколько проблем:

  • Они не допускают «застоя» и монополии технологий. Ситуация, когда язык не развивается грозит его деградацией, а возможно и вымиранием — появится конкурент удобнее, приятнее. (Маловероятно, что JS бы умер, но тем не менее.)
  • Создают более вовлечённое и отзывчивое сообщество. Когда есть возможность повлиять на развитие языка, которым разработчики пользуются каждый день, им интереснее участвовать в обсуждениях и помогать его развивать.
  • Заставляют браузеры обновляться, чтобы те соответствовали последним введениям. Ситуация, когда на рынке один браузер, под который всё разрабатывается, очень опасная. Вспомнить хотя бы IE5–6, от влияния на интернет которых мы отходили несколько лет.
  • Позволяют перенимать лучшие практики из других языков. Хотя разработчики стараются не превращать JS в другие языки, тем не менее удачные выразительные решения приживаются.
  • Делают пачки изменений меньше. От этого изучать изменения и привыкать к ним разработчикам становится проще.

ECMAScript 2016+

Скопировано

Все последующие версии спецификации выходят каждый год. Количество изменений в каждом релизе меньше, чем в ES2015, но они всё ещё достаточно полезные. Вот некоторые из них:

ES2016

Скопировано
  • Деструктурирование массивов;
  • возведение в степень через оператор **;
  • includes() для массивов.

ES2017

Скопировано

ES2018

Скопировано
  • finally() для промисов;
  • обновления в регулярных выражениях;
  • спред оператор для объектов.

ES2019

Скопировано
  • flat(), flatMap() для массивов;
  • fromEntries() для объектов.

ES2020

Скопировано
  • BigInt тип;
  • globalThis для удобного доступа к глобальному объекту;
  • ?? оператор для nullish coalescing.

Версии и браузеры

Скопировано

— Окей-окей, а какая версия точно в браузере работает-то? — Зависит от браузера ¯\_(ツ)_/¯

Считается, что точно-точно работает ES5 — тот самый, где добавили 'use strict'. С другими версиями сложнее: какие-то браузеры уже научились работать с фичами из поздних спецификаций, какие-то нет, да и набор поддерживаемых фич может отличаться от браузера к браузеру.

Пользоваться, однако, ES5 уже никому не хочется: эта версия менее удобна, чем современные.

Возникает проблема: хочется использовать новый синтаксис, но при этом хочется, чтобы приложение работало не только в самых современных браузерах, но также и в старых.

Решить эту проблему должна транспиляция.

Транспиляция

Скопировано

Транспиляция — это процесс «перевода» кода с одного языка на другой. Программы, которые занимаются транспиляцией называются транспайлерами.

Итак, у нас есть проблема: мы хотим писать на ES2015+, но браузеры понимают ES5. Звучит, как задача для транспайлеров из ES2015 в ES5. Но есть ли вообще программы, которые переводят программу из одного языка в тот же язык?

Да, есть. И более того они сами могут быть написаны на том же языке 😃

Babel

Скопировано

Один из таких транспайлеров, Babel, как раз сам написан на JS.

Он позволяет не только переводить код с ES2015 на ES5, но и, например, переводить код с TypeScript на ES5. Ещё он предлагает песочницу, в которой можно сразу посмотреть на результат перевода.

У Babel плагинная архитектура, это значит, что в самом Babel — только основная функциональность «переводчика», а конкретные правила того, что надо переводить и как, описываются в плагинах к нему.

Другие

Скопировано

Кроме Babel есть и другие: Traceur или ratel-core, написанный на Rust. Но Babel сейчас один из самых популярных транспайлеров JS.

Инструменты сборки и автоматизации

Скопировано

Использовать транспайлеры сами по себе не всегда удобно. Они справляются с тем, чтобы перевести язык, но иногда нам хочется провести какие-то дополнительные операции с кодом, чтобы подготовить его к релизу.

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

Сборка проекта — превращение исходников в конечный продукт.

Среди таких инструментов сейчас наиболее распространены Gulp и Webpack.

Gulp

Скопировано

Gulp позволяет полностью «руками» контролировать процесс превращения исходников в конечный результат.

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

Webpack

Скопировано

Webpack, в отличие от Gulp, — это бандлер. Разница между менеджером задач и бандлером в их подходе к задачам.

Менеджеры задач — это инструменты автоматизации, которые позволяют «поставить на поток» какие-то задачи типа минификации кода.

Бандлеры — это комбайны помощнее, заточенные под разработку и сборку приложений. У бандлеров шире функциональность, но и настраивать их сложнее.

Например, Webpack не только умеет сам минифицировать код, но ещё и может заменять модули «на лету» при разработке, удалять неиспользуемые функции, находить повторяющиеся зависимости, разбивать код на несколько файлов в зависимости оттого, как он будет использоваться, и другое.

У него выше порог вхождения и сложнее конфигурация. (А ещё там может много ненужного, если у вас какая-то простая рутинная задача, которую надо автоматизировать.)

Когда что использовать

Скопировано

Если нужно автоматизировать рутину — Gulp или другой менеджер задач.

Если нужны более серьёзные операции над кодом, сложная настройка проекта, более комфортный Developer Experience — Webpack или другой бандлер.

Процесс сборки

Скопировано

— Окей, допустим мы определились с инструментами и транспайлерами, которые хотим использовать. А как процесс выглядит дальше?

Как правило, у нас есть набор исходных файлов, которые написаны на языке, который мы хотим использовать (ActionScript, TypeScript, любой другой язык, соответствующий спецификации ES и т. д.). Мы настраиваем инструменты сборки так, чтобы они, используя исходники, приготовили нам программу на целевом языке (например, JS по спецификации ES5).

В итоге:

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