Приятная сборка frontend проекта15.02.2015. Приятная сборка frontend проекта Установка плагинов через пакетный менеджер npm

Приветствую. Если вы занимаетесь frontend разработкой, то могли заметить, что часто приходится выполнять одни и те же задачи. Было бы здорово все это автоматизировать и свести объем рутины к минимуму. В этом вам могут помочь таск-менеджеры и сборщики проектов, такие как Gulp и Grunt.

Gulp – это ответвление от проекта Grunt. От своего родителя он взял лучшие практики. Код инструкций пишется на JavaScript. Работает быстрее, чем Grunt в несколько раз.

Gulp предоставляет по-настоящему широкие возможности. Он облегчит и ускорит frontend разработку. Перечислю основные задачи, которые сборщик проектов вам поможет решить.

  • Создание веб-сервера для отладки
  • Автоматическая перезагрузка страниц при внесении изменений (LiveReload)
  • Слежение за изменениями в файлах проекта
  • Использование препроцессоров HTML, CSS, JS
  • Объединение файлов и их минификация
  • Автоматическое создание вендорных префиксов для браузеров (Autoprefixer)
  • Автоматизация управления файлами и директориями
  • Запуск и контроль внешних команд операционной системы
  • Запуск и контроль приложений
  • Оптимизация изображений (сжатие, изменение размеров и т.д.)
  • Выгрузка проекта на внешний сервер с помощью FTP, SFTP, Git и т.д.
  • Подключение и использование дополнительных плагинов (сегодня их уже 3570 штук; решение можно
  • найти практически для всех повседневных рутинных задач и не только)
  • Автоматизация ручного труда

Установка

Для работы Gulp требуется Node.js. Скачать его можно на официальном сайте . Советую ставить LTS версию программной платформы. После инсталляции Node.js можно переходить к установке Gulp. Для этого откройте консоль операционной системы и выполните следующую команду:

Мы используем параметр -g , который позволяет установить Gulp глобально в операционной системе, без привязки к конкретному проекту.

Важно, чтобы в пути к директории установки не было русских символов. Из-за этого некоторые плагины gulp могут работать некорректно.

Окей, пришло время создать проект, в котором мы будем использовать Gulp. Перейдите в директорию проекта и выполните команду:

Это запустит скрипт, который задаст вам несколько вопросов о проекте. В результате будет сконфигурирован файл для npm package.json . Это манифест проекта. Он содержит список пакетов, которые используются в проекте и другую информацию. На этом этапе я внес следующие данные, адаптируйте под свой проект.

name: (bybtc-landing) version: (1.0.0) description: Landing Page for byBTC entry point: (index.js) test command: git repository: https://github.com/Neuropassenger/bybtc-landing.git keywords: landing

Если какой-то вопрос хотите пропустить, то просто нажимайте Enter. Будет использовано значение по умолчанию. Теперь можно установить Gulp для нашего проекта. Выполните команду:

npm i --save-dev gulp

Gulp будет установлен в директорию проекта, а параметр –save-dev добавит его в зависимости package.json. Это позволит другому разработчику, открывшему ваш проект, быстро развернуть его на своей машине (с помощью команды npm i ).

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

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

Создаем две папки в корне проекта:

  • /src/ – исходный код проекта во время разработки, здесь вы будете редактировать файлы
  • /dist/ – файлы и папки проекта после сборки, готовый продукт

Каталог /dist/ будет заполняться автоматически при сборке проекта. Займемся пока что /src/ . Создайте внутри следующие папки:

  • /css/ – для каскадных таблиц стилей
  • /js/ – для JavaScript-сценариев
  • /img/ – для изображений
  • /fonts/ – для шрифтов
  • /sass/ – для файлов препроцессора SASS (если используете SASS)
  • /libs/ – для сторонних библиотек

Если все готово, то пора перейти к созданию файла gulpfile.js в корне проекта, который поможет настроить Gulp. Именно здесь вы можете создать инструкции Gulp, которые помогут автоматизировать часть рутинных задач.

Инструкции Gulp

Любая инструкция создается в gulpfile.js с помощью функции gulp.task() . Первый параметр – это название инструкции. Затем идет массив из названий инструкций, которые нужно выполнить до запуска определяемой инструкции. Последний параметр – это функция, тело которой определяет то, что делает данная инструкция.

