Контакти

Джентльменський набір Front-end розробника. Збірка front-end'а на пальцях за допомогою Gulp Приємна збірка frontend проекту

вересень 24 , 2016

Будуть розглянуті такі питання: робота зі стилями sass з використанням sourcemaps, склеювання і стиснення js-файлів, збірка requirejs за допомогою rjs, препроцессінг html, очищення та копіювання файлів, оптимізація зображень, підняття локального веб-сервера і режим спостереження - watch-таски. Ласкаво просимо до статті, буде багато цікавого!
P.S. Матеріалу багато, тому стаття буде розбита на 3 частини: основи побудови та організація проекту, написання тестового додатка на Backbone + Require.js і власне складання за допомогою gulp.

Навіщо потрібна збірка фронтенда.

Один з найважливіших принципів в розробці - це модульність. Розбиття коду проекту на безліч невеликих, в ідеалі слабосвязанних між собою шматочків-модулів. Це стосується далеко не тільки javascript-коду. Це відноситься і до стилів, і html-шаблонів, до різних бібліотекам.

Приблизно так може виглядати структура простого програми, написаної на Backbone + Require.

І це невеликий тестовий проект, в реальному додатку файлів може бути сотні і тисячі. Змушувати браузер користувача робити сотні http-запитів щонайменше негуманно. Ми повинні забезпечити максимально швидке завантаження написаного нами сервісу. Тому одна з найважливіших завдань інструментів збірки - це мініфікація, зменшення кількості використовуваних на проекті файлів, склеювання їх в бандли. На виході ми повинні мати більш коротку структуру, наприклад, ось таку:

Різниця добре помітна: замість десятків файлів ми маємо один index.html, один css-файл, оптимізовані і стислі зображення в окремій папці, хоча на скріншоті цього і не видно :-)

А також найцікавіше: в папці js ми отримали всього 3 стислих файлу.
P.S. Чому три, а не один, розповім пізніше.
Зауважу, що це реальна структура тестового додатку, який ми невдовзі напишемо.

Я описав лише одну причину використання інструментів збірки, але вона вже достатня, щоб почати використовувати gulp, grunt, webpack або щось подібне в своїх проектах. Причому не має значення, пишемо ми величезний сервіс, невелике SPA (як в нашій статті) або landing page. Принципи складання однакові для всіх проектів і розрізняються лише різноманітністю завдань і підходів до їх вирішення. У нашому прикладі ми створимо таку структуру, яка може як завгодно розширитися надалі, але на виході завжди буде акуратна стопка файлів, готова до виливання на ваш продакшен - бойовий сайт.

Як правильно організувати проект.

Принцип такий: є розділ з девелоперськими файлами, тобто з зібраними і все інше, що це добро обслуговує. Створимо в корені проекту 2 папки: src і build. У src і тільки в src ми будемо працювати, створювати нові файли, редагувати їх і взагалі розважатися. На скріншоті вище, там, де пара десятків файлів, Ви бачили саме вміст папки src нашого тестового проекту. А трохи нижче кілька акуратних файлів з папки build. Вона формується тільки автоматично, інструментами збірки, нічого самим там правити не потрібно. Все одно за будь-якої збірці її вміст затирається новими файлами (а в режимі development папки build взагалі немає - видаляється, щоб не муляти очі)

Крім src і build в корені будуть лежати файли package.json, gulpfile.js, папка node_modules і опціонально, .gitignore (якщо Ви працює з гітом). У мене ще можна помітити папку logs - це породження apache і давня звичка тримати логи проекту в його ж папці, звичайно, виключивши її зі сховищ Гіта :-)

Ось так виглядає структура проекту цілком:

За вмістом build, думаю, питань немає, по src поясню докладніше:

  • 1. html - index.html, кореневої індексний файл проекту. Чому не відразу в корені src? Тому що він буде препроцессіться і створюватися gulp-му. Яким чином, дізнаємося трохи пізніше, коли впритул займемося складанням.
  • 2. img - зображення, не стислі, звичайні
  • 3. js - вся javascript-двіжуха проекту, моделі та подання Backbone
  • 4. lib - сторонні бібліотеки, на зразок backbone.js, require.js, lodash.js і інших
  • 5. scripts - js-скрипти, які необхідні на бойовому сайті, але не потрібні в режимі розробки. Маються на увазі коди для аналітики, різних експериментів та інших маркетингових штук.
  • 6. styles - sass-файли зі стилями. В цю ж папку буде складатися зібраний css-файл (тільки для режиму девелопменту)
  • 7. tpl - html-шаблони. Використовуються уявленнями Backbone за допомогою плагіна require.js text

