LESS-компиляция через Node.js и Grunt
09-12-2015Reading time ~ 5 min.CSS, HTML, LESS, SASS 14146
Смысл этой затеи в том, чтобы автоматизировать компиляцию less-файлов. Работать должно так: сохранили любой less-файл, сам запускается компилятор и на выходе получается готовый css-файл. Сейчас я расскажу про вариант, который может использоваться любым вебмастером, но самое главное, что он универсальный и подходит и для других целей, например компиляция SCSS.
Перед началом, давайте определимся с основными понятиями.
Всё будет работать на Node.js. Node.js — это интерпретатор JavaScript. То есть исходные/исполняемые файлы для Ноды — это js-файлы. По большому счёту, нам вообще всё-равно как там что работает. Для нас главное — установить Node.js на свой компьютер. Делается это очень просто — загружается msi-файл с официального сайта и устанавливаем как обычную windows-программу.
Сразу отдельное замечание о том, как обновлять Node.js. В теории он может обновить себя сам. На практике же, проще скачать новую версию и её установить. Тогда никаких проблем не возникает.
В комплекте Node.js есть т.н. пакетный менеджер npm. Он позволяет устанавливать, удалять, обновлять и т.п. модули Node.js. Модули или пакеты — это что-то вроде программ, ради которых всё это безобразие и затевалось. Например Grunt — это модуль для автоматизации различных задач.
Работать с Node.js придется командной строкой через консоль. Стандартная консоль Windows — вещь не для слабонервных, поэтому я рекомендую поставить альтернативную. Сам я пользуюсь conemu. Консоль годится не только для Node.js, но и для кучи других задач. Для удобства conemu можно добавить в панель Total Commander.
Проверить работу Node.js можно выполнив команду
node -v
— которая выводит свою версию.
Для less-компиляции нужно установить модуль less. Делается это командой:
npm install -g less
Эта команда выполняет установку (install) модуля «less». Ключ «-g» указывает выполнить установку глобально. Если не указывать этот ключ, то установка модуля будет осуществляться только в текущий каталог. Таким образом делается установка любого другого модуля. Node.js сам скачивает через Интернет нужные файлы.
У модуля могут быть свои плагины. Например у «less» есть плагин сжатия css «less-plugin-clean-css». Устанавливается он точно также:
npm install -g less-plugin-clean-css
После такой установки в консоли будет доступна команда lessc, которой и выполняется ручная компиляция less-файлов.
Модули могут использовать другие модули (пакеты). Причём каких-то определенных версий. Человеческий мозг не в состоянии охватить всё это великолепие взаимодействие, поэтому все эти зависимости прописываются в самих модулях разработчиками. Отсюда получается, что устанавливая какой-то модуль, будет автоматом установлен еще один, там еще и т.д. В итоге модулей может оказаться довольно прилично. Я об этом специально упоминаю, потому что требуемый модуль может весить 2МБ, а подтянет за собой ещё 20МБ.
Сложность ещё в том, что все требуемые модули располагаются в каталоге проекта. Ну например, less-компиляция. Если у нас 10 шаблонов, то придется настроить все 10 проектов в каждом каталоге шаблона. То есть к 200КБ less-файлов придется таскать по 20МБ node-файлов.
Как обхитрить это недоразумение, я расскажу ниже, пока же рассмотрим еще одну особенность работы с Node.js.
Для того, чтобы управлять пакетами в проекте (проект — по сути это просто рабочий каталог), используется специальный файл package.json. В нём задаются настройки проекта, включая и используемые модули. То есть перед тем, как запустить Node.js для проекта, нужно создать package.json. Вот пример файла, который мы будем использовать для Grunt:
{ "author" : "author", "name" : "ProjectName", "version" : "1.0.0", "devDependencies" : { "grunt" : ">= 0.4", "grunt-cli" : ">= 0.1.6", "grunt-contrib-watch" : "~0.3.1", "grunt-contrib-less" : ">=0.12.0" } }
Секция devDependencies как раз и указывает какие модули будет использовать проект.
Инсталяция/инициализация проекта выполняется командой:
npm install
После этого Node.js немного пошурстит и в результате появится каталог node_modules. Этот каталог (и package.json) можно просто копировать между одинаковыми проектами без инсталяций.
Теперь поговорим о Grunt.
Grunt используется для автоматизации самых разных задач. Там гиганское количество плагинов и я предлагаю просто пробежаться глазами, чтобы оценить всю мощь этого инструмента. Нас будут интересовать grunt-contrib-less, который выполняет задачу less-компиляции и grunt-contrib-watch, который отслеживает каталоги на изменения и запускает нужные задачи (в нашем случае less).
Установить Grunt можно такими командами:
npm install -g grunt-cli npm install -g grunt-contrib-less --save-dev npm install -g grunt-contrib-watch --save-dev
Настраивать Grunt в проекте нужно через файл Gruntfile.js. Для основы возьмем такой вариант:
module.exports = function(grunt) { grunt.initConfig({ less: { development: { options: { compress: true, yuicompress: true, optimization: 2 }, files: { // target.css file: source.less file "css/main.css": "less/main.less" } } }, watch: { styles: { files: ['less/**/*.less'], // which files to watch tasks: ['less'], options: { nospawn: true } } } }); grunt.loadNpmTasks('grunt-contrib-less'); grunt.loadNpmTasks('grunt-contrib-watch'); grunt.registerTask('default', ['watch']); };
В секции watch в параметре files указывается маска (можно явно файл) для less-файлов в каталоге less. Все пути указываются относительно каталога проекта.
В секции less задаются непосредственно параметры компиляции. Здесь указан исходный и конечный файлы: less/main.less скомпилируется в css/main.css.
После этого запускаем Grunt командой:
grunt
Если не было ошибок, то появится что-то вроде этого
Running "watch" task Waiting...
Теперь изменим less/main.less и увидим сообщение
Completed in 2.752s at Wed Dec 09 2015 13:07:24 - Waiting...OK File "less/main.less" changed.
То есть любые изменения в less, автоматом приводят к компиляции css-файла. Чтобы остановить отслеживание, нажмите Ctrl+C
.
Когда у вас 1-2 проекта, то в принципе можно на node_modules не обращать особого внимания. Но, когда проектов десятки, да ещё и в разных местах, то это уже проблема. Чтобы обойти это безобразие я придумал небольшую хитрость. Дело в том, что Grunt позволяет одновременно отслеживать несколько каталогов и не обязательно в каталоге проекта.
Таким образом можно создать проект где-то совершенно отдельно (вообще пофиг где), а в задачи Grunt добавить пути к нужным нам less-каталогам (например шалоны MaxSite CMS). Делается это в Gruntfile.js так (показываю только изменные строчки):
less: { ... files: { "d:/xampp/htdocs/cms/application/maxsite/templates/default/assets/css/style.css": "d:/xampp/htdocs/cms/application/maxsite/templates/default/assets/less/style.less", "d:/xampp/htdocs/cms/application/maxsite/templates/d2000/assets/css/style.css": "d:/xampp/htdocs/cms/application/maxsite/templates/d2000/assets/less/style.less" } ... watch: { ... files: [ 'd:/xampp/htdocs/cms/application/maxsite/templates/default/assets/less/**/*.less', 'd:/xampp/htdocs/cms/application/maxsite/templates/d2000/assets/less/**/*.less' ], ...
— то есть здесь просто перечисляются каталоги и файлы с полными путями на диске. Если нужно добавить новый проект, то достаточно добавить две его строчки и заново запустить Grunt.
В conemu, кстати, есть пункт меню «Hide to TSA», который сворачивает консоль в иконку «к часикам» и не маячит на панели задач. Довольно удобно получается.