Статьи

Познакомьтесь с Elixir, способом компиляции активов Laravel

Большое спасибо Джаду Джубрану , Габриэлю Зербибу , Энтони Чамберсу и Скотту Молинари за рецензирование этого поста, а также всем рецензентам SitePoint за то, что они сделали контент SitePoint лучшим, каким он может быть!


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

Одним из таких инструментов являются препроцессоры для CSS и JavaScript. Они уменьшают объем кода в наших таблицах стилей и файлах JavaScript, но нам все равно нужно скомпилировать их в простой CSS и JavaScript, запустив правильный компилятор. Через некоторое время это станет скучной задачей, и вероятность того, что мы забудем что-то запустить, увеличится.

Помимо препроцессоров, нам, как разработчикам, часто приходится выполнять множество задач, включая сшивание файлов JS, тестирование, объединение, минификацию, и это лишь некоторые из них.

Все это привело к созданию основанных на JavaScript исполнителей задач, таких как Grunt и Gulp . Цель этих приложений — автоматизировать задачи, которые нам необходимо выполнять в процессе разработки.

Синтаксис Gulp чистый и простой в использовании, но всегда есть возможность сделать что-то проще. В Laravel 5 был представлен Elixir : инструмент на основе Node.js, разработанный Джеффри Вей , который легко управляет нашими задачами в Gulp.

Эликсир

В этом уроке мы узнаем, как использовать Elixir для управления задачами Gulp с помощью всего лишь нескольких строк кода. Эта статья посвящена компиляции ресурсов в среде Laravel, хотя мы попытаемся охватить использование в других средах.

Требования и установка

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

  1. Node.js
  2. Глоток
  3. Ларавел Эликсир

Node.js

Поскольку Gulp запускается внутри Node.js, мы должны убедиться, что Node.js установлен. Если мы используем Homestead Improved , то мы уже готовы, в противном случае нам нужно установить Node.js.

Gulp.js

Как упоминалось ранее, Elixir является оболочкой для Gulp, поэтому нам также нужно будет запустить Gulp.

Если он еще не установлен (если мы используем Homestead Improved ), мы можем установить его через npm :

 npm install --global gulp 

Ларавел Эликсир

В корневом каталоге Laravel есть файл package.json котором уже есть laravel-elixir 3.0.0, в качестве зависимости. Чтобы установить его, мы запускаем npm install из этого каталога.

Установка Elixir в других средах

Чтобы установить Elixir 3 в среде, отличной от Laravel:

 npm install laravel-elixir --save 

Прежде чем мы начнем

Полезно знать, что Elixir предполагает, что все исходные файлы ( .sass , .coffee , .coffee и т. Д.) Находятся в ./resources/assets/ . Выходные файлы будут скопированы в каталог ./public по умолчанию:

Тип файла Базовый исходный путь Выходной путь
Меньше ./resources/assets/less ./public/css
пререкаться ./resources/assets/sass ./public/css
CoffeeScript ./resources/assets/coffee ./public/js

Чтобы создать задачу Elixir, нам нужно вызвать функцию gulpfile.js в нашем файле gulpfile.js . Эта функция принимает обратный вызов с объектом в качестве аргумента. Этот объект, называемый mix , предоставляет все доступные методы, которые Elixir предоставляет «из коробки».

 // ... elixir ( function ( mix ) { mix . less ( 'styles.less' ) ; } ) ; 

Если мы передадим массив файлов или шаблон, соответствующий группе файлов, все файлы будут скомпилированы и объединены в один файл. Выходное имя файла будет app.css или app.js для файлов CSS и JavaScript соответственно.

Если мы передадим одно имя файла определенному методу, оно будет скомпилировано в файл с тем же именем. Например, если мы передадим styles.less , выходное имя файла будет styles.css .

Однако все эти значения по умолчанию можно настроить с помощью аргументов метода или объекта config Elixir, который мы вскоре обсудим.

Давайте посмотрим некоторые действия

Elixir предоставляет базовые задачи из коробки, включая задачи для компиляции, объединения, минификации, запуска тестовых пакетов и т. Д.

Компиляция Меньше Файлов

Чтобы скомпилировать файлы Less, нам нужно вызвать метод less() объекта mix :

 elixir ( function ( mix ) { mix . less ( "styles.less" ) ; } ) ; 

В вышеупомянутой задаче Elixir предполагает, что styles.less находится в пути resources/assets/less . После компиляции он сохранит выходной файл как public/css/styles.css .

То же самое касается файлов .sass , нам просто нужно изменить метод на sass() следующим образом:

 elixir ( function ( mix ) { mix . sass ( "styles.sass" ) ; } ) ; 