Зовнішній вигляд тестового додатка досить непоказний. Ви можете сказати, що подібна хрень робиться парою рядків html і css-коду без єдиного js-файлу.
Але ми переслідуємо ціль не намалювати красиву картинку, а створити надійну структуру проекту і розглянути якомога більше аспектів складання. Коли проект розростеться до сотні файлів, ми вже будемо готові до цієї напасті і легко впораємося із збільшеними обсягами. Тому незважаючи на малість і зовнішню убогість тестового додатка, ми дізнаємося принципи складання для великих і складних проектів.

Які завдання збірки ми вирішимо.

Нагадаю, що ми домовилися про двох режимах збірки: development і production. Всі наші завдання ми будемо писати, пам'ятаючи про ці двох режимах. Не всі операції нам потрібні в процесі розробки, і не всі в збірці для продакшена.

Ось список того, чим ми займаємося після написання тестового додатка:

  • 1. Очищення файлів і папок від результатів попередньої збірки
  • 2. Збірка css з sass-файлів, із стисненням і без
  • 3. Підключення sourcemaps до стилів, заодно покажу на прикладі, навіщо це потрібно
  • 4. Складання js-бандла за допомогою requirejs
  • 5. Склеювання і стиснення окремих js-файлів (аналітики)
  • 6. Препроцессінг html
  • 7. Оптимізація і стиснення зображень
  • 8. Підняття локального веб-сервера
  • 9. Завдання спостереження за файлами при роботі в режимі девелопменту - watch-таски
  • 10. Збір окремих завдань в купу - підсумкові таски для production-збірки і development-роботи

Отже, ми поміркували, навіщо взагалі потрібна збірка фронтенда, визначилися зі структурою проекту, детально розібрали, що ми хочемо від збірки і в загальних рисах поговорили про тестове додаток. В наступній частині статті ми займемося написанням простенького Backbone-додатки в зв'язці з Require.js. Якщо Ви не знайомі з Backbone і / або Require.js, то нічого страшного немає. Власне Backbone-івського коду в додатку мало. Ви легко можете замість нього використовувати улюблену бібліотеку або просто писати код на javascript / jquery і пропустити розділ налаштування requirejs.

В ті часи, коли сайти були невеликими, необхідності в окремій збірці фронтенда не було. Однак обсяг і складність 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 \u003d 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-проектів.

Хочете набрати побільше балів в 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 \u003d require ( "gulp"), // Сообственно Gulp JS uglify \u003d require ( "gulp-uglify"), // Мініфікація JS concat \u003d require ( "gulp-concat"), // Склеювання файлів imagemin \u003d require ( "gulp-imagemin"), // Мініфікація зображень csso \u003d require ( "gulp-csso"), // Мініфікація CSS sass \u003d 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 і так далі.

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

В останнім часом Gulp набирає велику популярність, і зрозуміло чому. Він швидше, красивіше і простіше ніж Grunt. Мені доводилося часто з ним працювати, але я завжди брав готові рішення і не до кінця розумів як же він все це робить. На цих вихідних я вирішив розібрати і закрити цю невелику проблему. Про це і поговоримо сьогодні.

Що таке Gulp?

Gulp - це інструмент збірки front-a. Він дозволяє автоматизувати повторювані задачі (збірка і мініфікація CSS- і JS-файлів, запуск тестів, перезавантаження браузера та інші). Тим самим Gulp прискорює і оптимізує процес веб-розробки.

установка Gulp

Встановити Gulp досить легко. Якщо у вас щось не вийде, пишіть в коментарях або загугли вашу проблему. Отже для установки потрібно зробити 3 кроки:

  • Встановити Gulp глобально
  • Встановити Gulp як devDependencies (залежно для розробки)
  • Створити файл gulpfile.js

Перший крок - встановлюємо глобально Gulp. Відкриваємо термінал і пишемо:

npm install --global gulp

