Статьи

Транспортировка модулей ES6 в AMD и CommonJS с помощью Babel & Gulp

В ECMAScript 6 (он же ECMAScript 2015 или ES6) спецификация для следующей версии JavaScript была утверждена, и поставщики браузеров усердно работают над ее реализацией. В отличие от предыдущих версий ECMAScript, ES6 поставляется с огромным набором изменений в языке, чтобы сделать его подходящим для масштаба, в котором он используется сегодня. Sitepoint имеет ряд статей, посвященных этим функциям.

Хотя браузеры еще не реализовали все функции , мы уже можем использовать ES6 во время разработки и преобразовать его в версию, понятную браузеру, перед отправкой приложения. Babel и Traceur — два ведущих транспортера, используемые для этой цели. Типизированный расширенный набор JavaScript от Microsoft, TypeScript также может использоваться в качестве транспортера ES6.

Я рассказал о том, как ES6 можно использовать сегодня для написания приложений Angular 1.x, в одной из моих предыдущих статей . В этой статье я использовал транспортер Traceur на лету для запуска приложения. Несмотря на то, что это работает, всегда лучше перенести данные заранее и сократить объем работы, выполняемой в браузере. В этой статье мы увидим, как одно и то же приложение-пример может быть перенесено в ES5 и модули в CommonJS или AMD, использующие Babel для запуска в современных браузерах. Хотя выборка основана на Angular, методы переноса могут использоваться с любым действующим кодом ES6.

Как всегда, вы можете найти код, сопровождающий эту статью, на нашем репозитории GitHub .

Важность модулей

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

Важность модулей не ограничивается приложениями. Даже большие библиотеки JavaScript могут использовать преимущества модульной системы для экспорта своих объектов в виде модулей, а приложения, использующие библиотеки, импортируют эти модули по мере необходимости. Angular 2 и Aurelia начали использовать эту функцию.

Если вы хотите быстро освоить использование модулей в ES6, прочитайте: Понимание модулей ES6

О пробной заявке

Предметом нашего примера приложения является виртуальная книжная полка. Он состоит из следующих страниц:

  1. Домашняя страница: показывает список активных книг, которые можно пометить как прочитанные или перенести в архив.
  2. Страница добавления книги: добавляет новую книгу на полку, принимая название книги и имя автора. Это не позволяет дублировать названия.
  3. Страница архива: список всех архивных книг.

Приложение построено с использованием AngularJS 1.3 и ES6. Если вы посмотрите на любой из файлов в папке app , вы увидите ключевые слова export и import используемые для экспорта объектов из текущего модуля и для импорта объектов из других модулей. Теперь наша задача — использовать задачи Babel Gulp для преобразования этих модулей в одну из существующих модульных систем.

Но я не использую Angular. Я просто хочу конвертировать модули ES6 в CommonJS / AMD

Не стоит беспокоиться! Мы вас прикрыли. С небольшим количеством настроек рецепты, показанные ниже, могут быть использованы в любом проекте, включающем модули ES6. Angular здесь совершенно не важен.

Преобразование в CommonJS

CommonJS — это модульная система, определенная группой CommonJS . Это синхронная модульная система, в которой модули загружаются с использованием функции require и экспортируются с использованием свойства exports объекта module . Ожидается, что объект module будет доступен во всех модулях по умолчанию.

Node.js использует эту систему модулей, поэтому он определяет объект module и делает его доступным для вашего приложения. Поскольку в браузерах этот объект не определен, нам нужно использовать утилиту Browserify, чтобы заполнить пробел.

Прежде чем мы начнем, нам также нужно будет установить несколько пакетов npm. Это позволит нам использовать Babel и Browserify совместно с Gulp для преобразования наших модулей ES6 в один из распространенных форматов модулей и упаковки приложения в единый файл для использования браузером.

  • gulp-babel — конвертирует код ES6 в ванильный ES5
  • Browserify — позволяет вам require('modules') в браузере, объединяя все ваши зависимости
  • vinyl-source-stream — обрабатывает модуль Browserify напрямую, избегая необходимости в обертке gulp-browserify
  • винил-буфер — преобразует поток в буфер (необходим для gulp-uglify, которая не поддерживает потоки)
  • gulp-uglify — минимизирует файлы
  • del — позволяет удалять файлы и папки
  • gulp-rename — плагин, позволяющий переименовывать файлы

Вы можете получить этот лот, набрав:

 npm install gulp-babel browserify gulp-browserify vinyl-source-stream vinyl-buffer gulp-uglify del gulp-rename --save-dev 

