81,01
Рейтинг
2ГИС
Главные по городской навигации
26 марта 2015

TARS, сделай уровень frontend-рутины 0%

Блог компании 2ГИСРазработка веб-сайтовCSSJavaScriptHTML
image

Frontend с каждым днём становится сложнее. Задачи — объёмнее, пользовательский интерфейс — насыщеннее, HTML, CSS и Javascript — огромнее, а сон фронтендера — короче и беспокойнее. Необходимо грамотно структурировать код, выполнять множество рутинных задач (компиляция css- и js-препроцессоров, сборка спрайтов, подготовка и оптимизация изображений, минификация файлов и др). Если вы работаете в команде — это автоматически увеличивает сложность разработки. Чтобы решить эти проблемы, я создал TARS — сборщик html-вёрстки, основанный на gulpjs.

Мы в 2ГИС знаем о frontend-рутине не понаслышке. В компании создаётся много веб-проектов различной сложности: от порталов и онлайн-карты, до различных лэндингов и промо-сайтов. Мы устали от скучного копипаста при работе с html, подготовки графики для дисплеев с высокой плотностью пикселей, минификации всего, что только можно минифицировать и т.д. Казалось, что все эти вещи машина может спокойно сделать за нас. Поэтому я решил разработать инструмент для автоматизации львиной доли frontend-рутины.

UPD: мы выпустили много новинок в TARS и даже написали об этом статью!

Что хотелось получить от этого инструмента:
  • автоматизировать всё, что можно;
  • использовать уже существующие наработки, а значит использовать знакомый нам язык программирования — JavaScript, знакомую экосистему — Node.js и npm;
  • базовый набор функций в одном инструменте;
  • удобное API;
  • кроссплатформенность.

Прежде чем писать своё, сначала мы с коллегами поискали уже готовые решения. Нашлось их очень много. Вот выжимка, как мне кажется, наиболее интересных проектов:

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

Тогда родился TARS, который вобрал всё лучшее из уже готовых проектов.

TARS — это набор gulp-тасков для автоматизации большинства задач frontend’а + возможность лёгкого добавления новых, если будет чего-то не хватать. TARS можно назвать фреймворком для gulp. Подходит как отдельным разработчикам, так и большим командам. С TARS легко разрабатывать проекты любой сложности: от лендинга до огромного портала. Вам даже не нужно знать, как работает gulp, так как всё, что можно, было вынесено в опции, весь код и варианты использования задокументированы.

Ключевые особенности у TARS.
  1. Jade или Handlebars в качестве html-шаблонизатора или обычный html (при выборе Handlebars).
  2. SCSS, Less, Stylus в качестве css-препроцессора или ламповый CSS (поддерживается синтаксис в рамках любого из препроцессоров). Недавно появился проект fmp, в котором это тоже доступно.
  3. Возможность отделить данные от представления, передав данные в виде js-объекта в шаблоны. Так мы используем один и тот же шаблон много раз, но с разными данными, без копипаста, библиотек и фреймворков. Подробнее об этом будет рассказано ниже.
  4. Вотчер chokidar.
  5. По-настоящему умная работа с изображениями. Максимально упрощается разработка под экраны с высокой плотностью пикселей. Об этом будет рассказано ниже.
  6. Легко расширять своими тасками. Модульная структура.
  7. Отличная документация.
  8. Создание архива готовой сборки. Мелочь, а приятно.

Ну и, конечно же, конкатенации, минификации и оптимизации всего, что только можно, несколько режимов сборки и т.д.

У TARS внушительный набор опций, каждая из которых подробно описана в документации.

Мы уже использовали TARS в разработке сайта о технологиях, продуктах и дизайне
2ГИС, различных лендингов (Промо приложения 2ГИС для Windows Phone, франшиза 2ГИС для Казахстана, сайт внутренней конференции разработчиков 2ГИС), сайта 5pm и др.

Как всё работает


Вам понадобятся:
  • Node.js (возможно, скоро и на IO.js, работаем над этим);
  • Gulp, установленный глобально;
  • Архив с TARS.

После того, как мы скачали архив, выполняем команду gulp init. Она подключит выбранные html-шаблонизатор и css-препроцессор (указываются в конфиге), создаст базовую файловую структуру. Всё, можно колбасить. TARS работает на всех десктопных платформах.