Обратите внимание, что Elixir предполагает, что файлы resources/assets/sass по умолчанию расположены в resources/assets/sass .

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

Компиляция файлов CoffeeScript

Хорошо, теперь давайте посмотрим, как компилируются файлы CoffeeScript:

 elixir ( function ( mix ) { mix . coffee ( [ 'controllers.coffee' , 'services.coffee' ] ) ; } ) ; 

Опять же, Elixir просматривает resources/assets/coffee/ , компилирует все файлы .coffee в код JavaScript и копирует их в каталог public/js как app.js

Это так просто!

Идти глубже

Компиляция нескольких файлов

Методы эликсира, такие как sass() , less() , coffee() следуют одному и тому же прототипу. Мы можем либо передать одно имя файла, символы подстановки, массив имен файлов, либо вообще не передавать аргументы.

Чтобы скомпилировать несколько файлов Less:

 elixir ( function ( mix ) { mix . less ( [ 'base.less' , 'styles.less' , 'custom.less' ] ) ; } ) ; 

В результате выходные данные будут скомпилированы в public/css/app.css .

То же самое касается других методов, таких как sass() , coffee() и т. Д.

Различные исходные и выходные каталоги

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

Использование аргументов

Все методы принимают второй аргумент, который определяет базовый выходной каталог:

 elixir ( function ( mix ) { mix . less ( [ 'base.less' , 'styles.less' 'custom.less' ] , 'resources/build/css' ) ; } ) ; 

В результате вышеупомянутая задача скомпилирует файлы Less в resources/build/css/app.css .

Чтобы изменить имя выходного файла , мы можем включить имя файла в аргумент:

 elixir ( function ( mix ) { mix . less ( [ 'base.less' , 'styles.less' 'custom.less' ] , 'resources/build/css/styles.css' ) ; } ) ; 

Предоставление полных путей

Помимо настройки базовых исходных и выходных путей, мы можем передать полный путь к файлу с префиксом ./ . Если заданному пути предшествует точка, Elixir предполагает, что пользователь хочет начать с корневого каталога проекта.

 elixir ( function ( mix ) { mix . less ( [ './resources/assets/src/less/base.less' ] ) ; } ) ; 

Использование объекта Config

Предпочтительным способом настройки стандартных исходных и выходных путей является изменение параметров css.output и js.output в объекте config Elixir. Мы обсудим это в разделе « Настройка эликсира ».

Объединение файлов

Elixir предоставляет несколько методов для объединения таблиц стилей и файлов JavaScript, используя scripts() для JavaScript и styles() для файлов CSS.

 elixir ( function ( mix ) { mix . styles ( [ 'base.css' , 'customized.css' ] ) . scripts ( [ 'app.js' , 'code.js' ] ) ; } ) ; 

Базовый источник и выходные пути для конкатенации

Методы scripts() и styles() предполагают, что исходные файлы по умолчанию находятся в public/js и resources/assets/css . После компиляции объединенная версия будет скопирована в public/js и public/css :

Тип Базовый исходный путь
CSS ./resources/assets/css
JavaScript ./public/js

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

Базовый выходной путь

Чтобы изменить выходной путь, мы можем сделать:

 elixir ( function ( mix ) { mix . styles ( [ 'base.css' , 'customized.css' ] , 'public/build/css' ) . scripts ( [ 'app.js' , 'code.js' ] , 'public/build/js' ) } ) ; 

По умолчанию имя выходного файла конкатенации — all.css для CSS и all.js для файлов JavaScript. Мы можем изменить это, включив имя файла в аргумент:

 elixir ( function ( mix ) { mix . styles ( [ 'base.css' , 'customized.css' ] , 'public/build/css/application.css' ) . scripts ( [ 'app.js' , 'code.js' ] , 'public/build/js/application.js' ) ; } ) ; 

В результате выходные данные будут сохранены как application.js и application.css .

Базовый исходный путь

Мы можем изменить базовый исходный путь с помощью третьего аргумента:

 elixir ( function ( mix ) { mix . styles ( [ 'base.css' , 'customized.css' ] , 'public/build/css/application.css' , 'public/css' ) . scripts ( [ 'app.js' , 'code.js' ] , 'public/build/js/application.js' , 'public/js' ) ; } ) ; 

Конкатенация всех файлов

Если нам нужно объединить все файлы в определенном каталоге, мы можем использовать scriptsIn() и stylesIn() :

 elixir ( function ( mix ) { mix . scriptsIn ( 'public/js' ) . stylesIn ( 'public/css' ) } ) ; 