Після цього вам потрібно встановити Gulp як devDependencies для вашого проекту. Переконайтеся в тому, що у вас є файл package.json. Якщо його немає, то створіть його написавши в консоль npm init. Тепер можна встановити Gulp як devDependencies:

npm install --save-dev gulp

І нарешті, вам потрібно створити gulpfile.js в корені вашого проекту, який буде містити ваші завдання (tasks). Як проміжний крок, ми встановимо плагін gulp-util. Щоб показати як встановлюються плагіни:

npm install --save-dev gulp-util

Тепер настав час написати нашу першу задачу. Відкриваємо щойно створений файл gulpfile.js і пишемо в нього наступне:

/ * File: gulpfile.js * / // збираємо всі наші плагіни var gulp \u003d require ( "gulp"), gutil \u003d require ( "gulp-util"); // створюємо завдання, яка буде виконуватися за замовчуванням gulp. task ( "default", function () (return gutil. log ( "Gulp is running!")));

І тепер нам залишається запустити gulp в терміналі і ми побачимо щось схоже на це:

\u003e Gulp [12:32:08] Using gulpfile ~ / Projects / gulp-scotch-io / gulpfile.js [12:32:08] Starting "default" ... [12:32:08] Gulp is running! [12:32:08] Finished "default" after 1 ms

огляд

Сам по собі Gulp дуже мізерний на можливості. Але все, що вам потрібно винесено в окремі плагіни. Вони спільно з Gulp творять чудеса.

Api у gulp дуже маленьке, і містить всього 4 функції вищого порядку:

  • gulp.task
  • gulp.src
  • gulp.dest
  • gulp.watch

gulp.task визначає наші завдання. В якості аргументів приймає назву, залежно (масив) і функцію (основні дії). Залежностей може і не бути:

gulp. task ( "mytask", function () (// зробити щось)); gulp. task ( "dependenttask", [ "mytask"], function () ( // зробити щось після того, як "mytask" буде виконаний });

gulp.src вказує на файли, які ми хочемо використовувати. Він іспользует.pipe доступу до файлів через плагіни.

gulp.dest вказує на папку, в яку ми хочемо зберегти змінені файли.

gulp.src і gulp.dest використовується для простої копії файлів:

gulp. task ( "copyHtml", function () ( // скопіювати всі html файли з source / в public / gulp. src ( "source / *. html"). pipe (gulp. dest ( "public")); ));

У gulp вбудована система реагування на зміни файлів (gulp.watch). Ви можете використовувати цю задачу для запуску інших необхідних вам задач при зміні файлів.

Таск-раннери і системи збирання сильно прискорюють роботу, автоматизуючи компіляцію, тестування та інші рутинні завдання. Як і в будь-якій області, на цьому ринку існує сильна конкуренція. До 2014 року серед них панував таск-Раннер grunt, але пізніше зі складу проекту виділилася невелика команда, яка вирішила робити альтернативний інструмент, gulp, орієнтований на складання проекту.

Щоб допомогти вам визначитися з вибором, в рамках статті розглянемо основні таск-менеджери:

  • grunt

а також торкнемося інших засобів і способів збирання.

Забігаючи трохи наперед, скажемо, що ми в WaveAccess користуємося саме gulp. Впровадити інструмент виявилося дуже легко: у сімейства продуктів JetBrains (IDEA, WebStorm, ReSharper), які ми використовуємо вже багато років, є відмінні плагіни для роботи з gulp / grunt і npm / nodejs.

Таск-менеджер vs. система збирання проекту: в чому різниця?

Таск-менеджер - інструмент для автоматизації завдань. У конфігурації РАННЕР можна записати імена цих завдань; функцію, яка їх виконує; плагіни для прискорення стандартних дій, але самі завдання можуть бути довільними. наприклад:

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

Приклади таких інструментів - grunt і gulp.

система збирання - це інструмент, який вирішує тільки одну типову задачу збірки проекту на java script, в яку входять:

  • конкатенація,
  • перевірка коду на валідність,
  • мініфікація коду, і тд.

До подібних інструментів відносяться Webpack, Broccoli, Brunch, Browserify і інші.

Всі подібні frontend-завдання можна автоматично виконувати за допомогою інших засобів: наприклад, за допомогою npm run, про який ми також поговоримо в статті.

приклад

Розглянемо gulp-файл для збірки проекту:

Const gulp \u003d require ( 'gulp'); const coffee \u003d require ( 'gulp-coffee'); const concat \u003d require ( 'gulp-concat'); const uglify \u003d require ( 'gulp-uglify'); const imagemin \u003d require ( 'gulp-imagemin'); const sourcemaps \u003d require ( 'gulp-sourcemaps'); const del \u003d require ( 'del'); )

Але збірка - це окремий випадок великої типового завдання. Для gulp можна написати і інший config - скажімо, для деплоя:

Var gulp \u003d require ( "gulp"); var zip \u003d require ( "gulp-zip"); var del \u003d require ( "del"); var install \u003d require ( "gulp-install"); var runSequence \u003d require ( "run-sequence"); var awsLambda \u003d require ( "node-aws-lambda"); gulp.task ( "clean", function (cb) (del ([ "./ dist", "./dist.zip"], cb);)); gulp.task ( "copy", function () (return gulp.src ( "index.js") .pipe (gulp.dest ( "dist /"));)); gulp.task ( "node-mods", function () (return gulp.src ( "./ package.json") .pipe (gulp.dest ( "dist /")) .pipe (install ((production: true) ));)); // Clean up all aws-sdk directories from node_modules. We don "t // need to upload them since the Lambda instance will already // have it available globally. Gulp.task (" clean-aws-sdk ", function (callback) (del ([" dist / node_modules / ** / aws-sdk "], callback);)); gulp.task (" zip ", function () (return gulp.src ([" dist / ** / * ","! dist / package.json "]) .pipe (zip ( "dist.zip")) .pipe (gulp.dest ( "./"));)); gulp.task ( "upload", function (callback) (awsLambda.deploy ( "./ dist .zip ", require (" ./ lambda-config.js "), callback);)); gulp.task (" deploy ", function (callback) (return runSequence ([" clean "], [" copy "] , [ "node-mods"], [ "clean-aws-sdk"], [ "zip"], [ "upload"], callback);));

A можна описувати нові завдання як комбінації вже існуючих:

Gulp.task ( 'deploy', gulp.series ( 'clean', 'copy', 'node-mods', 'clean-aws-sdk', 'zip', 'upload'));

В цьому і полягає відмінність. Тепер розглянемо основні інструменти.

gulp vs. grunt

Отже, перед нами два таск-Раннера: gulp і grunt. Обидва використовують node.js і npm, а завдання їм ставлять, використовуючи javascript.

На перший погляд вони схожі, проте у gulp є те, що робить його більш зручним саме для збирання: вміння паралельно обробляти завдання і компактний конфиг, лаконічне API. Давайте подивимося ближче їх принцип роботи.

Передача потокового даних

Перед нами грант-файл, який здійснює складання і обробку CSS.

З нього видно, що grunt при запуску кожного процесу:

    відкриває файл;

    запускає процес;

    зберігає зміни;

    закриває оброблений файл, щоб запобігти втручанню в нього наступного процесу;

    записує файл в підсумкову папку.

Тобто, ланцюжок включає в себе створення декількох тимчасових папок і збереження проміжних файлів:

Модулі пишуть різні автори. Щоб кожен плагін міг працювати з файлами, обходячи збереження, файли потрібно представити у вигляді об'єктів. У gulp цю задачу виконує віртуальна файлова система Vynyl-FS. І gulp відразу передає файл наступного процесу без створення тимчасових файлів і без збереження на диск.

Та ж сама конфігурація для gulp вже компактніше:

Його загальний механізм роботи - потоковая обробка файлів без запису на диск:

Послідовність виконання завдань

Є й інша відмінність: gulp за замовчуванням асинхронно виконує таски. У цьому є і плюси, і мінуси. У тому ж файлі конфігурації ми даємо команду вважати файли з директорії dev / * scss і відправити їх в SASS.

Потоки відправляють результат в.pipe. Метод.pipe дозволяє збирати результат в буфер вроздріб, а коли він заповнений, відразу відправляти інформацію в потік для читання, ще не закінчивши отримувати вміст директорії.

Послідовне виконання завдань робить gulp швидким і потужним, але зрідка виникає необхідність все ж виконати завдання синхронно, як в grunt. Проблему можна вирішити через зворотний виклик, повернення потоку або Promise. Більш докладно завдання розібрана на Хабре. Є й альтернативний варіант на самому сайті npm.js

Якщо ви користуєтеся grunt, але вас приваблює потокова передача даних - той же модуль Vynyl-FS можна використовувати для її реалізації в grunt.

Лаконічне API gulp має всього 5 методів:

    Task (name, fn). Реєструє функцію з ім'ям. Можна вказати залежність від інших ТАСК, якщо потрібно їх виконати спочатку.

    Run (tasks ...). Виконує завдання.

    Watch (glob, fn). Виконує функцію, якщо файл на місці glob змінюється.

    Src (glob). Як параметр приймає маску файлів і повертає потік, що представляє ці файли. Потім потік може бути переданий на вхід плагинам.

    Dest (folder). Зберігає файли в вказану папку.

Особливо хотілося б відзначити налічіе.watch () в "рідному" API проекту, адже стеження за постійними змінами файлів є найважливішою складовою збірки. Стислість API дає можливість цьому таск-менеджеру сфокусуватися на своєму основному завданню - збірці проектів.

Альтернативи gulp і grunt

Незважаючи на популярність gulp (більше 130 до завантажень в день) і grunt (понад 86 до завантажень в день згідно npmjs.com), розробники бачать у цих системах і свої недоліки: наприклад, залежність від плагінів, неповна документація, незручний дебаггінг. В якості альтернативи можна розглянути системи збирання проектів (такі як Broccoli і Webpack) або npm-скрипти.

Системи збирання проектів

Розглянемо кілька альтернативних рішень на платформі Node.js. Для складання проекту вони можуть замінити gulp і grunt.

Ця система, як і gulp, виникла як конкурент таск-Раннер grunt, проте розробники спочатку задумували її саме як помічник для збирання з усіма перевагами і недоліками. Він без налаштувань "зрозуміє", що * .js - це файл з скриптами, * .coffee - це CoffeeScript; його конфіг більш компактний. Однак ніяких довільних дій на етапі складання він зробити не зможе.

Ось конфиг-файл Brunch. Він написаний на CoffeeScript (можна також писати на JS):

Exports.config \u003d 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"

Тут хочеться звернути увагу на оператори joinTo і order. На рівні конфіга Brunch розуміє, що доведеться збирати файли в потрібному порядку. В результаті, конфиг займає 20-30 рядків.

Broccoli

Інді-інструмент, який знаходиться на стадії розробки. Його розробники хотіли створити конкуренцію вже gulp.

У порівнянні з gulp, інструмент Broccoli використовує інші принципи:

    Прискорення збірки. Кожен плагін реалізує проміжне кешування результатів збірки замість часткової пересборки тільки потрібних файлів.

    Дерева замість файлів. Gulp найкраще трансформує один файл в один підсумковий. Broccolli за замовчуванням використовує тільки дерева, а не файли, і їх трансформує в інші дерева (вироджені з однієї вершини).

В даний момент інструмент активно розвивається, з'являються нові плагіни, але для серйозних проектів його використовувати рано: плагінів поки недостатньо.

Webpack - гнучка модульна система збірки. Вона володіє незвичним синтаксисом, але сама сприймає будь-які синтаксиси модулів.

Розуміючи, що доведеться конкурувати з такими гігантами як gulp, творці вирішили полегшити нам життя при розробці великих проектів. І додали в утиліту:

    Уміння автоматично будувати дерево залежностей і ресурсів.

    Зручні засоби для реалізації динамічної підвантаження.

    Сумісність з практично будь-якими модулями (AMD, UMD, ES 2015 року, Common JS, сторонні модулі на їх основі).

    Сумісність з препроцесора (SASS, Babel, Coffee Script, Type Script і т.д.).

    Live Reload (технологію асинхронної завантаження, при якій браузер оновлює НЕ сторінки цілком, а окремі додатки).

    Можливість ділити код і генерувати безліч bundle-файлів, уникаючи створення одного важкого bundle.js.

    Уміння оптимізувати код.

Окремо можна відзначити гнучкий підхід до залежностей. Модулем може стати JS, CSS і HTML-файл, і навіть JPEG з PNG. Можна використовувати require ( "myJSfile.js") і require ( "myCSSfile.css"), ділити і використовувати частини артефакту повторно.

Детальніше про можливості, конфігурації інструменту, плагинах можна знайти на Github, в презентації з Fronttalks: глибоке занурення в Webpack.

npm скрипти

Завдання по збірці можна вирішити і за допомогою npm-скриптів. Багатьох відлякує ця ідея: мало можливостей, скрипти недостатньо швидкі в порівнянні з gulp або Webpack. Проте, ці недоліки перебільшені.

Можливості npm-скриптів

Npm-скрипти вирішують досить багато завдань. Так, наприклад, можна реалізувати скрипти пасток:

( "Name": "npm-scripts-example", "version": "1.0.0", "description": "npm scripts example", "scripts": ( "prebuild": "echo I run before the build script "," build ":" cross-env NODE_ENV \u003d production webpack "" postbuild ":" echo I run after the build script "))

Сценарії будуть завантажуватися по порядку згідно префіксам: prebuild, наприклад, стартує перед build, тому що у нього є префікс pre. Відповідно, postbuild буде завантажений останнім. Команда npm run build запустить їх у потрібному порядку.

Можна викликати один скрипт з іншого, щоб декомпозировать складні завдання. Наприклад, тут завдання prebuild викликає завдання clean.

( "Name": "npm-scripts-example", "version": "1.0.0", "description": "npm scripts example", "scripts": ( "clean": "rimraf ./dist && mkdir dist "," prebuild ":" npm run clean "," build ":" cross-env NODE_ENV \u003d production webpack "))

Якщо завдання стає занадто складною, завжди можна викликати окремий файл:

( "Name": "npm-scripts-example", "version": "1.0.0", "description": "npm scripts example", "scripts": ( "build": "node build.js"))

За рахунок стрімінга gulp для задач складання став набагато зручніше, ніж grunt. Але його можна реалізувати і через npm. У Windows і Unix стрімінг робиться за замовчуванням, без збереження проміжних файлів.

Наприклад, в Unix можна зробити grep вмісту файлу і направити його в новий файл:

Grep 'My Name' bigFile.txt\u003e linesThatHaveMyName.txt

Редирект (\u003e) направляє потрібні рядки в кінцевий файл. Завдання виконується без збереження проміжних файлів.

Але є і незручності: не можна залишати коментарі в package.json. Виходом може стати створення коротких скриптів зі зрозумілими назвами, націлених на якусь одну невелику задачу. Більш детально питання заміни таск-Раннер npm-скриптами добре освітлений в англомовній статті Why I Left Gulp and Grunt for npm Scripts.

підсумок

На ринку існує велика конкуренція інструментів для автоматизації рутинних завдань (наприклад, gulp і grunt), а також інструментів для автоматизації збирання проекту (Webpack, Broccoli, Medusa, Browserify і т.д.).

Якщо дивитися на таск-раннери, то gulp в порівнянні з grunt більш простий, зрозумілий і продуктивний: виграє за рахунок економії на дискових операціях. Але у grunt більше плагінів (наприклад, є плагін для тестування). Через це у нього залишається багато шанувальників.

Якщо ж говорити тільки про збірку, то у gulp є всі переваги перед grunt:

    Поточна архітектура для передачі файлів по ланцюжку, яку забезпечує модуль Vynyl-FS.

    За замовчуванням - асинхронне виконання завдань.

    Лаконічне API всього з 5 функцій.

У той же час, для збірки Webpack є не менш цікавим інструментом. У ньому передбачена технологія Live Reload, прискорює оновлення браузера. Це величезний плюс: технологія економить час на натискання кнопки оновлення, яку розробникам доводиться натискати постійно. У gulp також є Live Reload, але Webpack складно порівнювати з gulp або grunt, так як він "заточений" тільки під білд і не "уміє" вирішувати довільні завдання.

Всі ці рішення прекрасно інтегруються з сімейством продуктів від JetBrains, проте ми в WaveAccess віддали перевагу саме grunt за широкі можливості і для верстальників, і для frontend-фахівців.

Якщо у Вас виникли питання і вам необхідна розробка web-проекту, пишіть нам на [Email protected]

  • Frontend
  • Grunt
  • Gulp
  • Task runners


Сподобалася стаття? поділіться їй