В ближайшем будущем сделаю yeoman-генератор.

Прежде чем начать работу со сборщиком, рекомендую ознакомиться с документацией.

Основные команды для сборки


Всего есть две основные команды:
  • gulp build (или просто gulp);
  • gulp dev.

Первая команда делает готовую сборку проекта, а вторая запускает TARS в режиме разработки. В dev-режиме проект собирается без минификаций и с запущенными вотчерами за файлами.

Команды разбавлены небольшим количеством флагов:
  • gulp build (или просто gulp) (--min, --release, --ie8);
  • gulp dev (--lr, --tunnel, --ie8).

С gulp build можно использовать ключ --min, и тогда в html подключатся минифицированные js- и css-файлы. При использовании ключа --release в html подключатся всё те же минифицированные файлы, в названии которых есть рандомный hash.

С gulp dev используются ключи --lr для запуска livereload в браузере, который откроется автоматически (браузер можно выбрать в конфиге). Ключ --tunnel расшарит вёрстку с вашего локального компьютера во внешний веб. Вы получите ссылку в консоли, по которой вёрстка будет доступна в вебе.

Также с любой командой можно использовать ключ --ie8, который запустит дополнительные таски для сборки с поддержкой браузера Internet Explorer 8. Браузер особенный, вот и workflow для него особенный.

Все инструкции по установке находятся в документации.

Структура проекта


В папке «tars» находятся все файлы сборщика (встроенные и пользовательские таски с вотчерами, различные хэлперы) и папка с исходниками проекта (markup). В корне лежит конфиг сборщика, списки зависимостей для проекта, конфиг для проверки js code style и основной gulpfile.js.

├── gulpfile.js                 # gulpfile сборщика
├── tars-config.js              # Конфигурационный файл
├── package.json                # Зависимости TARS
├── user-package.json           # Пользовательские пакеты
└── tars/                       # Таски и хелперы для gulp
    └── helpers/                # Хелперы
    └── tasks/                  # Основные таски
    └── user-tasks/             # Пользовательские таски
    └── watchers/               # Основные вотчеры
    └── user-watchers/          # Пользовательские вотчеры
└── markup/                     # Основная папка с проектом
    └── modules/                # Модули
    └── pages/                  # Шаблоны страниц
    └── static/                 # Различная статика (css, js и т.п.)
└── docs/                       # Документация


Проект — это набор страниц (папка pages), набор модулей (папка modules) и папка с различной статикой (static, по умолчанию. Название можно сменить в конфиге).

Страницы — самые простые шаблоны, в которые подключаются модули. Простейший пример модуля — menu или footer. Чтобы стало понятнее, в терминах БЭМ модуль — это блок. А если без БЭМ, то модуль — любая самостоятельная сущность на странице.

exampleModule/                              # Пример модуля
    └── assets/                             # Различная статика для текущего модуля
    └── ie/                                 # Стили для ie8 и ie9 (ie9/ie8.scss|less|styl)
    └── data/                               # Папка для хранения данных для модуля
        ├── data.js                         # Данные для модуля в виде js-объекта
   ├── exampleModule.html                   # Html|Jade-представления модуля 
   ├── exampleModule.scss|less|styl         # Scss|Less|Stylus-представление модуля
   ├── exampleModule.js                     # Js-представление модуля


Каждый модуль имеет своё html-, css- и js-представление, папку для различных файлов для модуля (картинки, видеофайлы и т.д.), папку для стилей браузеров IE8 и IE9, папку с файлом данных для модулей. Все перечисленные файлы и папки необязательны для модуля. Любой модуль может включать другие модули.

Вовсе не обязательно, что модуль — отдельная сущность. Вы можете использовать модули так, как вам будет удобно.

Папка со статикой может содержать в себе подкаталоги для хранения картинок, js-файлы библиотек и плагинов, файлы выбранного css-препроцессора + различные файлы, которые должны в итоге оказаться в корне проекта, например, фавиконка или robots.txt

Обязательно прочтите, каким образом склеиваются JavaScript и CSS, — от этого зависит то, как нужно пользоваться файлами сборщика.