Jade to Blade Подборка

В этом разделе рассказывается о компиляции Jade-файлов в шаблоны Blade.

Elixir не поддерживает компиляцию Jade to Blade из коробки. Однако это возможно с помощью пакета npm , называемого laravel-elixir-jade . Он компилирует jade файлы в файлы .blade.php .

Чтобы установить laravel-elixir-jade :

 npm install laravel - elixir - jade@ 0.1 . 8 -- save - dev 

В результате laravel-elixir-jade будет установлен и добавлен в devDependencies внутри нашего файла package.json .

Elixir предполагает, что файлы jade находятся в resources/jade , и копирует выходные файлы в resources/views .

Для компиляции файлов .jade мы используем метод jade :

 var elixir = require ( 'laravel-elixir' ) ; require ( 'laravel-elixir-jade' ) ; elixir ( function ( mix ) { mix . jade ( { search : '**/*.jade' } ) ; } ) ; 

jade() ожидает объект, содержащий все возможные опции:

 { baseDir : './resources' , blade : true , dest : '/views/' , pretty : true , search : '**/*.jade' , src : '/jade/' } 

Все параметры говорят сами за себя: baseDir , dest , search и src определяют исходные и выходные каталоги.

pretty инструктирует Elixir сохранить все разрывы строк и отступы. Это true по умолчанию.

Установив blade в false , мы даем Elixir команду компилировать в файлы .php вместо файлов .blade.php .

Также есть полезная коллекция нефритовых миксинов, разработанных @franzose .

Управление версиями файлов

Elixir также предоставляет функцию контроля версий, которая добавляет уникальный хэш к именам файлов. Это предотвратит загрузку браузером файлов ресурсов из своего кэша. Раньше нам приходилось добавлять номер версии к имени файла в виде строки запроса (? V = 2), но не больше!

Используя метод Elixir version() , теперь все намного проще. Единственное, что нам нужно передать методу version() — это полный путь к файлу:

 elixir ( function ( mix ) { mix . version ( "./public/build/js/all.css" ) ; } ) ; // We can also pass an array to the version method. elixir ( function ( mix ) { mix . version ( [ './public/build/js/all.js' , './public/build/js/code.js' ] ) ; } ) ; 

В результате имя файла будет styles.all-16d570a7.css примерно так: styles.all-16d570a7.css . Запоминание этого имени — еще одна проблема. Хорошо, что мы не должны иметь дело с этим самостоятельно, поскольку Laravel уже позаботился об этом для нас.

В наших представлениях Blade мы можем использовать вспомогательную функцию elixir() для ссылки на хешированный файл:

 @block('stylesheets') < link rel = " stylesheet " type = " text/css " href = " {{ elixir( " styles . all . css ") }}" > @endblock 

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

Начиная с Elixir 3.0, мы должны предоставить полный путь к файлу. Это означает, что мы даже можем использовать version() для всех других файлов в нашем проекте.

Конфигурирование эликсира

Одним из преимуществ Elixir является то, что его можно настраивать с помощью объекта config. Все доступные опции существуют в node_modules/laravel-elixir/Config.js . Если мы откроем файл, то увидим, что есть объект config содержащий все настройки, которые определяют поведение Elixir. Если мы используем Elixir в среде Laravel, нам не придется изменять большинство этих параметров, поскольку они уже совместимы с макетом каталогов Laravel.

Настройки сгруппированы внутри вложенных объектов (в зависимости от их использования) внутри объекта config . Например, параметры, относящиеся к файлам .css , определены в объекте css :

 // ... css : { folder : 'css' , outputFolder : 'css' , autoprefix : { enabled : true , // https://www.npmjs.com/package/gulp-autoprefixer#api options : { browsers : [ 'last 2 versions' ] , cascade : false } } } // ... 

Чтобы увидеть все доступные параметры, пожалуйста, проверьте файл Config.js .

Чтобы переопределить настройки по умолчанию, мы можем получить к ним доступ через объект gulpfile.js в gulpfile.js :

 //... elixir . config . assetsPath = 'resources/assets/src/' ; 

Чтобы настроить группу параметров, мы можем создать файл elixir.json в корневом каталоге нашего проекта и объявить объект, содержащий параметры, которые мы должны переопределить:

elixir.json

 { "assetsPath" : "resources/assets/src" , "css" : { "outputFolder" : "stylesheets" } } 

Все, что мы добавим в этот объект, переопределит настройки по умолчанию в основном объекте config .

Пример из реального мира

Давайте посмотрим на силу эликсира в реальном мире. Мы будем управлять нашими активами в проекте Laravel / Angular.