gulp.task("название_инструкции", ["инструкция_выполняющаяся_перед_текущей", "еще_одна_инструкция"], function() { // Какие-то действия });

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

gulp название_команды

Компиляция SASS в CSS

Начнем с компиляции SASS в CSS. Установим пакет gulp-sass:

npm i --save-dev gulp-sass

Сначала необходимо подключить используемые пакеты в gulpfile.js . Сделаем это:

var gulp = require("gulp"), sass = require("gulp-sass");

Теперь создадим инструкцию, которая будет выполнять компиляцию SASS в CSS:

gulp.task("sass", function() { return gulp.src("src/sass/**/*.sass") .pipe(sass()) .pipe(gulp.dest("src/css")); });

В первой строке инструкции указываем исходные файлы для компиляции. В конкретном примере будут взяты все файлы с расширением .sass , находящиеся внутри папки /src/sass/ и ее подпапках. Можно выбирать и конкретные файлы. Вот примерный список того, как вы можете задавать пути к исходным файлам.

  • src/sass/main.sass – выбор файла main.sass
  • src/sass/*.sass – выбор всех файлов с расширением sass
  • src/sass/**/*.sass – выбор всех файлов с расширением sass во всех вложенных папках в папке sass
  • !src/sass/main.sass – исключение файла main.sass
  • [‘!src/sass/main.sass’, ‘src/sass/second.sass’] – исключение массива файлов main.sass и second.sass
  • src/sass/**/*.+(scss|sass) – выбрать все файлы scss и sass во всех вложенных папках в sass

Теперь создаем в папке /src/sass/ файл main.sass и определим в нем немного стилей:

body color: red font-size: 20px

Сохраняем файл. Теперь мы можем проверить, как работает компиляция. В консоли выполняем команду:

Проверяем каталог /src/css/ . В нем должен находится только что скомпилированный CSS файл. Видите? Отлично! Двигаемся дальше.

Автообновление страниц (LiveReload)

Перейдем к автоматизации обновления страниц при их изменении, т.е. настроим LiveReload . Это одна из самых популярных задач, стоящих перед . Нам понадобится пакет npm Browsersync для автоматического обновления браузера. Установим его:

npm i --save-dev browser-sync

Подключим browser-sync пакет в начале gulpfile.js , как мы это делали ранее с пакетами gulp и gulp-sass :

browserSync = require("browser-sync");

Создадим инструкцию для запуска Browsersync:

gulp.task("browser-sync", function() { browserSync({ server: { baseDir: "src" } }); });

Все, что мы сделали – это вызвали запуск Browsersync и указали директорию проекта с исходными файлами. Есть и другие настройки для Browsersync . Можете узнать о них в документации.

Добавим еще один pipe к инструкции sass , с помощью которого будет происходить обновление стилей при компиляции CSS файлов. Указываем параметр stream: true . Это позволит обновлять стили потоково , без полной перезагрузки страницы.

Pipe(browserSync.reload({ stream: true; }))

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

gulp.task("watch", ["browser-sync"], function() { gulp.watch("src/sass/**/*.sass", ["sass"]); gulp.watch("src/js/**/*.js", browserSync.reload); gulp.watch("src/**/*.html", browserSync.reload); });

Поясню. Перед запуском выполняется инструкция browser-sync , т.е. стартует веб-сервер для отладки проекта. После этого выполняется сама инструкция watch . Для слежения за изменениями в файлах используем gulp.watch() .

Внутри анонимной функции мы выполняем 3 раза gulp.watch с двумя параметрами. Первый параметр – файлы, за которыми нужно следить, второй – действия, которые нужно выполнить при изменении файлов, т.е. выполнить инструкцию sass или обновить страницу.

Обратите внимание на первый gulp.watch . Вместо browserSync.reload мы передаем в массиве инструкцию sass , которую нужно выполнить, если файлы были изменены. В ней, как вы помните, мы потоково обновляем стили на странице.

Минификация и объединение файлов

Почти в любом проекте приходится использовать сторонние библиотеки. Их количество может составлять от 5 и до бесконечности. Соответственно, все они должны быть включены в готовый продукт. Все это дело было бы неплохо оптимизировать, а именно:

  • минифицировать (сжать) используемые библиотеки
  • уменьшить количество запросов к серверу, объединив библиотеки в единый файл

Добавим в исходные файлы проекта несколько библиотек. Для этого я использую Bower , пакет для NPM . Установим Bower:

Создаем файл конфигурации .bowerrc в корне проекта для Bower, где укажем ему, куда сохранять библиотеки:

{ "directory": "src/libs/" }

Установим, для примера, библиотеку jQuery и слайдер slick :

bower i jquery slick-carousel

Теперь можем заняться конкатенацией и сжатием библиотек. Для этого будем использовать пакеты gulp-concat и gulp-uglifyjs касательно JavaScript-файлов. Установим их:

npm i --save-dev gulp-concat gulp-uglifyjs

Касательно CSS – пакет gulp-cssnano . Устанавливаем:

npm i --save-dev gulp-cssnano

Минифицированные файлы обычно имеют суффикс .min . Добавить его нам поможет пакет gulp-rename . Устанавливаем:

npm i --save-dev gulp-rename

Начнем с подключения установленных плагинов в gulpfile.js :

concat = require("gulp-concat"), uglifyJs = require("gulp-uglifyjs"), cssNano = require("gulp-cssnano"), rename = require("gulp-rename");

JavaScript

Создадим инструкцию, которая позволит нам сжимать и объединять JavaScript-файлы:

gulp.task("min-js", function() { return gulp.src([ "src/libs/jquery/dist/jquery.min.js", "src/libs/slick-carousel/dist/slick.min.js" ]) .pipe(concat("libs.min.js")) .pipe(uglifyJs()) .pipe(gulp.dest("src/js")); });

Внутри анонимной функции инструкции min-js мы сначала указываем пути на JavaScript-файлы библиотек в виде массива. Затем с помощью concat объединяем библиотеки в единый файл libs.min.js uglifyJs . И, наконец, сохраняем результат в папку /src/js/ .

Инструкцию можно проверить с помощью команды в консоли:

В папке /src/js/ появится файл libs.min.js , в котором объединены и сжаты используемые в проекте JavaScript-файлы библиотек.

CSS

Создадим в каталоге /src/css/ файл libs.sass . Будем в него импортировать CSS-файлы библиотек. Для примера с помощью Bower я скачал библиотеку Bootstrap :

bower i bootstrap

Откроем файл libs.sass и импортируем в него CSS-файл Bootstrap:

@import "src/libs/bootstrap/dist/css/bootstrap"

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

gulp.task("min-css", ["sass"] , function() { return gulp.src("src/css/libs.css") .pipe(cssNano()) .pipe(rename({ suffix: ".min" })) .pipe(gulp.dest("src/css")); });

Перед сжатием мы компилируем CSS из SASS с помощью инструкции sass , которую мы указали в массиве после имени инструкции min-css .

В первой строке мы берем конкретный файл, libs.css . Далее сжимаем его с помощью cssNano . Затем с помощью rename добавляем суффикс .min . Результат сохраняем в папке /src/css/ .

Проверяем инструкцию:

Если вы все сделали правильно, то в папке /src/css/ должно появиться два файла. libs.css и libs.min.css . Сравните их размеры.

Автоматическое добавление вендорных префиксов (Autoprefixer)

При использовании свежих возможностей CSS необходимо расставлять вендорные префиксы для правильной работы стилей. Делать такие вещи вручную – неблагодарное занятие. Поэтому заставим Gulp это сделать за нас.

Для начала установим gulp-autoprefixer :

npm i --save-dev gulp-autoprefixer

Подключим установленный пакет в gulpfile.js :

autoprefixer = require("gulp-autoprefixer");

Окей, теперь мы можем использовать autoprefixer в инструкции sass . Сделаем это после вызова .pipe(sass()) , т.к. вендорные префиксы нужно расставить после того, как SASS будет преобразован в CSS. Добавим новый pipe :

Pipe(autoprefixer([ "last 10 versions" ], { cascade: true }))

Первым параметром autoprefixer мы передаем массив, в котором указываем, что хотим включить поддержку последних 10 версий браузеров. Второй параметр – это настройки, где мы указываем, что хотим видеть красивый код на выходе, т.е. включаем каскадность.

Проверяем, добавляя в main.sass новое свойство flex . Запускаем инструкцию sass :

В main.css должны появиться вендорные префиксы. Очень просто, все работает в автоматическом режиме. Замечательно!

Финальная сборка проекта

Последнее, чего хотелось бы коснуться в этом гайде для новичков по Gulp – это финальная сборка проекта. Для этого нам понадобится папка /dist/ , которую мы создали в самом начале. Перед каждой сборкой ее необходимо очищать. Для этого будем использовать пакет NPM del . Установим его:

npm i --save-dev del

Подключим пакет del в gulpfile.js :

del = require("del");

Создадим инструкцию clean для очистки каталога / dist/ перед сборкой:

gulp.task("clean", function() { return del.sync("dist"); });

Теперь можно заняться непосредственно сборкой проекта. Создадим инструкцию build :

gulp.task("build", ["clean", "min-css", "min-js"], function() { var buildCss = gulp.src([ "src/css/libs.min.css", "src/css/main.css" ]) .pipe(gulp.dest("dist/css")); var buildFonts = gulp.src("src/fonts/**/*") .pipe(gulp.dest("dist/fonts")); var buildJs = gulp.src("src/js/**/*") .pipe(gulp.dest("dist/js")); var buildHtml = gulp.src("src/*.html") .pipe(gulp.dest("dist")); });

Перед вызовом инструкции build мы очищаем папку /dist/ на тот случай, если сборка уже проводилась до этого. Затем сжимаем и объединяем JavaScript и CSS файлы с помощью инструкций min-js и min-css соответственно . Попутно компилируем SASS в CSS, т.к. перед выполнением инструкции min-css выполняется инструкция sass .

Внутри тела инструкции мы копируем подготовленные файлы проекта в каталог с готовым продуктом /dist/ . Проверяем работу инструкции:

Все отлично работает! В папке /dist/ теперь находится готовый продукт после сборки, который можно выгружать на рабочий сервер.

Заключение

На этом закончу гайд для новичков по сборке проектов в Gulp. Как видите, все довольно просто. Со временем опубликую еще несколько постов, касающихся Gulp и его плагинов, как только сам хорошенько в них разберусь. А пока пользуйтесь и автоматизируйте свои рутинные задачи во frontend разработке согласно приведенной инструкции. Если появятся вопросы – задавайте в комментариях к посту.

{ "name": "bybtc-landing", "version": "1.0.0", "description": "Landing Page for byBTC", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "repository": { "type": "git", "url": "git+https://github.com/Neuropassenger/bybtc-landing.git" }, "keywords": [ "landing" ], "author": "Oleg Sokolov", "license": "ISC", "bugs": { "url": "https://github.com/Neuropassenger/bybtc-landing/issues" }, "homepage": "https://github.com/Neuropassenger/bybtc-landing#readme", "devDependencies": { "browser-sync": "^2.18.13", "del": "^3.0.0", "gulp": "^3.9.1", "gulp-autoprefixer": "^4.0.0", "gulp-concat": "^2.6.1", "gulp-cssnano": "^2.1.2", "gulp-rename": "^1.2.2", "gulp-sass": "^3.1.0", "gulp-uglifyjs": "^0.6.2" } }

var gulp = require("gulp"), sass = require("gulp-sass"), browserSync = require("browser-sync"), concat = require("gulp-concat"), uglifyJs = require("gulp-uglifyjs"), cssNano = require("gulp-cssnano"), rename = require("gulp-rename"), autoprefixer = require("gulp-autoprefixer"), del = require("del"); gulp.task("sass", function() { return gulp.src("src/sass/**/*.sass") .pipe(sass()) .pipe(autoprefixer([ "last 10 versions" ], { cascade: true })) .pipe(gulp.dest("src/css")) .pipe(browserSync.reload({ stream: true })); }); gulp.task("min-css", ["sass"] , function() { return gulp.src("src/css/libs.css") .pipe(cssNano()) .pipe(rename({ suffix: ".min" })) .pipe(gulp.dest("src/css")); }); gulp.task("min-js", function() { return gulp.src([ "src/libs/jquery/dist/jquery.min.js", "src/libs/slick-carousel/dist/slick.min.js" ]) .pipe(concat("libs.min.js")) .pipe(uglifyJs()) .pipe(gulp.dest("src/js")); }); gulp.task("browser-sync", function() { browserSync({ server: { baseDir: "src" } }); }); gulp.task("watch", ["browser-sync"], function() { gulp.watch("src/sass/**/*.sass", ["sass"]); gulp.watch("src/js/**/*.js", browserSync.reload); gulp.watch("src/**/*.html", browserSync.reload); }); gulp.task("clean", function() { return del.sync("dist"); }); gulp.task("build", ["clean", "min-css", "min-js"], function() { var buildCss = gulp.src([ "src/css/libs.min.css", "src/css/main.css" ]) .pipe(gulp.dest("dist/css")); var buildFonts = gulp.src("src/fonts/**/*") .pipe(gulp.dest("dist/fonts")); var buildJs = gulp.src("src/js/**/*") .pipe(gulp.dest("dist/js")); var buildHtml = gulp.src("src/*.html") .pipe(gulp.dest("dist")); });

Сжатие изображение, JS и CSS файлов, в целях оптимизации загрузки веб-страниц и многоe многое другое. Чтобы упросить этот процесс, мы предлагаем вам воспользоваться сборкой проектов Gulp 4, которую постоянно совершенствует Андрей Горохов. Ниже будут представлены ссылки на скачивание, а пока пройдемся по основным моментам: описанию и установке.

Сборщик проектов Gulp

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

Скачать сборку можно с репозитория Github или через командную строку Git . В дальнейшем вы сможете настроить её под свои задачи.

Особенности

  • именование классов по БЭМ
  • используется БЭМ-структура
  • используется препроцессор SCSS
  • используется транспайлер Babel для поддержки современного JavaScript (ES6) в браузерах
  • используется Webpack для сборки JavaScript-модулей
  • используется CSS-сетка smart-grid на основе Bootstrap для быстрой адаптивной вёрстки
  • используется жёсткий кодгайд

Установка

  • установите NodeJS (если требуется) и Yarn
  • скачайте сборку с помощью Git : git clone https://github.com/andreyalexeich/gulp-scss-starter.git
  • установите gulp глобально: yarn global add gulp-cli
  • перейдите в скачанную папку со сборкой: cd gulp-scss-starter
  • скачайте необходимые зависимости: yarn
  • чтобы начать работу, введите команду: yarn run dev (режим разработки)
  • чтобы собрать проект, введите команду yarn run build (режим сборки)

Если вы всё сделали правильно, у вас должен открыться браузер с локальным сервером. Режим сборки предполагает оптимизацию проекта: сжатие изображений, минифицирование CSS и JS-файлов для загрузки на сервер.

Если у тебя возникли проблемы с установкой, то посмотри этот ролик:

Файловая структура

gulp-scss-starter ├── dist ├── gulp-tasks ├── src │ ├── blocks │ ├── fonts │ ├── img │ ├── js │ ├── styles │ ├── views │ └── .htaccess ├── gulpfile.babel.js ├── webpack.config.js ├── package.json ├── .babelrc.js ├── .bemrc.js ├── .eslintrc.json ├── .stylelintrc ├── .stylelintignore └── .gitignore
  • Корень папки:
    • .babelrc.js - настройки Babel
    • .bemrc.js - настройки БЭМ
    • .eslintrc.json - настройки ESLint
    • .gitignore – запрет на отслеживание файлов Git’ом
    • .stylelintrc - настройки Stylelint
    • .stylelintignore – запрет на отслеживание файлов Stylelint’ом
    • gulpfile.babel.js - настройки Gulp
    • webpack.config.js - настройки Webpack
    • package.json - список зависимостей
  • Папка src — используется во время разработки:
    • БЭМ-блоки: src/blocks
    • шрифты: src/fonts
    • изображения: src/img
    • JS-файлы: src/js
    • страницы сайта: src/views/pages
    • SCSS-файлы: src/styles
    • HTML-файлы: src/views
    • конфигурационный файл веб-сервера Apache с настройками gzip (сжатие без потерь): src/.htaccess
  • Папка dist — папка, из которой запускается локальный сервер для разработки (при запуске yarn run dev)
  • Папка gulp-tasks — папка с Gulp-тасками

Команды

  • yarn run lint:style — проверить SCSS-файлы. Для VSCode необходимо установить плагин . Для WebStorm или PHPStorm необходимо включить Stylelint в Languages & Frameworks - Style Sheets - Stylelint (ошибки будут исправлены автоматически при сохранении файла)
  • yarn run lint:style --fix — исправить ошибки в SCSS-файлах
  • yarn run dev — запуск сервера для разработки проекта
  • yarn run build — собрать проект с оптимизацией без запуска сервера
  • yarn run build views — скомпилировать Pug-файлы
  • yarn run build styles — скомпилировать SCSS-файлы
  • yarn run build scripts — собрать JS-файлы
  • yarn run build images — собрать изображения
  • yarn run build webp — сконвертировать изображения в формат.webp
  • yarn run build sprites — собрать спрайты
  • yarn run build fonts — собрать шрифты
  • yarn run build favicons — собрать фавиконки
  • yarn run build gzip — собрать конфигурацию Apache

Компонентный подход к разработке сайтов

  • аждый БЭМ-блок имеет свою папку внутри src/blocks/modules
  • папка одного БЭМ-блока содержит в себе один HTML-файл, один SCSS-файл и один JS-файл (если у блока используется скрипт)
    • HTML-файл блока импортируется в файл src/views/index.html (или в необходимый файл страницы, откуда будет вызываться блок)
    • SCSS-файл блока импортируется в файл src/blocks/modules/_modules.scss
    • JS-файл блока импортируется в src/js/import/modules.js

Пример структуры папки с БЭМ-блоком:

Blocks ├── modules │ ├──header │ │ ├── header.html │ │ ├── header.js │ │ ├── header.scss

Чтобы вручную не создавать соответствующие папку и файлы, достаточно в консоли прописать команду bem create my-block — для создания папки БЭМ-блока, где my-block — имя БЭМ-блока

Страницы проекта

  • страницы проекта находятся в папке src/views/pages
    • главная страница: src/views/index.html

Шрифты

  • шрифты находятся в папке src/fonts
    • используйте форматы .woff и.woff2
    • шрифты подключаются в файл src/styles/base/_fonts.scss
    • сконвертировать локальные шрифты можно с помощью данного сервиса

Изображения

  • изображения находятся в папке src/img
    • изображение для генерации фавиконок должно находиться в папке src/img/favicon и иметь размер не менее 1024px x 1024px
    • изображения автоматически конвертируются в формат.webp . Подробная информация по использованию .

Сторонние библиотеки

  • все сторонние библиотеки устанавливаются в папку node_modules
    • для их загрузки воспользуйтеcь командой yarn add package_name
    • для подключения JS-файлов библиотек импортируйте их в самом начале JS-файла БЭМ-блока (то есть тот БЭМ-блок, который использует скрипт), например:

    Import $ from " jquery" ;

    • для подключения стилевых файлов библиотек импортируйте их в файл src/styles/vendor/_libs.scss
    • JS-файлы и стилевые файлы библиотек самостоятельно изменять нельзя

⚠️ Если в вашем проекте используется несколько библиотек, которые необходимо подключать на нескольких страницах, во избежании ошибок нужно:

  • по пути src/js/import создать папку pages
  • в папке pages создать js-файл для страницы, например, pageA.js , и импортировать туда библиотеку, которая будет использоваться только на этой странице
    • аналогично проделать шаг для дополнительных страниц
  • в файле webpack.config.js в точку входа добавить js-файлы страниц, пример:

Entry: { main: " ./src/js/index.js" , pageA: " ./src/js/import/pages/pageA.js" , pageB: " ./src/js/import/pages/pageB.js" }

  • подключить скомпилированные js-файлы на необходимых страницах

CSS-сетка smart-grid

В сборщик включена CSS-сетка smart-grid от Дмитрия Лаврика . Она позволяет избавиться от лишних классов в разметке за счёт использования примесей в SCSS и ускоряет адаптивную вёрстку. Конфигурация уже настроена в соответствии с сеткой Bootstrap . Пример использования:

Items { @include row-flex (); @include md (justify-content , center ); .item { @include col (); @include size (3 ); @include size-md (5 ); @include size-xs (10 ); } }

Хотите набрать побольше баллов в Google Page Speed? Не знаете что такое «сборка front-end»? Тогда вам сюда, будет интересно.

Что такое Node.JS?

Node.JS принято называть «северным JavaScript». Эта платформа позволяет писать программы, используя синтаксис JavaScript.

Есть реализации для Windows, Mac OS и Linux.

В комплект входит менеджер пакетов NPM , с помощью которого можно устанавливать пакеты.

Что такое Gulp?

Gulp — это пакет, написанный на Node.JS, который помогает веб-мастерам осуществлять сборку проектов на этапе верстки макетов.

Для установки Gulp необходимо воспользоваться командной строкой.

Npm install gulp

В конце данной статьи находится файл, который поможет собрать типовой проект.

В этом примере с помощью Gulp мы сделаем следующее:

  • Автоматически оптимизируем изображения для веба;
  • Собираем один минифицированный файл стилей из предпроцессоров (SASS, SCSS);
  • Собираем один минифицированный файл со скриптами.

Как собирать front-end с помощью Gulp?

Чтобы понять, как все работает, разберем все по шагам.

Структуру можно посмотреть на скриншоте.

  • Папка assets — для исходников изображений, стилей и скриптов;
  • Папка public — результат сборки проекта будет находится именно в ней;
  • gulpfile.js — файл, в котором описана логика работы сборщика;
  • package.json — файл, в котором содержатся информация о программах и плагинах, использующихся для корректной работы Gulp.

package.json

Содержимое файла:

{ "name": "gulp_project", "version": "1.0.0", "description": "Example", "main": "gulpfile.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "author": "Dmitriy Ilichev", "license": "ISC", "devDependencies": { "gulp": "^3.9.0", "gulp-csso": "^1.0.0", "gulp-concat": "^2.6.0", "gulp-uglify": "^1.2.0", "gulp-imagemin": "^2.3.0", "gulp-sass": "^2.1.1" } }

Из этого файла понятно следующее:

  • Название проекта gulp_project , версия и описание;
  • Главный файлом является gulpfile.js ;
  • Автор проекта, лицензия — все это не столь важно и попросту эти поля могут быть пустыми;
  • Интересным пунктом является devDependencies . В нем описаны зависимости.

Файл можно отредактировать в обычном текстовом редакторе. Его также можно создать для нового проекта командой npm int .

Исходя из этого, Node.JS понимает, что для работы нам понадобятся:

  • Gulp версии 3.9.0 и выше для сборки;
  • Gulp-csso версии 1.0.0 и выше — плагин для минификации стилей (css);
  • Gulp-concat версии 2.6.0 и выше — плагин для склейки нескольких файлов в один;
  • Gulp-uglify версии 1.2.0 и выше — плагин для минификации javascript;
  • Gulp-imagemin версии 2.3.0 и выше — плагин для оптимизации изображений;
  • Gulp-sass версии 2.1.1 и выше — плагин для получения css из sass (scss).

Отлично! После этого нужно все это установить. Делается это из командной строки. Находясь в папке с проектом нужно выполнить команду:

Npm install

Вся необходимая информация будет взята из package.json .

После всего этого волшебства появится служебная папка node_modules .

gulpfile.js

Содержимое файла:

/* * * Определяем переменные * */ var gulp = require("gulp"), // Сообственно Gulp JS uglify = require("gulp-uglify"), // Минификация JS concat = require("gulp-concat"), // Склейка файлов imagemin = require("gulp-imagemin"), // Минификация изображений csso = require("gulp-csso"), // Минификация CSS sass = require("gulp-sass"); // Конверстация SASS (SCSS) в CSS /* * * Создаем задачи (таски) * */ // Задача "sass". Запускается командой "gulp sass" gulp.task("sass", function () { gulp.src("./assets/styles/style.scss") // файл, который обрабатываем.pipe(sass().on("error", sass.logError)) // конвертируем sass в css .pipe(csso()) // минифицируем css, полученный на предыдущем шаге.pipe(gulp.dest("./public/css/")); // результат пишем по указанному адресу }); // Задача "js". Запускается командой "gulp js" gulp.task("js", function() { gulp.src([ "./assets/javascripts/jquery-2.1.4.min.js", "./assets/javascripts/bootstrap.min.js", "./assets/javascripts/script.js" ]) // файлы, которые обрабатываем.pipe(concat("min.js")) // склеиваем все JS .pipe(uglify()) // получившуюся "портянку" минифицируем.pipe(gulp.dest("./public/js/")) // результат пишем по указанному адресу }); // Задача "images". Запускается командой "gulp images" gulp.task("images", function() { gulp.src(".assets/images/**/*") // берем любые файлы в папке и ее подпапках.pipe(imagemin()) // оптимизируем изображения для веба.pipe(gulp.dest("./public/images/")) // результат пишем по указанному адресу }); // Задача "watch". Запускается командой "gulp watch" // Она следит за изменениями файлов и автоматически запускает другие задачи gulp.task("watch", function () { // При изменение файлов *.scss в папке "styles" и подпапках запускаем задачу sass gulp.watch("./assets/styles/**/*.scss", ["sass"]); // При изменение файлов *.js папке "javascripts" и подпапках запускаем задачу js gulp.watch("./assets/javascripts/**/*.js", ["js"]); // При изменение любых файлов в папке "images" и подпапках запускаем задачу images gulp.watch("./assets/images/**/*", ["images"]); });

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

На выходе получим готовый к публикации в интернете шаблон.

Задачи можно запускать отдельно. В итоге, в архиве в конце статьи вас ждет следующее:

! Обратите внимание на то, что распаковав у себя этот архив, прежде всего необходимо будет выполнить команду npm install . Папка эта содержит довольно большое количество файлов, и каждый раз копировать/вставлять их — пустая трата времени.

В заключении

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

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

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

Разумеется, как только необходимость в сборке стала ощутима, тут же на фронтенд начали переползать инструменты, использовавшиеся бэкендом. Основная их проблема и причина того, что в данный момент их все меньше используют для фронтенда, - они совершенно не заточены под его специфику, так как структура проекта, используемые технологии и цикл разработки очень сильно зависят от задач проекта и могут значительно отличаться. Тот же Ant, например, обладает многословным синтаксисом и не особо умеет делать нужные для фронтенда вещи: встроенных задач совсем немного, а расширяется он плохо. Если говорить о GNU make, то он гораздо более универсальный, поскольку оперирует shell-командами. Из недостатков нужно упомянуть об особом синтаксисе, который надо дополнительно изучать, необходимости хорошо знать shell, а также тенденции к быстрому усложнению Makefile при росте требований к сборке.

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

/libs/ jquery.min.js underscore.min.js /js/ common.js carousel.js popups.js ....

Система сборки обычно делает следующее:

  • конкатенирует все JS-файлы в один (в нужном порядке, мы же не хотим загрузить наши скрипты раньше, чем jQuery);
  • проверяет JS-код на валидность (например, с помощью JSHint);
  • минимизирует код, по необходимости его обфусцирует (то есть делает непонятным);
  • конкатенирует CSS-файлы (порядок тут тоже важен, так как свойства часто переопределяются);
  • минимизирует CSS;
  • складывает файлики в отдельную директорию, из которой ты и подключаешь их в своем HTML.

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

Все эти задачи, и даже больше, умеют решать современные инструменты сборки. Будем рассматривать самые популярные решения, которые работают на платформе Node.js. Общим их преимуществом является понятный язык, который знают (или считают, что знают) все фронтенд-разработчики, изначальная направленность на решение задач фронтенда, а также понятное Node.js окружение, в котором ты, может быть, уже разрабатываешь свое приложение.

Grunt

Grunt - самый старый, самый главный и самый популярный инструмент для сборки. Почти все рассматриваемые нами системы сборки так или иначе сравнивают себя с Grunt, а некоторые и возникли как более быстрые или более простые его альтернативы. Несмотря на это, у него есть пара существенных недостатков.

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

Во-вторых, Grunt разрабатывался как универсальный продукт, то есть на его основе можно решить практически любую задачу, связанную со сборкой проекта. Это круто, но за универсальность приходится платить. Как упоминавшейся многословностью, так и скоростью. В сравнении с другими системами сборки на Node.js Grunt заметно медленнее, и, что особенно неприятно, имеет тенденцию замедляться по мере роста проекта. Если не вдаваться в детали архитектуры Grunt, то причина кроется в том, что каждый раз, когда тебе нужно собрать, например, JS-файл, он пересобирает все JS-файлы. Можно постараться ускорить процесс сборки, прописав вручную необходимые связи между файлами, но на проекте со сложным деревом зависимостей файлов это может оказаться чрезмерно сложным.

Несмотря на все это, у Grunt огромная экосистема: сотни плагинов, тысячи проектов, миллиарды разработчиков, вот это все. То есть мало того, что Grunt универсален, еще и плагин под твою задачу уже, скорее всего, написан.

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

Gulp

Gulp - активно развивающаяся в данный момент система сборки. В основе ее архитектуры лежит использование потоков в Node.js, что позволяет не записывать на диск временные файлы и папки. Основные достоинства Gulp - скорость и краткость конфига. Причем если первое бесспорно, то краткость по сравнению с Grunt достигается просто за счет другой его структуры. Если в конфиге Grunt ты по отдельности оперируешь плагинами, настраивая каждый из них, то в конфиге Gulp нужно описывать процесс, который должен пройти каждый файл (или набор файлов), чтобы быть собранным. Вот жизненный пример компиляции SASS:

Gulp.task("styles", function() { return gulp.src("styles/*.scss") .pipe(sass({ style: "expanded" })) .pipe(rename({suffix: ".min"})) .pipe(minifycss()) .pipe(gulp.dest("build/styles/css")); });

В первой строчке мы регистрируем задачу для Gulp с именем styles . Затем последовательно описываем, что же нужно сделать с каждым из файлов, подходящим под маску styles/*.scss: компилируем SASS, добавляем.min к имени файла, минимизируем, кладем в конечную директорию. Если с этим файлом понадобится делать что-то еще, мы просто добавим соответствующую команду, например.pipe(добавить комментарий с ASCII-единорогом в начало файла) (надеюсь, для этой повседневной задачи сделают наконец плагин). Мне такой подход к написанию конфига нравится больше: он лучше описывает, что же реально происходит с твоими файлами.

Конечно, пока Gulp проигрывает Grunt по количеству плагинов, но для множества задач плагины есть. Скорее всего, тебе хватит существующих плагинов, а если будет чего-то очень не хватать, всегда можно написать свой (шутка). Кстати, есть пакет gulp-grunt, который позволяет запускать задачи Grunt из Gulp, если прям очень надо.

Если тебе нравится подобный подход к сборке, важна скорость и не нужно выполнять специфические задачи, плагин для которых есть только для Grunt, то Gulp может стать отличным выбором. На настоящий момент Gulp остается самым серьезным конкурентом Grunt.

Broccolli

Самый молодой из рассматриваемых инструментов сборки, находится сейчас, по сути, в стадии разработки. Разработчики Broccolli не скрывают, что вдохновлялись Gulp, однако считают некоторые концепции, лежащие в его основе, ошибочными. Например, они выбрали кеширование всех промежуточных результатов сборки (причем реализуемое каждым из плагинов) для ее ускорения вместо частичной пересборки только требуемых файлов. Также им не понравилось, что Gulp лучше всего оперирует с трансформацией одного файла в один итоговый, то есть один к одному. Чтобы улучшить выполнение операций вида «много к одному», в данный момент Gulp разрабатывает сложную схему с созданием виртуальной файловой системы, что разработчикам Broccolli кажется лишним усложнением и проявлением слабости изначальных концепций Gulp. Broccolli изначально оперирует понятиями деревьев вместо файлов и совершает только трансформации деревьев в другие деревья (пусть даже вырожденные и из одной вершины).

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

Brunch

Brunch создавался с той же задачей - уделать Grunt по всем фронтам, но подошел к ней совсем с другой стороны. Разработчики Brunch решили взять хорошим пониманием предметной области, то есть сделать менее универсальный инструмент, который будет заточен именно под задачи фронтенда, например без всяких настроек понимать, что *.js - это файл со скриптами, *.coffee - CoffeeScript и так далее. Brunch довольно быстрый, гораздо быстрее Grunt, но чуть медленнее Gulp. К безусловным достоинствам Brunch стоит отнести также действительно компактный конфиг, меньше, чем у Grunt и Gulp, в разы. Вот, например, простой конфиг Brunch:

Exports.config = files: javascripts: joinTo: "javascripts/app.js": /^app/ "javascripts/vendor.js": /^(bower_components|vendor)/ stylesheets: joinTo: "stylesheets/app.css" order: after: ["vendor/styles/helpers.css"] templates: joinTo: "javascripts/app.js"

Заметь, что конфиг можно писать как на CoffeeScript (как в данном случае), так и на обычном JS. Мы создаем обычный модуль, который возвращает JSON с настройками сборки.

Обрати внимание на ключи joinTo и order. Это и есть знание предметной области, о котором я упоминал, - на уровне конфига Brunch знает, что ты, скорее всего, захочешь склеить файлы, причем некоторые раньше остальных. Именно это позволяет заменить 400 строк конфига Grunt на 20–30 строчек Brunch.

Плюс к этому экосистема Brunch гораздо меньше, чем у Grunt и даже чем у Gulp. Плагинов около 50 (сравни с 450+ у Gulp, например), развитие идет не очень быстро, в общем, здесь все довольно печально.

Подводя итог: если тебе очень нравятся короткие конфиги, важна скорость, но при это не нужны никакие особенные действия на этапе сборки, то можно посмотреть на Brunch. Смущает, конечно, небольшое количество плагинов, но, может быть, ситуация поменяется.

ENB

Ну и под конец самое сладкое. Хочу рассказать про систему сборки, разработанную в Яндексе Маратом Дулиным, которая называется ENB. Именно ее мы сейчас и используем на нашем проекте. Ее подход принципиально отличается от всех описанных систем: изначально она создавалась для работы с проектами, использующими BEM-методологию, хотя, как отмечает автор, ее платформа свободна от идеологии BEM и может быть использована для всех проектов подходящей структуры.

Вкратце, в чем суть. В ENB мы оперируем понятием цели, то есть конечного файла, который нужно собрать, или ноды (папки, в общем случае страницы), для которой нужно собрать некоторый набор файлов. Для того чтобы собрать целевой файл, мы используем некоторое количество технологий (грубо говоря, плагинов в терминах Grunt, хотя технологии меньше по размерам и более специализированы). Первым делом ENB определяет исходный набор файлов, которые нужны для сборки целей (этим занимаются несколько базовых технологий, по умолчанию работающие с методологией BEM, то есть они ищут *.bemdecl -файл, в котором прописаны зависимости данной ноды от разных блоков), полностью разворачивает это дерево зависимостей (когда блок, от которого зависит твоя страница, сам зависит от другого, подключаются оба в нужном порядке), а затем находит файлы, необходимые для каждой зарегистрированной технологии. Затем ENB придерживается описанной в конфиге последовательности трансформаций файлов (тут можно проследить некоторую аналогию с Gulp). Несмотря на некоторые отличия от стандартного подхода систем сборки, разобравшись с основными понятиями, дальше работать с ENB довольно легко.

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

К недостаткам можно отнести то, что конфиг ENB достаточно многословный, так как есть возможность управлять абсолютно всеми этапами сборки. Плюс ENB все-таки писался для BEM-методологии, и прикрутить его к проекту с совершенно другой структурой потребует лишних телодвижений. Для ENB не так много написанных технологий (порядка 60), но с большинством задач BEM-проектов он справляется на ура.

Подводя итог: ENB - лучший выбор для проектов, основанных на методологии BEM, которую лично я считаю наиболее подходящей для средних и больших сайтов, так как организация кода по блокам рулит и бибикает. Он очень быстрый, собирает десятки страниц и сотни файлов за считаные секунды, несложный в настройке и приятный в использовании. Если твой проект крупный, ты путаешься в коде и правишь файлики по тысяче строк, советую подробнее изучить BEM как способ организации структуры фронтенд-проектов. А когда ты полюбишь BEM, ты полюбишь и ENB, как самый родной инструмент сборки BEM-проектов.

Джентльменский набор Front-end разработчика

Ни для кого не секрет, что современный front-end разработчик обязан иметь в своем вооружении один из инструментов сборки проектов такие как Gulp или Grunt . До какого-то времени Grunt занимал монополию в этом вопросе, но отделившаяся от Grunt группа разработчиков решила создать свой легковесный и быстрый таск-менеджер Gulp.

В этой статье мы с нуля подготовим стартовый пакет для использования его в будущих проектах.

Какие мы используем технологии

  • Программная платформа: Node.js
  • CSS пре-процессор: Stylus
  • Таск-менеджер: Gulp

Зачем фронтендеру таск-менеджер

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

CSS пре-процессоры - реально удобны и ускоряют написание стилей, но компилирование кода написанного на пре-процессоре в обычный CSS, не совсем тривиальная задача которая решается одной кнопкой. Тут то нам на помощь и приходит таск-менеджер. Преобразование кода происходит не то чтобы нажатием кнопки, все происходит в режиме онлайн без вашего участия (конечно если правильно все настроить).

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

Установка Node.js

Если вы знаете как установить node.js на свою систему и пользуетесь ей, можете смело переходить к следующему заголовку.

Хотелось бы сразу предупредить, что все описанные действия актуальны для Mac OS X , но в целом применимы и для других Unix систем. Разработка через таск-менеджер и командную строку в Windows несколько более затруднительная и тут она описана не будет. Однако, если вы все же пользуетесь Windows и не готовы от него отказываться, то могу предложить вариант использования виртуальной машины с установленной Ubuntu , я использую этот вариант на своей домашней системе, что в целом довольно удобно.

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

в ответ должна появиться версия установленной node.js. Если все хорошо, идем дальше.

Структура директорий проекта

В наших проектах мы будем использовать унифицированный вариант структуры:

Develop - корневой каталог разработки └─start - каталог проекта ├─build - билд собраный таск-менеджером ├─resource - все файлы исходники для разработки (.psd и пр.) ├─src - каталог разработки │├─css - каталог разработки стилей ││├─images - все статичные изображения ││├─sprites - изображение собираемые в спрайт ││├─partial - пользовательские файлы стилей │││├─mixins.styl - пользовательские миксины │││└─styles.styl - пользовательские стили ││├─vendor - прочие внешние файлы стилей ││└─styles.styl - основной файл стилей │├─fonts - каталог шрифтов │├─img - каталог динамических изображений │├─js - каталог разработки JavaScript ││├─_*.js - побочные файлы js ││├─_main.js - основной пользовательский js ││└─main.js - основной файл js │├─.htaccess - конфиг для сервера │├─*.html - файлы разметки страницы │├─pages.html - файл со ссылками на все страницы шаблона │├─index.html - индексовый файл разметки страницы │└─include - каталог подключаемых файлов разметки │ └─*.html - подключаемые файлы разметки (header.html и пр.) ├─package.json - конфиг пакетного менеджера npm ├─gulpfile.js - конфиг Gulp ├─stylus.template.mustache - маска для чтения спрайтов ├─TODO - todo лист └─.gitignore - конфиг для Git

Установка

В консоли с помощью команды cd перейдем в корневой каталог разработки, создадим каталог нашего проекта mkdir start и перейдем в него.

Установим нашу структуру для проекта через консоль:

mkdir build resource src src/css src/css/images src/css/sprites src/css/partial src/css/vendor src/js src/template src/template/include src/img src/fonts

Создадим начальные файлы в структуре проекта:

touch gulpfile.js stylus.template.mustache .gitignore src/.htaccess src/TODO src/css/styles.styl src/css/partial/styles.styl src/css/partial/mixins.styl src/js/main.js src/js/_main.js src/template/pages.html src/template/index.html src/template/include/header.html src/template/include/footer.html

Создадим package.json

все всплывающие вопросы можно прощелкать через Enter, node установит им значения по-умолчанию, либо заполнить предлагаемые поля.

.gitignore

Говорим гиту какие каталоги игнорировать и не заливать в репозиторий:

/node_modules/ /build/ /resource/

Каталог node_modules появится позже после установки плагинов и будет содержать в себе все node-плагины проекта.

src/.htaccess

Устанавливаем для сервера дополнительное gzip сжатие и кэширование:

AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css text/javascript application/javascript # Serve gzip compressed CSS files if they exist # and the client accepts gzip. RewriteCond "%{HTTP:Accept-encoding}" "gzip" RewriteCond "%{REQUEST_FILENAME}\.gz" -s RewriteRule "^(.*)\.css" "$1\.css\.gz" # Serve gzip compressed JS files if they exist # and the client accepts gzip. RewriteCond "%{HTTP:Accept-encoding}" "gzip" RewriteCond "%{REQUEST_FILENAME}\.gz" -s RewriteRule "^(.*)\.js" "$1\.js\.gz" # Serve correct content types, and prevent mod_deflate double gzip. RewriteRule "\.css\.gz$" "-" RewriteRule "\.js\.gz$" "-" # Serve correct encoding type. Header append Content-Encoding gzip # Force proxies to cache gzipped & # non-gzipped css/js files separately. Header append Vary Accept-Encoding ExpiresActive on ExpiresByType application/javascript "access plus 1 months" ExpiresByType image/jpg "access plus 1 month" ExpiresByType image/jpeg "access plus 1 month" ExpiresByType image/gif "access plus 1 month" ExpiresByType image/png "access plus 1 month" ExpiresByType text/css "access plus 1 months"

src/css/styles.styl

Подключим пользовательские файлы стилей в основной файл стилей:

@import "partial/styles"

Обратите внимание, что для подключение.styl файлов, расширение не указывается, согласно семантике кода пре-процессора Stylus. Для подключения стилей в другом расширении, например.css, указание последнего обязательно.

TODO

Эта страница содержит в себе todo лист разработки. Более подробно о работе с данным файлом вы можете почитать на странице плагина PlainTasks для Sublime Text.

На этом установка структуры завершена.

Установка плагинов через пакетный менеджер npm

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

Установка плагина Gulp

Для начала нужно установить Gulp глобально (с ключем -g) на нашу систему

npm install gulp -g

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

Теперь нужно установить Gulp локально в каталог проекта

npm install gulp --save-dev

Ключ --save-dev говорит о том, что информация о плагине (имя в репозитории и его версия) будет добавлена в конфиг package.json и запомнит его для данного проекта. Поскольку мы не храним в гите тяжеловесную папку с плагинами node_modules , сохраненная в конфиге информация об установленных плагинах позволит всего одной командой npm i развернуть в проекте все нужные плагины.

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

В дальнейшем мы так же будем пользоваться сокращенным форматом команд.

Плагин Stylus для Gulp

В наших проектах мы пользуемся пре-процессором Stylus который отлично работает и компилируется на ноде.

Устанавливаем:

npm i gulp-stylus -D

Плагины обработки CSS

Автопрефиксер - автоматически подставляет префиксы -ms- -o- -moz- -webkit- в нужные свойства:

npm i gulp-autoprefixer -D

Минификация CSS - плагин минифицирует выходной CSS файл избавляя его от лишних пробелов и табуляций:

npm i gulp-minify-css -D

Плагины обработки изображений

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

npm i gulp.spritesmith -D

Добавим в ранее созданный файл stylus.template.mustache маску вычисления позиций в спрайтах:

{{#items}} ${{name}} = {{px.x}} {{px.y}} {{px.offset_x}} {{px.offset_y}} {{px.width}} {{px.height}} {{px.total_width}} {{px.total_height}} "{{{escaped_image}}}"; {{/items}}

Добавим специальные миксины в mixins.styl:

SpriteWidth($sprite) width $sprite spriteHeight($sprite) height $sprite spritePosition($sprite) background-position $sprite $sprite spriteImage($sprite) background-image url($sprite) sprite($sprite) if !match("hover", selector()) && !match("active", selector()) spriteImage($sprite) spritePosition($sprite) spriteWidth($sprite) spriteHeight($sprite)

Подключим миксины и генерируемый файл с координатами в основной файл стилей src/css/styles.styl:

@import "partial/sprite" @import "partial/mixins"

Обратите внимание что файлы спрайтов должны подключаться до пользовательских стилей @import "partial/styles"

Оптимизация изображений под веб - плагин автоматически вырежет всю лишнюю информацию из ваших изображений и ужмет их до оптимального размера, что позволит в некоторых случаях добиться сокращения объема изображений до 90%:

npm i gulp-imagemin -D

Плагины обработки JavaScript

Минификация JS - плагин максимально минифицирует ваш JS код сокращая время его загрузки:

npm i gulp-uglify -D

Отслеживание ошибок JS - плагин досканально проверит ваш JS код на выявление всех несоответствий и выведет их в консоль:

npm i jshint gulp-jshint -D

Плагины обработки HTML

Подключаемые файлы - плагин позволяет хранить статичные части сайта, такие как header , footer , aside и т.д., в отдельных файлах и подключать их в любой части другого файла. Больше нет надобности, в случае мелких изменений в шапке, менять десятки, а то и сотни html страниц шаблона:

npm i gulp-rigger -D

Плагин так же совместим с JS.

Подключим пользовательский JS в основной файл JS src/js/main.js констуркцией:

//= _main.js

Подключим в index.html файлы header.html и footer.html

//= include/header.html //= include/footer.html

Прочие плагины

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

npm i gulp-connect -D

Предохраняем Gulp от вылета - иногда случается так, что Gulp может вылететь из режима наблюдения в случае возникновения критических ошибок (в основном из-за JS). Данный плагин, по возможности, старается оставить процессы Gulp работоспособными:

npm i gulp-plumber -D

Переименование файлов - самая обычная работа с именами файлов. Плагин позволяет полностью переименовывать файлы, изменять расширение, добавлять префиксы и постфиксы, например чтобы привести файл вида style.styl в style.min.css:

npm i gulp-rename -D

Клинер - иногда возникает потребность в полном очищении каталога build , тут нам на помощь приходит плагин:

Sourcemap - для того чтобы после минификации ваши файлы оставались читаемы через отладку браузером, нужно добавлять sourcemap в минифицируемые файлы:

npm i gulp-sourcemaps -D

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

npm i gulp-watch -D

Проверим package.json

После всех установленных плагинов, проверим наш package.json . Он должен иметь примерно следующий вид:

{ "name": "start", "version": "1.0.0", "description": "Start pack for Front-end develop", "author": "Ivan Ivanov", "license": "MIT", "dependencies": {}, "devDependencies": { "gulp": "latest", "gulp-autoprefixer": "latest", "gulp-connect": "latest", "gulp-imagemin": "latest", "jshint": "latest", "jshint-stylish": "latest", "gulp-jshint": "latest", "gulp-minify-css": "latest", "gulp-plumber": "latest", "gulp-rename": "latest", "gulp-rigger": "latest", "gulp-sourcemaps": "latest", "gulp-stylus": "latest", "gulp-uglify": "latest", "gulp-watch": "latest", "gulp.spritesmith": "latest", "rimraf": "latest" } }

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

В папке проекта также должен появиться каталог node_modules в котором хранятся все файлы плагинов ноды. Все нужные плагины установлены, можно переходить к настройки конфига Gulp.

Настройка gulpfile.js

gulpfile.js - это основной файл конфигурации нашего таск-менеджера, именно в нем мы будем хранить все настройки и команды.

Вся работа Gulp сводится к task (англ. задача). Задача - это отдельная самостоятельная функция с именем. Каждая задача может быть вызвана отдельно.

Режим совмстимости с современными стандартами

Во первых в начало файла подключим режим совместимости только по современным стандартам:

"use strict";

Подробнее про эту директиву можно .

Инициализируем плагин

Плагины инициализируются следующей конструкцией:

var initPlugin = require("plugin-name");

В соответствии с этой конструкцией инициализируем все наши плагины:

Var gulp = require("gulp"), //основной плагин gulp stylus = require("gulp-stylus"), //препроцессор stylus prefixer = require("gulp-autoprefixer"), //расставление автопрефиксов cssmin = require("gulp-minify-css"), //минификация css uglify = require("gulp-uglify"), //минификация js jshint = require("gulp-jshint"), //отслеживание ошибкок в js rigger = require("gulp-rigger"), //работа с инклюдами в html и js imagemin = require("gulp-imagemin"), //минимизация изображений spritesmith = require("gulp.spritesmith"), //объединение картинок в спрайты rimraf = require("rimraf"), //очистка sourcemaps = require("gulp-sourcemaps"), //sourcemaps rename = require("gulp-rename"), //переименвоание файлов plumber = require("gulp-plumber"), //предохранитель для остановки гальпа watch = require("gulp-watch"), //расширение возможностей watch connect = require("gulp-connect"); //livereload

Константы путей

Для удобства сразу определим все пути и маски:

Var path = { build: { //Тут мы укажем куда складывать готовые после сборки файлы html: "build/", js: "build/js/", css: "build/css/", img: "build/css/images/", fonts: "build/fonts/", htaccess: "build/", contentImg: "build/img/", sprites: "src/css/images/", spritesCss: "src/css/partial/" }, src: { //Пути откуда брать исходники html: "src/template/*.html", //Синтаксис src/template/*.html говорит gulp что мы хотим взять все файлы с расширением.html js: "src/js/[^_]*.js",//В стилях и скриптах нам понадобятся только main файлы jshint: "src/js/*.js", css: "src/css/styles.styl", cssVendor: "src/css/vendor/*.*", //Если мы хотим файлы библиотек отдельно хранить то раскоментить строчку img: "src/css/images/**/*.*", //Синтаксис img/**/*.* означает - взять все файлы всех расширений из папки и из вложенных каталогов fonts: "src/fonts/**/*.*", contentImg: "src/img/**/*.*", sprites: "src/css/sprites/*.png", htaccess: "src/.htaccess" }, watch: { //Тут мы укажем, за изменением каких файлов мы хотим наблюдать html: "src/template/**/*.html", js: "src/js/**/*.js", css: "src/css/**/*.*", img: "src/css/images/**/*.*", contentImg: "src/img/**/*.*", fonts: "src/fonts/**/*.*", htaccess: "src/.htaccess", sprites: "src/css/sprites/*.png" }, clean: "./build", //директории которые могут очищаться outputDir: "./build" //исходная корневая директория для запуска минисервера };

Обратите внимание, что мы можем использовать маски имен:

  • *.js - все файлы с расширением js
  • [^_]*.js - все файлы с расширением js, исключая те что начинаются с нижнего подчеркивания
  • *.* - любые файлы с любым расширением в пределах текущей дитректории
  • /**/*.html - все файлы с расширением.html в пределах текущей директории и всех дочерних директорий

Task (задачи)

Теперь, когда все константы прописаны, можно приступить к написанию тасков. Все задачи имеют следующую конструкцию:

Gulp.task("taskName", function(){ //some functions });

Мини-сервер и LiveReload

Первым делом мы настроим работу локального сервера и LiveReload:

// Локальный сервер для разработки gulp.task("connect", function(){ connect.server({ //настриваем конфиги сервера root: , //корневая директория запуска сервера port: 9999, //какой порт будем использовать livereload: true //инициализируем работу LiveReload }); });

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

Билд HTML

// таск для билдинга html gulp.task("html:build", function () { gulp.src(path.src.html) //Выберем файлы по нужному пути.pipe(rigger()) //Прогоним через rigger .pipe(gulp.dest(path.build.html)) //выгрузим их в папку build .pipe(connect.reload()) //И перезагрузим наш сервер для обновлений });

Билд JS

// проверка js на ошибки и вывод их в консоль gulp.task("jshint:build", function() { return gulp.src(path.src.jshint) //выберем файлы по нужному пути.pipe(jshint()) //прогоним через jshint .pipe(jshint.reporter("jshint-stylish")); //стилизуем вывод ошибок в консоль }); // билдинг яваскрипта gulp.task("js:build", function () { gulp.src(path.src.js) //Найдем наш main файл.pipe(rigger()) //Прогоним через rigger .pipe(sourcemaps.init()) //Инициализируем sourcemap .pipe(uglify()) //Сожмем наш js .pipe(sourcemaps.write()) //Пропишем карты.pipe(rename({suffix: ".min"})) //добавим суффикс.min к выходному файлу.pipe(gulp.dest(path.build.js)) //выгрузим готовый файл в build .pipe(connect.reload()) //И перезагрузим сервер });

Билд спрайтов

Все изображения для объединения в спрайты складываются в директорию src/css/sprites/ и после прогона через Gulp становятся единым спрайтовым изображением. В спрайты не стоит складывать логотипы и бэкграунды без четких размеров.

// билдим спрайты gulp.task("sprites:build", function () { var spriteData = gulp.src(path.src.sprites) //выберем откуда брать изображения для объединения в спрайт.pipe(spritesmith({ imgName: "sprite.png", //имя спрайтового изображения cssName: "sprite.styl", //имя стиля где храним позиции изображений в спрайте imgPath: "images/sprite.png", //путь где лежит спрайт cssFormat: "stylus", //формат в котором обрабатываем позиции cssTemplate: "stylus.template.mustache", //файл маски cssVarMap: function(sprite) { sprite.name = "s-" + sprite.name //имя каждого спрайта будет состоять из имени файла и конструкции "s-" в начале имени } })); spriteData.img.pipe(gulp.dest(path.build.sprites)); // путь, куда сохраняем картинку spriteData.css.pipe(gulp.dest(path.build.spritesCss)); // путь, куда сохраняем стили });

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

Lorem sprite($s-lorem)

Теперь объект с классом.lorem примет размеры изображения и само изображение в качестве фона.

Билд статичных изображений

Статичные изображения - это изображения используемые в шаблоне верстки.

// билдим статичные изображения gulp.task("image:build", function () { gulp.src(path.src.img) //Выберем наши картинки.pipe(imagemin({ //Сожмем их progressive: true, //сжатие.jpg svgoPlugins: [{removeViewBox: false}], //сжатие.svg interlaced: true, //сжатие.gif optimizationLevel: 3 //степень сжатия от 0 до 7 })) .pipe(gulp.dest(path.build.img)) //выгрузим в build .pipe(connect.reload()) //перезагрузим сервер });

Билд динамичных изображений

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

// билдим динамичные изображения gulp.task("imagescontent:build", function() { gulp.src(path.src.contentImg) .pipe(imagemin({ //Сожмем их progressive: true, //сжатие.jpg svgoPlugins: [{removeViewBox: false}], //сжатие.svg interlaced: true, //сжатие.gif optimizationLevel: 3 //степень сжатия от 0 до 7 })) .pipe(gulp.dest(path.build.contentImg)) //выгрузим в build .pipe(connect.reload()) //перезагрузим сервер });

Билдим CSS

// билдинг пользовательского css gulp.task("cssOwn:build", function () { gulp.src(path.src.css) //Выберем наш основной файл стилей.pipe(sourcemaps.init()) //инициализируем soucemap .pipe(stylus({ compress: true, "include css": true })) //Скомпилируем stylus .pipe(prefixer({ browser: ["last 3 version", "> 1%", "ie 8", "ie 7"] })) //Добавим вендорные префиксы.pipe(cssmin()) //Сожмем.pipe(sourcemaps.write()) //пропишем sourcemap .pipe(rename({suffix: ".min"})) //добавим суффикс.min к имени выходного файла.pipe(gulp.dest(path.build.css)) //вызгрузим в build .pipe(connect.reload()) //перезагрузим сервер });

Отдельный таск для внешних стилей:

// билдинг вендорного css gulp.task("cssVendor:build", function () { gulp.src(path.src.cssVendor) // Берем папку vendor .pipe(sourcemaps.init()) //инициализируем soucemap .pipe(cssmin()) //Сожмем.pipe(sourcemaps.write()) //пропишем sourcemap .pipe(gulp.dest(path.build.css)) //выгрузим в build .pipe(connect.reload()) //перезагрузим сервер });

Также добавим таск для билда общего CSS:

// билдим css целиком gulp.task("css:build", [ "cssOwn:build", // "cssVendor:build" ]);

В случае если требуется обработать внешние стили отдельно от домашних и выгрузить их отдельными файлами нужно раскомментировать строчку "cssVendor:build"

Билд шрифтов

// билдим шрифты gulp.task("fonts:build", function() { gulp.src(path.src.fonts) .pipe(gulp.dest(path.build.fonts)) //выгружаем в build });

Билд.htaccess

// билдим htaccess gulp.task("htaccess:build", function() { gulp.src(path.src.htaccess) .pipe(gulp.dest(path.build.htaccess)) //выгружаем в build });

Общий билд

Для того чтобы нам не приходилось билдить каждую часть отдельно, пропишем таск для общего билда:

// билдим все gulp.task("build", [ "html:build", "jshint:build", "js:build", "sprites:build", "css:build", "fonts:build", "htaccess:build", "image:build", "imagescontent:build" ]);

Очистка билда

Иногда требуется полностью очистить каталог build . Здесь нам на помощь придет следующий таск:

// чистим папку билда gulp.task("clean", function (cb) { rimraf(path.clean, cb); });

Watch или отслеживание изменений в реальном времени

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

// watch gulp.task("watch", function(){ //билдим html в случае изменения watch(, function(event, cb) { gulp.start("html:build"); }); //билдим спрайты в случае изменения watch(, function(event, cb) { gulp.start("sprites:build"); }); //билдим контекстные изрображения в случае изменения watch(, function(event, cb) { gulp.start("imagescontent:build"); }); //билдим css в случае изменения watch(, function(event, cb) { gulp.start("css:build"); }); //проверяем js в случае изменения watch(, ["jshint"]); //билдим js в случае изменения watch(, function(event, cb) { gulp.start("js:build"); }); //билдим статичные изображения в случае изменения watch(, function(event, cb) { gulp.start("image:build"); }); //билдим шрифты в случае изменения watch(, function(event, cb) { gulp.start("fonts:build"); }); //билдим htaccess в случае изменения watch(, function(event, cb) { gulp.start("htaccess:build"); }); });

Действия по-умолчанию

Действия по-умолчанию - это то какие задачи будет выполнять таск-менеджер при вводе команды gulp в консоль:

// действия по умолчанию gulp.task("default", ["build", "watch", "connect"]);

В нашем случае по-умончанию мы сбилдим наш проект, включим режим watch и запустим сервер.

Команды для командной строки

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

  • gulp - основная команда, запускает таск default
  • gulp build - билдим всё
  • gulp watch - запуск watch
  • gulp clean - очистка каталога build
  • gulp connect - запуск сервер
  • gulp html:build - билд HTML
  • gulp jshint:build - проверяем JS на ошибки
  • gulp js:build - билд JS
  • gulp sprites:build - билд спрайта
  • gulp image:build - билд статичных изображений
  • gulp imagecontent:build - билд динамичных изображений
  • gulp cssOwn:build - билд пользовательского CSS
  • gulp cssVendor:build - билд внешних CSS
  • gulp css:build - общий билд CSS
  • gulp fonts:build - билд шрифтов
  • gulp htaccess:build - билд.htaccess

На данном этапе настройка gulpfile.js закончена.

Копируем стартовый пакет в проект

Для начала зайдем через консоль в папке где мы ведем разработку, например cd develop/example и скопируем все из директории стартового пакета в наш проект cp -a ~/develop/start/. ~/develop/example/

Такой способ копирования наиболее удобен, т.к. точно скопирует все, в том числе и скрытые файлы.gitignore и пр.

Заключение

Используя данное руководство мы подготовили стартовый пакет для использования Gulp в своих проектах для Front-end разработки.

Так же данный пакет доступен на GitHub

Post Scriptum

Данная статья не является заключительной и будет обновляться в зависимости от изменений и улучшений.