Файловая структура создаётся автоматически при инициализации проекта. Она в целом неизменяемая, но есть ряд необязательных каталогов, плюс ряд опций для изменения имени уже существующих папок сборщика. Файловая структура подробно описана в документации.

Для JavaScript созданы отдельные опции, в которых можно указать, откуда ещё нужно брать js для склейки. Таким образом, не нужно лезть в файлы сборщика, если вы хотите использовать какой-либо фреймворк, в котором есть не только такая сущность, как модуль (или представление, или директива, или что-то там ещё).

Работа с шаблонами


Предположим, что у нас есть страница, на которой есть верхнее, боковое и нижнее меню. Примерно такая:



Меню очень похожи друг на друга, но имеют разные ссылки, небольшие различия в стилях. Далее будем говорить в терминах БЭМ. Каждое меню — это блок. Набросаем немного html для реализации меню, который в итоге мы положим в папку modules (modules/menu/menu.html):

<nav class=”menu”>
    <ul class=”menu__list”>
        <li class=”menu__listItem”>
            <a href=”url” class=”menu__listItemLink”>title</a>
        </li>
        ...
    </ul>
</nav>


Я не буду приводить весь код, но очевидно, что портянка получается вполне солидной. Теперь вынесем все данные для этого меню (ссылки и названия пунктов меню) в отдельный файл (data/data.js в папке модуля):

menu: {
    header: {
        mod: ‘header’,
        list: [
            {
                url: firstLinkUrl,
                title: firstLinkTitle
            }
            ...
        ]
    },
    side: {
        mod: side,
        list: [
            {
                url: firstLinkUrl,
                title: firstLinkTitle
            }
            ...
        ]
    },
    footer: {
        mod: footer,
        list: [
            {
                url: firstLinkUrl,
                title: firstLinkTitle
            }
            ...
        ]
    }
}


Теперь немного усовершенствуем наш шаблон для меню (используем handlebars):