Структура каталога активов

Представьте себе, что макет каталога наших resources :

 . . . resources ├── assets │ └── src │ ├── coffee │ │ ├── app . coffee │ │ ├── base . coffee │ │ ├── controllers . coffee │ │ ├── directives . coffee │ │ └── services . coffee │ └── less │ ├── base . less │ ├── bootstrap │ ├── footer . less │ ├── header . less │ ├── styles . less │ ├── typography . less │ └── Bootstrap │ └── . . . ├── jade │ ├── dashboard . jade │ ├── incs │ │ ├── footer . jade │ │ └── navbar . jade │ ├── layouts │ │ ├── base . jade │ │ └── master . jade │ ├── list . jade │ └── login . jade . . . 

Все файлы ресурсов находятся в ./resources/assets/src .

Обратите внимание, что в каталоге less нам нужно только скомпилировать styles.less , потому что все остальные файлы styles.less уже импортированы в него:

 /* resources/assets/src/less/styles.less */ @import "bootstrap/bootstrap.less" ; @import "base.less" ; @import "typography.less" ; @import "header.less" ; @import "footer.less" ; 

Причина, по которой mixins и переменные Bootstrap импортируются в styles.less заключается в том, чтобы использовать существующие mixins и переменные, которые предоставляет Bootstrap. Результатом будет настроенный файл Bootstrap. Тем не менее, это всего лишь один из способов написания таблиц стилей, которые могут отличаться от проекта к проекту.

Давайте перечислим шаги, которые мы должны предпринять для нашей компиляции активов:

  • Шаг 1: Загрузите Elixir и другие необходимые модули в наш gulpfile.js

  • Шаг 2: Настройте эликсир, используя elixir.json

  • Шаг 3: Скомпилируйте файл styles.less в public/build/styles.css

  • Шаг 4: Скомпилируйте все файлы .coffee в код JavaScript и сохраните вывод как public/build/js/app.js

  • Шаг 5: Скомпилируйте файлы .blade.php шаблоны .blade.php , чтобы они могли отображаться с помощью блейд-движка Laravel.

  • Шаг 6: Создание версий файлов для очистки кеша.

Написание задач

Прелесть Elixir в том, что все, что мы делаем, определяется в gulpfile.js . Это означает, что мы можем смешивать синтаксис Elixir с синтаксисом Gulp, особенно когда мы расширяем Elixir.

Шаг 1: загрузка необходимых модулей

В нашем gulpfile.js мы пишем следующий код:

 var elixir = require ( 'laravel-elixir' ) ; require ( 'laravel-elixir-jade' ) ; 

Сначала мы загрузили Elixir и поместили его в переменную elixir для дальнейшего использования. Затем мы загрузили laravel-elixir-jade для компиляции наших jade файлов.

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

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

Для этого мы создаем файл в корневом каталоге нашего проекта с именем elixir.json со следующим содержимым:

 { assetsPath : 'resources/assets/src' , publicPath : 'public/build' } 

Шаг 3: Компиляция меньшего количества файлов

 elixir ( function ( mix ) { mix . less ( 'styles.less' ) ; } ) ; 

Шаг 4: Компиляция файлов CoffeeScript

 elixir ( function ( mix ) { mix . coffee ( [ 'app.coffee' , 'base.coffee' , 'controllers.coffee' , 'directives.coffee' , 'services.coffee' ] ) ; } ) ; 

Вышеуказанная задача скомпилирует все файлы .coffee public/build/js как app.js

Шаг 5: Компиляция файлов Jade

В нашем каталоге resources/jade у нас есть два подкаталога, incs и layouts , которые содержат файлы макетов и несколько частей для панели навигации и раздела incs колонтитула. У нас также есть несколько файлов для просмотра, включая страницу входа в систему, страницу панели инструментов и список.

Чтобы скомпилировать файлы .jade , мы используем метод jade следующим образом:

 elixir ( function ( mix ) { mix . jade ( { search : '**/*.jade' } ) ; } ) ; 

Вышеуказанная задача рассмотрит каталог и подкаталоги ./resources/jade и скомпилирует все файлы .blade.php файлы .blade.php .

Шаг 6: Версионирование файлов

На нашем последнем шаге давайте сделаем версию файлов, чтобы позаботиться о разрушении кэша:

 elixir ( function ( mix ) { mix . version ( [ './public/css/styles.css' , './public/js/app.js' ] ) ; } ) ; 

И это все, что нужно сделать. Наш gulpfile.js готов!

