Недавно я отвечал за оптимизацию Sass в довольно большом Rails-проекте, и одна из самых важных вещей, которую нужно было сделать, — это улучшить время компиляции. Из-за имеющейся архитектуры Sass и того факта, что Ruby Sass (в данном случае через конвейер ресурсов Rails) имеет тенденцию работать медленно при работе с огромным количеством файлов, компиляция таблиц стилей может занять до 40 секунд. Поговорим о быстром процессе разработки. ?
Моя идея состояла в том, чтобы отойти от конвейера активов и использовать скорость LibSass . Чтобы сделать вещи проще, я решил пойти с простым рабочим процессом Gulp . Это был первый раз, когда я использовал Gulp, и я должен сказать, что это был довольно приятный опыт (что касается Гранта, насколько я понимаю).
В этой короткой статье давайте кратко рассмотрим, как настроить рабочий процесс Gulp’y для работы с Sass. Вот что мы будем включать:
- Неудивительно, что компиляция Sass с LibSass
- Создание исходных карт для облегчения отладки
- Префикс CSS с помощью автопрефиксера
- Генерация документации Sass с помощью SassDoc
Компиляция Sass
Первое, что нужно сделать, это установить зависимости и создать Gulpfile.js
. Нам понадобится Gulp (без дерьма, Шерлок), но также Gulp-sass для компиляции наших таблиц стилей:
$ npm install gulp gulp-sass --save-dev
Эта строка указывает npm установить оба пакета gulp-sass
и gulp-sass
качестве зависимостей разработки. Теперь вы можете найти их в объекте devDependencies
вашего package.json
. И Gulpfile.js
:
var gulp = require('gulp'); var sass = require('gulp-sass');
Вау, это было коротко. Теперь нам нужно запустить Sass (фактически gulp-sass
) в нашей папке стилей.
var input = './stylesheets/**/*.scss'; var output = './public/css'; gulp.task('sass', function () { return gulp // Find all `.scss` files from the `stylesheets/` folder .src(input) // Run Sass on those files .pipe(sass()) // Write the resulting CSS in the output folder .pipe(gulp.dest(output)); });
Это оно! Теперь мы можем скомпилировать наши таблицы стилей, используя LibSass, благодаря очень минимальной задаче Gulp. Что об этом? Мы можем передать параметры в gulp-sass
для компиляции таблиц стилей в расширенном режиме и для вывода ошибок в консоли:
var sassOptions = { errLogToConsole: true, outputStyle: 'expanded' }; gulp.task('sass', function () { return gulp .src(input) .pipe(sass(sassOptions).on('error', sass.logError)) .pipe(gulp.dest(output)); });
Добавление исходных карт
Все идет нормально. А как насчет генерации исходных карт? Если вы не знаете, что такое исходные карты, это в основном способ сопоставить сжатые производственные источники с расширенными источниками разработки, чтобы упростить отладку живого кода. Они вообще не ограничены CSS, исходные карты можно использовать и в JavaScript.
У нас есть хорошая статья об исходных картах здесь, в SitePoint . Не стесняйтесь прочитать его перед тем, как продолжить, если вам не хватает понимания исходных карт.
Итак, чтобы добавить генерацию исходных карт в нашу задачу, нам нужно установить gulp-sourcemaps :
$ npm install gulp-sourcemaps --save-dev
А теперь давайте оптимизируем нашу задачу:
var gulp = require('gulp'); var sass = require('gulp-sass'); var sourcemaps = require('gulp-sourcemaps'); // ... variables gulp.task('sass', function () { return gulp .src(input) .pipe(sourcemaps.init()) .pipe(sass(sassOptions).on('error', sass.logError)) .pipe(sourcemaps.write()) .pipe(gulp.dest(output)); });
По умолчанию gulp-sourcemaps
записывает исходные карты в скомпилированные CSS-файлы. В зависимости от настроек проекта, мы можем захотеть записать их в отдельные файлы, и в этом случае мы можем указать путь относительно gulp.dest()
назначения sourcemaps.write()
функции sourcemaps.write()
например:
gulp.task('sass', function () { return gulp .src(input) .pipe(sourcemaps.init()) .pipe(sass(sassOptions).on('error', sass.logError)) .pipe(sourcemaps.write('./stylesheets/maps')) .pipe(gulp.dest(output)); });
Привлечение Автопрефиксера на вечеринку
Я не буду вдаваться в подробности о том, почему использование Autoprefixer лучше, чем написание поставщика вручную (или с миксином, который в основном то же самое), но примерно Autoprefixer — это этап пост-обработки, означающий, что он фактически обновляет уже скомпилированные таблицы стилей для добавления соответствующие префиксы на основе современной базы данных и заданной конфигурации. Другими словами, вы сообщаете Autoprefixer, какие браузеры вы хотите поддерживать, и он добавляет только соответствующие префиксы в таблицы стилей. Нулевое усилие, отличная поддержка (пожалуйста, напомните мне запатентовать эту ключевую фразу)
Чтобы включить Autoprefixer в наш рабочий процесс Gulp’y, нам нужно только передать его после того, как Sass сделает свое дело. Затем Autoprefixer обновляет таблицы стилей для добавления префиксов.
Во-первых, давайте установим его (вы уже поняли суть):
$ npm install gulp-autoprefixer --save-dev
Затем мы добавим это к нашей задаче:
var gulp = require('gulp'); var sass = require('gulp-sass'); var sourcemaps = require('gulp-sourcemaps'); var autoprefixer = require('gulp-autoprefixer'); // ... variables gulp.task('sass', function () { return gulp .src(input) .pipe(sourcemaps.init()) .pipe(sass(sassOptions).on('error', sass.logError)) .pipe(sourcemaps.write()) .pipe(autoprefixer()) .pipe(gulp.dest(output)); });
Прямо сейчас мы работаем с конфигурацией по умолчанию от Autoprefixer, которая
- Браузеры с долей рынка более 1%,
- Последние 2 версии всех браузеров,
- Firefox ESR,
- Опера 12.1
Мы можем использовать нашу собственную конфигурацию следующим образом:
var gulp = require('gulp'); var sass = require('gulp-sass'); var sourcemaps = require('gulp-sourcemaps'); var autoprefixer = require('gulp-autoprefixer'); // ... variables var autoprefixerOptions = { browsers: ['last 2 versions', '> 5%', 'Firefox ESR'] }; gulp.task('sass', function () { return gulp .src(input) .pipe(sourcemaps.init()) .pipe(sass(sassOptions).on('error', sass.logError)) .pipe(sourcemaps.write()) .pipe(autoprefixer(autoprefixerOptions)) .pipe(gulp.dest(output)); });
Отпустите документы!
Последний, но не менее важный инструмент для добавления в наш рабочий процесс — генерация документации Sass с помощью SassDoc . SassDoc для Sass, что JSDoc для JavaScript: инструмент документации. Он анализирует ваши таблицы стилей в поисках блоков комментариев, документирующих переменные, миксины, функции и заполнители.
Если ваш проект использует SassDoc (он должен!), Вы можете добавить автоматическую генерацию документации в ваш рабочий процесс Gulp.
Крутая вещь с SassDoc заключается в том, что он может передаваться напрямую в Gulp, потому что его API совместим с Gulp. Так что на самом деле у вас gulp-sassdoc
плагина gulp-sassdoc
.
npm install sassdoc --save-dev
var gulp = require('gulp'); var sass = require('gulp-sass'); var sourcemaps = require('gulp-sourcemaps'); var autoprefixer = require('gulp-autoprefixer'); var sassdoc = require('sassdoc'); // ... variables gulp.task('sass', function () { return gulp .src(input) .pipe(sourcemaps.init()) .pipe(sass(sassOptions).on('error', sass.logError)) .pipe(sourcemaps.write()) .pipe(autoprefixer(autoprefixerOptions)) .pipe(gulp.dest(output)) .pipe(sassdoc()) // Release the pressure back and trigger flowing mode (drain) // See: http://sassdoc.com/gulp/#drain-event .resume(); });
Обратите внимание, что в зависимости от размера вашего проекта и количества документированных элементов, запуск SassDoc может занять до нескольких секунд (насколько я заметил, редко выше 3), поэтому вам может потребоваться отдельная задача для это.
gulp.task('sassdoc', function () { return gulp .src(input) .pipe(sassdoc()) .resume(); });
Опять же, мы используем конфигурацию по умолчанию, но мы можем использовать нашу собственную, если захотим.
var sassdocOptions = { dest: './public/sassdoc' }; gulp.task('sassdoc', function () { return gulp .src(input) .pipe(sassdoc(sassdocOptions)) .resume(); });
я наблюдаю, слежу за тобой
Есть еще кое-что, что мы можем сделать перед уходом: создать задачу по watch
. Смысл этой задачи состоит в том, чтобы отслеживать изменения в таблицах стилей для их повторной компиляции. Это очень удобно при работе со стороной Sass проекта, поэтому вам не нужно запускать задачу sass
вручную при каждом сохранении файла.
gulp.task('watch', function() { return gulp // Watch the input folder for change, // and run `sass` task when something happens .watch(input, ['sass']) // When there is a change, // log a message in the console .on('change', function(event) { console.log('File ' + event.path + ' was ' + event.type + ', running tasks...'); }); });
Вот еще одна причина, по которой я рекомендую не включать SassDoc в задачу sass: вы, вероятно, не хотите восстанавливать документы каждый раз, когда вы касаетесь таблицы стилей. Скорее всего, это то, что вы хотите сделать при сборке или отправке, возможно, с помощью ловушки перед фиксацией.
Добавляем последний штрих
Последнее, но важное, о чем нужно подумать: запуск sass
в задаче по умолчанию.
gulp.task('default', ['sass', 'watch' /*, possible other tasks... */]);
Массив, переданный в качестве второго аргумента функции task(..)
является списком зависимых задач. По сути, он говорит Gulp запускать эти задачи перед выполнением задачи, указанной в качестве третьего аргумента (если есть).
Кроме того, мы могли бы, вероятно, создать задачу prod
которую можно было бы запустить прямо перед развертыванием в производство (возможно, с помощью git hook). Эта задача должна:
- Скомпилируйте Sass в сжатом режиме
- Префикс CSS с автоматическим исправлением
- Восстановить документацию SassDoc
- Избегайте любых исходных карт
gulp.task('prod', ['sassdoc'], function () { return gulp .src(input) .pipe(sass({ outputStyle: 'compressed' })) .pipe(autoprefixer(autoprefixerOptions)) .pipe(gulp.dest(output)); });
Последние мысли
Вот и все, ребята! Всего за пару минут и несколько строк JavaScript нам удалось создать мощный маленький рабочий процесс Gulp. Вы можете найти полный файл здесь . Что бы вы добавили к этому?