Теперь давайте начнем использовать эти пакеты в нашем gulpfile.js . Нам нужно написать задачу, чтобы взять все файлы ES6 и передать их Бабелю. По умолчанию в Babel используется модульная система CommonJS, поэтому нам не нужно отправлять какие-либо параметры в функцию babel.

 var babel = require('gulp-babel'), browserify = require('browserify'), source = require('vinyl-source-stream'), buffer = require('vinyl-buffer'), rename = require('gulp-rename'), uglify = require('gulp-uglify'), del = require('del'); gulp.task('clean-temp', function(){ return del(['dest']); }); gulp.task('es6-commonjs',['clean-temp'], function(){ return gulp.src(['app/*.js','app/**/*.js']) .pipe(babel()) .pipe(gulp.dest('dest/temp')); }); 

Надеюсь, здесь нет ничего слишком запутанного. Мы объявляем задачу es6-commonjs которая захватывает любые файлы JavaScript в каталоге приложения и любых его подкаталогах. Затем он передает их через Babel, который, в свою очередь, преобразует отдельные файлы в модули ES5 и CommonJS и копирует преобразованные файлы в папку dest/temp . Задача es6-commonjs имеет зависимость с именем clean-temp , которая удаляет каталог dest и все файлы в нем до es6-commonjs задачи es6-commonjs .

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

 .pipe(babel({ modules:"common" })) 

Теперь мы можем создать один связанный файл из этих отдельных файлов, применив Browserify, а затем свернуть вывод с помощью пакета uglify. Следующий фрагмент показывает это:

 gulp.task('bundle-commonjs-clean', function(){ return del(['es5/commonjs']); }); gulp.task('commonjs-bundle',['bundle-commonjs-clean','es6-commonjs'], function(){ return browserify(['dest/temp/bootstrap.js']).bundle() .pipe(source('app.js')) .pipe(buffer()) .pipe(uglify()) .pipe(rename('app.js')) .pipe(gulp.dest("es5/commonjs")); }); 

Вышеуказанная задача имеет две зависимости: первая — это задача bundle-commonjs-clean , которая удалит каталог es5/commonjs , вторая — ранее обсуждаемая es6-commonjs . После запуска задача помещает объединенный и уменьшенный файл app.js в папку es5/commonjs . На этот файл можно ссылаться непосредственно в index.html а страницу можно просматривать в браузере.

Наконец, мы можем добавить задачу, чтобы начать работу:

 gulp.task('commonjs', ['commonjs-bundle']); 

Преобразование в AMD

Система асинхронного определения модулей (AMD) — это, как следует из названия, асинхронная система загрузки модулей. Он позволяет загружать несколько зависимых модулей параллельно и не ожидает полной загрузки одного модуля, прежде чем пытаться загрузить другие модули.

Require.js — библиотека, используемая для работы с AMD. RequireJS доступен через Bower:

 bower install requirejs --save 

Нам также нужен плагин Gulp для require.js для комплектации приложения. Для этого установите пакет gulp-requirejs npm.

 npm install gulp-requirejs --save-dev 

Теперь нам нужно написать задачи для преобразования кода ES6 в ES5 и AMD, а затем связать его с помощью RequireJS. Задачи очень похожи на задачи, созданные в разделе CommonJS.

 var requirejs = require('gulp-requirejs'); gulp.task('es6-amd',['clean-temp'], function(){ return gulp.src(['app/*.js','app/**/*.js']) .pipe(babel({ modules:"amd" })) .pipe(gulp.dest('dest/temp')); }); gulp.task('bundle-amd-clean', function(){ return del(['es5/amd']); }); gulp.task('amd-bundle',['bundle-amd-clean','es6-amd'], function(){ return requirejs({ name: 'bootstrap', baseUrl: 'dest/temp', out: 'app.js' }) .pipe(uglify()) .pipe(gulp.dest("es5/amd")); }); gulp.task('amd', ['amd-bundle']); 

Чтобы использовать последний скрипт на странице index.html, нам нужно добавить ссылку на RequireJS, сгенерированный скрипт, а затем загрузить модуль bootstrap . Файл bootstrap.js внутри папки app загружает приложение AngularJS, поэтому нам нужно загрузить его, чтобы запустить приложение AngularJS.

 <script src="bower_components/requirejs/require.js" ></script> <script src="es5/amd/app.js"></script> <script> (function(){ require(['bootstrap']); }()); </script> 

Вывод

Модули являются давно назревшей функцией в JavaScript. Они прибудут в ES6, но, к сожалению, их собственная поддержка браузера в настоящее время оставляет желать лучшего. Это, однако, не означает, что вы не можете использовать их сегодня. В этом уроке я продемонстрировал, как использовать Gulp, Babel и различные плагины для преобразования модулей ES6 в формат CommonJS и AMD, которые вы можете запустить в своем браузере.

А что касается ES6? ES6 привлек большое внимание в сообществе, так как это было объявлено. Он уже используется несколькими библиотеками JavaScript или средами, включая подключаемые модули Bootstrap для JavaScript, Aurelia, Angular 2 и некоторыми другими. В TypeScript также добавлена ​​поддержка нескольких функций ES6, включая модули. Изучение и использование ES6 сегодня сократит усилия, необходимые для преобразования кода в будущем.