Это полный код:

 var elixir = require ( 'laravel-elixir' ) ; require ( 'laravel-elixir-jade' ) ; elixir ( function ( mix ) { mix . less ( 'styles.less' ) . coffee ( [ 'app.coffee' , 'base.coffee' , 'controllers.coffee' , 'directives.coffee' , 'services.coffee' ] ) ; . jade ( { search : '**/*.jade' } ) . version ( [ 'build/css/styles.css' , 'build/js/app.js' ] ) ; } ) ; 

Elixir позволяет связывать методы, как показано в последнем коде выше.

Выполнение задач

Для запуска задач нам просто нужно вызвать gulp :

 gulp 

Это запустит все задачи, зарегистрированные в Elixir.

Мы также можем watch за изменениями в файлах, чтобы автоматизировать выполнение задач, поэтому нам не придется запускать gulp всякий раз, когда мы вносим изменения в файл:

 gulp watch 

Выполнение индивидуальных задач

Всякий раз, когда мы добавляем задачу в Elixir, за кулисами, в Gulp регистрируется одноименная задача. Например, если мы используем метод less() в Elixir, имя задачи Gulp будет less . Это означает, что мы сможем выполнять задачи индивидуально, как мы обычно делаем с Gulp.

 gulp less 

Как насчет минификации?

Одним из распространенных применений таких исполнителей задач, как Grunt или Gulp, является минимизация содержимого файлов, чтобы сделать их меньше и сохранить пропускную способность. Используя Elixir, единственное, что нам нужно сделать, это отправить опцию --production при запуске команды --production :

 gulp -- production 

Идя вперед

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

Эликсир предоставляет основные задачи из коробки. В большинстве случаев этого более чем достаточно. Тем не менее, мы можем столкнуться с ситуациями, когда существующие задачи не могут обрабатывать определенные операции, что означает, что пришло время расширить Elixir!

Для этой цели Elixir предлагает метод extend . Метод extend принимает два параметра. Первая — это имя пользовательской задачи, а вторая — обратный вызов, в котором мы пишем задачу Gulp.

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

 var elixir = require ( 'laravel-elixir' ) , gulp = require ( 'gulp' ) , shell = require ( 'gulp-shell' ) ; Elixir . extend ( 'saysHi' , function ( message ) { new Elixir . Task ( 'saysHi' , function ( ) { return gulp . src ( '' ) . pipe ( shell ( 'Hi, I am a custom task!' ) ) ; } ) . watch ( './app/**' ) ; } ) ; 

watch() регистрирует наблюдателя. В результате, когда мы редактируем любые файлы, соответствующие регулярному выражению, задача запускается.

Мы можем поместить этот блок в gulpfile.js файла gulpfile.js или поместить его во внешний файл и импортировать в наш gulpfile.js :

 var elixir = require ( 'laravel-elixir' ) ; require ( './elixir-extensions' ) ; 

Настраиваемая задача теперь доступна через объект mix :

 elixir ( function ( mix ) { mix . saysHi ( ) ; } ) ; 

Теперь каждый раз, когда мы запускаем gulp saysHi , на экране будет напечатан следующий текст:

 gulp custom Task [ 01 : 10 : 57 ] Using gulpfile ~ / www / sites / elixir / gulpfile . js [ 01 : 10 : 57 ] Starting 'saysHi' . . . Hi , I am a custom task ! [ 01 : 10 : 57 ] Finished 'saysHi' after 370 μs 

Использование ресурсов в шаблонах лезвий

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

 @block('scripts') < link rel = " stylesheet " type = " text/css " href = " {{ elixir('css/styles.all.css') }} " > @stop @block('styles') < script src = " {{ elixir('css/scripts.all.js') }} " > @stop 

Теперь у нас есть спокойствие о версиях и мы можем сосредоточиться на проекте!

Завершение

Elixir — это оболочка для Gulp.js, предоставляющая широкий спектр функциональных возможностей, помогающих нам в составлении наших активов. В дополнение к стандартным задачам Gulp, он также предоставляет несколько методов для управления версиями, тестирования и копирования файлов, и это лишь некоторые из них. Эликсир очень гибкий. Мы можем настроить его, расширить и даже объединить со стандартным синтаксисом Gulp.

Основное внимание в этом руководстве уделялось составлению ресурсов. Тем не менее, есть еще несколько функций Elixir, которые мы не рассмотрели в этом руководстве, например, задачи по копированию файлов, тестированию и даже запуску команд Laravel Artisan. Чтобы узнать больше, пожалуйста, обратитесь к официальной документации Elixir .

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

Спасибо за прочтение. Оставьте свои вопросы и комментарии ниже!