<nav class=”menu {{#if mod}} _{{mod}} {{/if}}”>
    <ul class=”menu__list”>
        {{#each list}}
            <li class=”menu__listItem”>
                <a href=”{{ur}}” class=”menu__listItemLink”>{{title}}</a>
            </li>
        {{/each}}
    </ul>
</nav>


В этом случае добавился некий mod, с помощью которого мы сможем кастомизировать CSS для меню в зависимости от его положения.
Осталось только подключить эти меню на странице:

<html>
    <head></head>
    <body>
        <header>
            {{> menu/menu menu.header}}
        </header>
        <aside>
            {{> menu/menu menu.side}}
        </aside>
        <footer>
            {{> menu/menu menu.footer}}
        </footer>
    </body>
</html>


С помощью handlebars-хелпера «>» мы подключаем модуль menu с представлением menu (каждый модуль может иметь несколько представлений) на страницу и передаём ему определённые данные.

Итого мы имеем 1 шаблон + 1 файл с данными для меню, который используется в двух разных местах. Таким образом можно реализовать модуль, который очень удобно переиспользовать. Остаётся только добавить, что такой же функционал реализован и для jade.

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


Сегодня существует много экранов с высокой плотностью пикселей. Разберёмся, что это значит.

В качестве примера рассмотрим смартфоны IPhone 3GS и IPhone 4. У 3GS разрешение экрана 320x480, а у 4-ки — 640x960. Как мы видим, разрешение увеличилось ровно в два раза при той же диагонали, а значит пиксель стал меньше. Чтобы нивелировать эту разницу между размерами пикселей (а ведь именно пикселями мы управляем в CSS) появился параметр device-pixel-ratio (или dppx), который показывает, сколько реальных экранных пикселей содержится в неком логическом пикселе, которым мы оперируем в css. Например, для дисплея IPhone 4 этот параметр равен 2. Более подробно можно прочесть на сайте W3C.

Предположим, у нас есть спрайт PNG-изображений. У таких картинок фиксированные размеры. Если мы разместим такой спрайт на экране IPhone 4, то каждый пиксель спрайта будет размыт на два экранных, а если размазывать такую картинку на количество пикселей в 2 раза большее, чем размеры картинки, то изображение будет выглядеть ужасно.

Чтобы избавиться от этой проблемы, можно использовать изображение в 2 раза большего размера, при этом размер картинки в CSS задавать исходя из размера оригинального изображения (свойство background-size).

На данный момент существуют экраны с dppx от 1 до 4 (скоро будут и выше). Готовить спрайты для четырёх размеров экранов — это очень много работы.

Выручает SVG. Векторный, не зависит от dppx-экрана, отлично рендерится в современных (и не только) браузерах. Можно сделать только один размер, и это изображение будет выглядеть одинаково на всех экранах.

К сожалению, SVG имеет несколько недостатков:
  • SVG плохо отображает радиальные и другие сложные градиенты (линейные отображаются отлично);
  • плохо отображаются сложные тени;
  • не отображается в IE8.

Итого имеем два подхода: SVG для всего, чего можем. Для остального готовим PNG-изображения. Для IE8 будем просто растрировать SVG-изображения и готовить спрайт из них.

Чтобы легко управлять этими подходами, были написаны два замечательных миксина (синтаксис SCSS):

    @include bg-svg($svg-image-name);  для SVG изображений;
    @include bg($png-image-name);  для PNG изображений.


При этом для IE8 у нас всё сгенерируется и подключится автоматически, для png-изображений сгенерируются media-запросы, которые подключают определённые png-картинки в зависимости от типа экрана. Вообще, для IE8 и IE9 генерируются отдельные css-файлы. Файлы для IE8 создаются только в том случае, если мы запустили сборку с ключом --ie8.
Пример использования миксинов:



Можете представить по объёму сгенерированного кода, сколько работы было сделано автоматически.

Более подробно о сборке графики можно почитать в документации, а сам подход отлично описан в презентации веб-разработчика Тимофея Чаптыкова.

Пользовательские таски


В TARS уже есть всё, что нужно для разработки проектов любой сложности, но всем не угодишь. У каждого может быть какая-то своя специфика, какие-то дополнительные задачи. Чтобы решить эту проблему, был создан шаблон пользовательского таска (tars/user-tasks/example-task.js). На его основе можно сделать свой таск, который легко встраивается в существующую инфраструктуру сборщика.

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

Поскольку основной package.json (файл, в котором находятся зависимости сборщика) может изменяться самим сборщиком (например, при выполнении команды gulp update-deps), то пользовательские зависимости нужно хранить в отдельном месте. Для этого есть user-package.json. Синтаксис объявления зависимостей такой же, как и в основном package.json

Также есть пример пользовательского вотчера в директории tars/user-watchers.

Планы на будущее


Есть планы по добавлению новых фич:
  • переехать на Gulp 4 версии;
  • добавить шаблонизаторы;
  • добавить пре- и пост-процессоров для CSS;
  • добавить поддержку ES6;
  • использовать Browserify или webpack.

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

Забыл упомянуть, что это open source, поэтому жду ваших pull request'ов, вопросов по расширению функционала сборщика в issue. Продублирую прямую ссылку на репозиторий проекта.

P.S.: 28–29 марта в Новосибирске пройдёт крупнейшая IT-конференция за Уралом — СodeFest. На этой конференции у TARS будет отдельный стенд. Если приедете на CodeFest — подходите, задавайте вопросы.
Теги:автоматизация frontendcssscsslessstylusjavascripthtmlhandlebarsjadegulpopen sourcetars
Хабы: Блог компании 2ГИС Разработка веб-сайтов CSS JavaScript HTML
+31
52k 389
Комментарии 44
Похожие публикации
Ведущий разработчик под Android C++/Qt
2GISНовосибирскМожно удаленно
Разработчик iOS (senior)
2GISНовосибирскМожно удаленно
C++ разработчик в команду 3D-карты
2GISНовосибирскМожно удаленно
С++ разработчик в команду Navi
2GISНовосибирскМожно удаленно
Разработчик .NET/C#
2GISНовосибирскМожно удаленно
▇▅▄▅▅▄ ▇▄▅
Информация
Дата основания

25 мая 1999

Местоположение

Россия

Сайт

2gis.ru

Численность

1 001–5 000 человек

Дата регистрации

9 августа 2008

Блог на Хабре