Привет, разработчик!
Для автоматизации рутинных, повторяющихся процессов мы используем 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' );
});
На этом все.