Начинаем работать с gulp.js
Привет, разработчик!
Для автоматизации рутинных, повторяющихся процессов мы используем gulp.js. В своем шаблоне мы используем следующие его возможности:
- компиляция scss в css, jade в html
- автоматическое проставление вендорных префиксов
- оптимизация изображений
- конкатинация скриптов
- сжатие скриптов и стилей
- создание иконочных шрифтов и svg-спрайтов
- проверка html на валидность
Это основные, есть еще несколько мелочей, об этом позже. Шаблон нашей команды вы найдете на гитхабе
Установка
Gulp - это npm-пакет для node.js, поэтому устанавливаем node.js (https://nodejs.org/en/). Устанавливаем как обычную программу.
Если у вас Windows, вам необходимо установить python 2 версии (https://www.python.org/downloads/release/python-2710/) и Microsoft Visual Studio (https://www.microsoft.com/en-gb/download/details.aspx?id=44914). Они необходимы для работы с некоторыми пакетами, чаще всего проблемы при установке возникают в связи их отсутствия.
После установки перейдите в папку с проектом и в консоли введите:
npm init
Последуют разные сообщения, на все можете отвечать утвержительно. Эта процедура инициализации необходима для установки пакетов. После её завершения введите в консоль:
npm install gulp
После выполнения этой команды вы увидите в вашем проекте папку node_modules. Это папка для хранения npm-пакетов. В данном случае вы установили пакет локально, т.е. все файлы gulp лежат в проеке. Как вы могли заметить это занимает некоторое время. Для того, чтобы не устанавливать каждый раз кучу модулей локально - устанавливайте пакеты глобально, а затем делайте ссылку на них в проекте. Как это сделать:
npm install gulp -g
npm link gulp
Мы установили gulp глобально, а затем сделали ссылку в проект. Все команды запускаются из папки проекта.
Далее установим остальные пакеты и слинкуем их:
npm install rimraf gulp-jade gulp-sass gulp-inline-image gulp-autoprefixer gulp-plumber gulp-directory-sync browser-sync gulp-concat -g
npm link rimraf gulp-jade gulp-sass gulp-inline-image gulp-autoprefixer gulp-plumber gulp-directory-sync browser-sync gulp-concat -g
npm install gulp-html5-lint gulp-purifycss gulp-uglify gulp-imagemin imagemin-pngquant gulp-csso -g
npm link gulp-html5-lint gulp-purifycss gulp-uglify gulp-imagemin imagemin-pngquant gulp-csso
Сначала я устанавливаю плагины для разработки, потом для сборки. Если у вас возникли проблемы с установкой какого-либо плагина - попробуйте установить его отдельно.
Пишем gulpfile
В корне вашего проекта создайте gulpfile.js. Без этого файла gulp работать не будет. В нем описываются все таски, перечисленные в начале статьи. Сначала необходимо прописать зависимости для проекта.
gulpfile.js
// plugins for development
var gulp = require('gulp'),
rimraf = require('rimraf'),
jade = require('gulp-jade'),
sass = require('gulp-sass'),
inlineimage = require('gulp-inline-image'),
prefix = require('gulp-autoprefixer'),
plumber = require('gulp-plumber'),
dirSync = require('gulp-directory-sync'),
browserSync = require('browser-sync').create(),
concat = require('gulp-concat');
// plugins for build
var purify = require('gulp-purifycss'),
uglify = require('gulp-uglify'),
imagemin = require('gulp-imagemin'),
pngquant = require('imagemin-pngquant'),
csso = require('gulp-csso');
//plugins for testing
var html5Lint = require('gulp-html5-lint');
Обычно в репозитории плагинов есть информация о том, как прописывать зависимость. Далее объявим переменные для папок проекта:
var assetsDir = 'assets/';
var outputDir = 'dist/';
var buildDir = 'build/';
Их будем использовать в тасках. Напишем первый таск - для компиляции jade
gulp.task('jade', function () {// Название таска
gulp.src([assetsDir + 'jade/*.jade', '!' + assetsDir + 'jade/_*.jade'])//берем файлы
.pipe(plumber())
.pipe(jade({pretty: true}))// компилим jade
.pipe(gulp.dest(outputDir))// куда положить html
.pipe(browserSync.stream());
});
Теперь, чтобы скомпилировать jade, достаточно ввести в консоль:
gulp jade
Аналогично sass
gulp.task('sass', function () {
gulp.src([assetsDir + 'sass/**/*.scss', '!' + assetsDir + 'sass/**/_*.scss'])//берем файлы
.pipe(plumber())
.pipe(sass())// компилим sass
.pipe(inlineimage())
.pipe(prefix('last 3 versions'))
.pipe(gulp.dest(outputDir + 'styles/'))// куда положить css
.pipe(browserSync.stream());
});
gulp sass
Постепенно вы привыкните к синтаксису. Обычно в репозитории gulp-модуля есть примеры тасков. Обратите внимание на строчку
.pipe(plumber())
При возникновении ошибок компиляции будет “вылетать” gulp, и нужно запускать заново. Но с плагином plumber этого не будет. Для того, чтобы перезапускать браузер после каждого прохождения таска используется команда:
.pipe(browserSync.stream());
Для конкатинации скриптов служит следующий таск:
gulp.task('jsConcat', function () {
return gulp.src(assetsDir + 'js/all/**/*.js')
.pipe(concat('all.js', {newLine: ';'}))
.pipe(gulp.dest(outputDir + 'js/'))
.pipe(browserSync.stream());
});
Он соединит все таски из папки js/all в один скрипт. Обычно это разные плагины.
Таски для синхронизации папок проекта между собой:
//-------------------------------------------------Synchronization
gulp.task('imageSync', function () {
return gulp.src('')
.pipe(plumber())
.pipe(dirSync(assetsDir + 'i/', outputDir + 'i/', {printSummary: true}))
.pipe(browserSync.stream());
});
gulp.task('fontsSync', function () {
return gulp.src('')
.pipe(plumber())
.pipe(dirSync(assetsDir + 'fonts/', outputDir + 'fonts/', {printSummary: true}))
.pipe(browserSync.stream());
});
gulp.task('jsSync', function () {
return gulp.src(assetsDir + 'js/*.js')
.pipe(plumber())
.pipe(gulp.dest(outputDir + 'js/'))
.pipe(browserSync.stream());
});
//-------------------------------------------------Synchronization###
Для того, чтобы отслеживать изменения в проекте и запускать таски автоматически используем gulp.watch
gulp.task('watch', function () {
gulp.watch(assetsDir + 'jade/**/*.jade', ['jade']);
gulp.watch(assetsDir + 'sass/**/*.scss', ['sass']);
gulp.watch(assetsDir + 'js/**/*.js', ['jsSync']);
gulp.watch(assetsDir + 'js/all/**/*.js', ['jsConcat']);
gulp.watch(assetsDir + 'i/**/*', ['imageSync']);
gulp.watch(assetsDir + 'fonts/**/*', ['fontsSync']);
});
Для обновления браузера и локального хоста используем browser-sync
gulp.task('browser-sync', function () {
browserSync.init({
port: 1337,
server: {
baseDir: outputDir
}
});
});
Теперь, чтобы запустить все это хозяйство напишем дефолтный таск gulp
gulp.task('default', ['jade', 'sass', 'imageSync', 'fontsSync', 'jsConcat', 'jsSync', 'watch', 'browser-sync']);
Здесь мы указываем какие таски необходимо запустить вместе. Благодаря таску watch, gulp не закончит работу, а будет ждать изменений.
Для того, чтобы запустить дефолтный таск введите
gulp
Откроется браузер и все будет компилироваться и обновляться автоматически.
Теперь напишем сборку проекта:
//---------------------------------building final project folder
//clean build folder
gulp.task('cleanBuildDir', function (cb) {
rimraf(buildDir, cb);
});
//minify images
gulp.task('imgBuild', function () {
return gulp.src(outputDir + 'i/**/*')
.pipe(imagemin({
progressive: true,
svgoPlugins: [{removeViewBox: false}],
use: [pngquant()]
}))
.pipe(gulp.dest(buildDir + 'i/'))
});
//copy fonts
gulp.task('fontsBuild', function () {
return gulp.src(outputDir + 'fonts/**/*')
.pipe(gulp.dest(buildDir + 'fonts/'))
});
//copy html
gulp.task('htmlBuild', function () {
return gulp.src(outputDir + '**/*.html')
.pipe(gulp.dest(buildDir))
});
//copy and minify js
gulp.task('jsBuild', function () {
return gulp.src(outputDir + 'js/**/*')
.pipe(uglify())
.pipe(gulp.dest(buildDir + 'js/'))
});
//copy, minify css
gulp.task('cssBuild', function () {
return gulp.src(outputDir + 'styles/**/*')
.pipe(purify([outputDir + 'js/**/*', outputDir + '**/*.html']))
.pipe(csso())
.pipe(gulp.dest(buildDir + 'styles/'))
});
gulp.task('build', ['cleanBuildDir'], function () {
gulp.start('imgBuild', 'fontsBuild', 'htmlBuild', 'jsBuild', 'cssBuild');
});
Запускаем
gulp build
И наконец таск для валидации:
gulp.task('validation', function () {
return gulp.src(buildDir + '**/*.html')
.pipe(html5Lint());
});
Итоговый gulpfile:
// plugins for development
var gulp = require('gulp'),
rimraf = require('rimraf'),
jade = require('gulp-jade'),
sass = require('gulp-sass'),
inlineimage = require('gulp-inline-image'),
prefix = require('gulp-autoprefixer'),
plumber = require('gulp-plumber'),
dirSync = require('gulp-directory-sync'),
browserSync = require('browser-sync').create(),
concat = require('gulp-concat');
// plugins for build
var purify = require('gulp-purifycss'),
uglify = require('gulp-uglify'),
imagemin = require('gulp-imagemin'),
pngquant = require('imagemin-pngquant'),
csso = require('gulp-csso');
//plugins for testing
var html5Lint = require('gulp-html5-lint');
var assetsDir = 'assets/';
var outputDir = 'dist/';
var buildDir = 'build/';
//----------------------------------------------------Compiling
gulp.task('jade', function () {
gulp.src([assetsDir + 'jade/*.jade', '!' + assetsDir + 'jade/_*.jade'])
.pipe(plumber())
.pipe(jade({pretty: true}))
.pipe(gulp.dest(outputDir))
.pipe(browserSync.stream());
});
gulp.task('sass', function () {
gulp.src([assetsDir + 'sass/**/*.scss', '!' + assetsDir + 'sass/**/_*.scss'])
.pipe(plumber())
.pipe(sass())
.pipe(inlineimage())
.pipe(prefix('last 3 versions'))
.pipe(gulp.dest(outputDir + 'styles/'))
.pipe(browserSync.stream());
});
gulp.task('jsConcat', function () {
return gulp.src(assetsDir + 'js/all/**/*.js')
.pipe(concat('all.js', {newLine: ';'}))
.pipe(gulp.dest(outputDir + 'js/'))
.pipe(browserSync.stream());
});
//----------------------------------------------------Compiling###
//-------------------------------------------------Synchronization
gulp.task('imageSync', function () {
return gulp.src('')
.pipe(plumber())
.pipe(dirSync(assetsDir + 'i/', outputDir + 'i/', {printSummary: true}))
.pipe(browserSync.stream());
});
gulp.task('fontsSync', function () {
return gulp.src('')
.pipe(plumber())
.pipe(dirSync(assetsDir + 'fonts/', outputDir + 'fonts/', {printSummary: true}))
.pipe(browserSync.stream());
});
gulp.task('jsSync', function () {
return gulp.src(assetsDir + 'js/*.js')
.pipe(plumber())
.pipe(gulp.dest(outputDir + 'js/'))
.pipe(browserSync.stream());
});
//-------------------------------------------------Synchronization###
//watching files and run tasks
gulp.task('watch', function () {
gulp.watch(assetsDir + 'jade/**/*.jade', ['jade']);
gulp.watch(assetsDir + 'sass/**/*.scss', ['sass']);
gulp.watch(assetsDir + 'js/**/*.js', ['jsSync']);
gulp.watch(assetsDir + 'js/all/**/*.js', ['jsConcat']);
gulp.watch(assetsDir + 'i/**/*', ['imageSync']);
gulp.watch(assetsDir + 'fonts/**/*', ['fontsSync']);
});
//livereload and open project in browser
gulp.task('browser-sync', function () {
browserSync.init({
port: 1337,
server: {
baseDir: outputDir
}
});
});
//---------------------------------building final project folder
//clean build folder
gulp.task('cleanBuildDir', function (cb) {
rimraf(buildDir, cb);
});
//minify images
gulp.task('imgBuild', function () {
return gulp.src(outputDir + 'i/**/*')
.pipe(imagemin({
progressive: true,
svgoPlugins: [{removeViewBox: false}],
use: [pngquant()]
}))
.pipe(gulp.dest(buildDir + 'i/'))
});
//copy fonts
gulp.task('fontsBuild', function () {
return gulp.src(outputDir + 'fonts/**/*')
.pipe(gulp.dest(buildDir + 'fonts/'))
});
//copy html
gulp.task('htmlBuild', function () {
return gulp.src(outputDir + '**/*.html')
.pipe(gulp.dest(buildDir))
});
//copy and minify js
gulp.task('jsBuild', function () {
return gulp.src(outputDir + 'js/**/*')
.pipe(uglify())
.pipe(gulp.dest(buildDir + 'js/'))
});
//copy, minify css
gulp.task('cssBuild', function () {
return gulp.src(outputDir + 'styles/**/*')
.pipe(purify([outputDir + 'js/**/*', outputDir + '**/*.html']))
.pipe(csso())
.pipe(gulp.dest(buildDir + 'styles/'))
});
//testing your build files
gulp.task('validation', function () {
return gulp.src(buildDir + '**/*.html')
.pipe(html5Lint());
});
gulp.task('default', ['jade', 'sass', 'imageSync', 'fontsSync', 'jsConcat', 'jsSync', 'watch', 'browser-sync']);
gulp.task('build', ['cleanBuildDir'], function () {
gulp.start('imgBuild', 'fontsBuild', 'htmlBuild', 'jsBuild', 'cssBuild');
});
На этом все.