Всем привет! Давно хотел написать хорошую развернутую документацию про Html препроцессор Pug и вот этот момент настал. Я довольно давно использую Pug в своей работе и просто балдею от него . Я не понимаю, как можно сегодня верстать и писать обычный нативный Html-код. Это же так нудно и долго.
Вообще Pug это примерно тоже самое, что и препроцессор Sass. Я имею ввиду тут логику, хотя и сам синтаксис немного похож. Если вы поняли, чем хорош Sass, то Pug вам понравится еще больше.
Pug — это шаблонизатор Html, написанный на языке JavaScript для Node.js. После интерпретации сервером синтаксис Pug превращается в Нtml код. Старое название Pug — Jade. Подробности не знаю, но у разработчика возникли проблемы с авторскими правами и проект был переименован в Pug. Так что, если встретите упоминание Jade, знайте, что речь идет о Pug.
Начало работы
Для того, чтобы работать с Pug вам необходим установить Node.js. Скачать его можно с официального сайта nodejs.org. После установки открываем консоль (в Windows это комбинация клавиш Win + R) и вводим команду:
$ npm install pug
Дождитесь пока установщик завершит установку. Чтобы проверить, что все прошло удачно введите команду в консоли:
$ npm pug -v
Вам должно выдать последнюю версию Pug, например — 6.13.4.
Далее запускаем еще одну команду:
npm install pug-cli -g
Если все прошло без ошибок, то можно начинать работу.
Теперь, чтобы начать создайте файл с расширением .pug
, например, index.pug
с классическим содержанием Hello, World:
html(lang="ru")
head
meta(charset="utf-8")
title= "Учимся работать с шаблонизатором Pug"
body
h1 Hello, World!
Чтобы скомпилировать все это в Html необходимо в консоли перейти в директорию с данным файлом и запустить команду:
pug index.pug
После выполнения в этой же директории должен появиться файл index.html. Если откроем исходный код, то увидим, что весь код идет в одну строку и читать такой код довольно трудно. Чтобы исправить ситуацию запустим компиляцию Html с флагом --pretty
(перед командой двойной дефис).
В итоге получим в index.html
<html lang="ru">
<head>
<meta charset="utf-8"/>
<title>Учимся работать с шаблонизатором Pug</title>
</head>
<body>
<h1>Hello, World!</h1>
</body>
</html>
Можно также указать еще один флаг -w
, для слежки за изменениями в файлах *.pug.
pug --pretty -w index.pug
Вообще вы можете запустить команду pug --help
, чтобы посмотреть все доступные флаги и их сокращения.
Вообще хотелось бы отметить, что вряд ли кто-то использует данные команды в своей работе. Для того, чтобы комфортно работать с Pug используют сборки таск-менеджеры, например Gulp + плагин gulp-pug
. Но это отдельная тема для разговора. А мы давайте по подробнее разберем синтаксис pug.
Синтаксис Pug
Код Pug достаточно прост. Он не имеет угловых скобок и закрывающих тегов. Вложенность элементов определяется отступом — Tab или пробел.
Все это делает код лаконичным и легкочитаемым. И самое главное — ускоряется скорость написания кода.
Как было уже отмечено, синтаксис Pug чем-то напоминает синтаксис Sass:
- Вложенность определяется отступом (Tab или пробел)
- Классы задаются через точку (.)
- Id задаются через решетку (#)
- Однострочные комментарии задаются через //
Это в основном тот список, что нужно знать, чтобы начать работать с Pug. Сюда я бы добавил еще то, что атрибуты указываются в круглых скобках. Давайте теперь по порядку.
Теги, классы, идентификаторы
Давайте напишем небольшую разметку, например маркированный список.
ul
li Значение 1
li Значение 2
li Значение 3
li Значение 4
Html
<ul>
<li>Значение 1</li>
<li>Значение 2</li>
<li>Значение 3</li>
<li>Значение 4</li>
</ul>
Теперь добавим классы нашей разметке
ul.list
li.list__item Значение 1
li.list__item Значение 2
li.list__item Значение 3
li.list__item Значение 4
Html
<ul class="list">
<li class="list__item">Значение 1</li>
<li class="list__item">Значение 2</li>
<li class="list__item">Значение 3</li>
<li class="list__item">Значение 4</li>
</ul>
Добавим тегу ul
еще и идентификатор
ul.list#listItems
li.list__item Значение 1
li.list__item Значение 2
li.list__item Значение 3
li.list__item Значение 4
Html
<ul class="list" id="listItems">
<li class="list__item">Значение 1</li>
<li class="list__item">Значение 2</li>
<li class="list__item">Значение 3</li>
<li class="list__item">Значение 4</li>
</ul>
Если обратили внимание, текст элементу списка задается через пробел. Об этом поговорим более подробнее ниже.
Атрибуты
Для того, чтобы указать атрибут элементу разметки достаточно указать его в круглых скобках.
a(href="#") Ссылка
Html
<a href="#">Ссылка</a>
Если необходимо указать несколько атрибутов, то указываем их через запятую или пробел. Я больше предпочитаю пробел.
a(href="#", target="_blank") Ссылка
a(href="#" target="_blank") Ссылка
Html
<a href="#" target="_blank">Ссылка</a>
Если атрибутов много, то можно указать их многострочными линиями
input(
type='checkbox'
name='agreement'
checked
)
Если с атрибутами нам необходимо указать класс и/или индификатор, то указываются они до атрибутов.
Неправильно
a(href="#" target="_blank").link#linkHref Ссылка
Правильно
a.link#linkHref(href="#" target="_blank") Ссылка
Класс или Id можно указать также, как обычный атрибут.
a(class="link" id="linkHref" href="#" target="_blank") Ссылка
Текст
Как было уже сказано, текст элементу указывается через пробел.
p Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ex dolorum, assumenda animi, deleniti sunt...
Можно указать и через символ |
:
p
| Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ex dolorum, assumenda animi, deleniti sunt...
| Еще строка текста
Если у вас много текста, например, большой абзац, то есть вариант написать текст, указав точку в конце тега и через отступ вложенностью указываем текст. После точки не должно быть никаких символов и пробелов.
p.
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ex dolorum, assumenda animi, deleniti sunt tempore quaerat nihil eveniet unde perferendis, possimus est temporibus labore minus amet et? Voluptatem, molestiae tempora. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ex dolorum, assumenda animi, deleniti sunt tempore quaerat nihil eveniet unde perferendis, possimus est temporibus labore minus amet et? Voluptatem, molestiae tempora.Lorem ipsum dolor sit amet, consectetur adipisicing elit.
Также можно указывать обычные html теги внутри текста.
p Lorem ipsum dolor sit amet, <strong>consectetur</strong> adipisicing elit. Ex dolorum, assumenda animi, deleniti sunt…
Комментарии
Однострочные комментарии начинаются с символов — //
// Это комментарий в коде
Html
<!-- Это комментарий в коде -->
Если не хотите выводить комментарии в итоговом html коде, а в pug-файлах они нужны, то достаточно сразу после слешей добавить дефис.
//- А этот комментарий в html коде не выводится
Также можно выводить и многострочные комментарии.
//-
А это большой комментарий
Много много текста комментария и этот
многострочный комментарий в html
разметке не выводится.
//
А это большой комментарий.
Много много текста комментария и этот
многострочный комментарий выводится
в html разметке.
Html
<!--
А это большой комментарий.
Много много текста комментария и этот
многострочный комментарий выводится
в html разметке.
-->
Doctype
В Html5 doctype указывается следующим образом:
doctype html
Html
<!DOCTYPE html>
Если вы хотите указать doctype для различных типов документов, то можете почитать более подробно в официальной документации как это сделать.
Подключения (include)
Большим достоинством Pug является возможность подключения отдельных модулей кода. То есть можно выносить в отдельные фрагменты кода целые области сайта. Например, можно вынести отдельно header, sidebar, content, footer и все это собрать в одном индексном файле. Такой подход сделает наш код удобочитаемым и в случае правок достаточно изменить в одном месте.
//- index.pug
doctype html
html(lang="ru")
//- Include head
include ./components/head.pug
body
//- Include header
include ./components/header.pug
h1 Заголовок страницы
p Абзац, небольшое описание
//- Include footer
include ./components/footer.pug
//- Head.pug
head
meta(charset='UTF-8')
title Заголовок страницы
script(src="/js/jquery.js")
script(src="/js/scripts.js")
//- Header.pug
header.header
.logo Логотип сайта
//- Footer.pug
footer.footer
p Copyright текст
Html
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<title>Заголовок страницы</title>
<script src="/js/jquery.js"></script>
<script src="/js/scripts.js"></script>
</head>
<body>
<header class="header">
<div class="logo">Логотип сайта</div>
</header>
<h1>Заголовок страницы</h1>
<p>Абзац, небольшое описание</p>
<footer class="footer">
<p>Copyright текст</p>
</footer>
</body>
</html>
Как видим код файла index.pug намного удобнее читать и ориентироваться в нем.
Также есть возможность подключать отдельные файлы стилей и скриптов.
//- Include custom styles
style
include ./css/custom-style.css
//- Include custom scripts
script
include ./js/custom-script.js
Циклы
Циклы или итерации в Pug позволяют выполнять какие-то множественные операции, написав всего лишь несколько строк кода. Например, можно вывести список пунктов меню, написав код итерации следующим образом:
nav.menu
ul.menu__list
each name in ['Главная', 'О компании', 'Услуги', 'Каталог', 'Контакты']
li
a(href="#")= name
Html
<nav class="menu">
<ul class="menu__list">
<li><a href="#">Главная</a></li>
<li><a href="#">О компании</a></li>
<li><a href="#">Услуги</a></li>
<li><a href="#">Каталог</a></li>
<li><a href="#">Контакты</a></li>
</ul>
</nav>
Есть возможность также перебрать ключи в объекте.
nav.menu
ul.menu__list
each value, index in {'Главная' : 'home', 'О компании' : 'about', 'Услуги' : 'services', 'Каталог' : 'catalog', 'Контакты' : 'contact'}
li
a(href= "/" + value + ".html")= index
Html
<nav class="menu">
<ul class="menu__list">
<li><a href="/home.html">Главная</a></li>
<li><a href="/about.html">О компании</a></li>
<li><a href="/services.html">Услуги</a></li>
<li><a href="/catalog.html">Каталог</a></li>
<li><a href="/contact.html">Контакты</a></li>
</ul>
</nav>
Вместо each
вы можете использовать for
в качестве псевдонима.
Как написано в документации, Pug поддерживает 2 основных вида итераций — это each
и while
. Each мы рассмотрели, теперь давайте посмотрим на while
.
- var i = 0;
ul.list
while i < 4
li= i++
Html
<ul class="list">
<li>0</li>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
Как видим, циклы это обычный JavaScript и ничего сложного тут нет, хватает всего лишь знаний основ данного языка программирования.
Миксины
Миксины позволяют создавать многократно повторяемые блоки кода. Это практически тоже самое, что и функция в языке программирования.
Объявление миксина начинается с ключевого слова mixin
, затем через пробел название миксина.
//- Mixin declaration
mixin listItems
ul.list-items
li One
li Two
li Three
li Four
li Five
//- Call mixin
+listItems
<ul class="list-items">
<li>One</li>
<li>Two</li>
<li>Three</li>
<li>Four</li>
<li>Five</li>
</ul>
Как видим, чтобы вызвать миксин необходимо поставить символ +
и без пробела написать название миксина. Если код миксина выносится в отдельный файл, то в том документе, где он вызывается необходимо его подключить через include
в верхней части документа.
Аргументы
Миксин может принимать также и аргументы.
//- Mixin declaration
mixin listItem(name)
li= name
//- Call mixin
ul.list-items
+listItem("One")
+listItem("Two")
...
+listItem("Five")
У нас есть также возможность установить значения аргументов по умолчанию. Делается это примерно также, как и установка параметров функции по умолчанию в ES6 (ECMAScript 6).
//- Mixin declaration
mixin article(title="Заголовок по умолчанию")
article.article
h1= title
//- Call mixin
+article()
Блоки миксинов
Миксины могут выступать в качестве блоков или контейнеров, которые могут содержать различный контент.
//- Mixin declaration
mixin article(title)
article.article
h1= title
if block
block
else
p Нет контента для отображения
//- Call mixin
+article("Заголовок страницы")
p Lorem ipsum dolor sit amet, consectetur adipisicing elit.
p Lorem ipsum dolor sit amet, consectetur adipisicing elit.
<article class="article">
<h1>Заголовок страницы</h1>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit.</p>
</article>
Атрибуты
Помимо аргументов миксины также могут принимать и атрибуты.
mixin link(href, name)
//- attributes == {class: "link-btn"}
a(class!= attributes.class href= href)= name
+link('/link.html', 'Название ссылки')(class="link-btn")
Обратите внимание, что атрибуты выводятся через символ !=
. Дело в том, что спец. символы экранируются автоматически и чтобы избежать повторного экранирования мы используем знак !=
. Если вы не хотите экранировать символы, то используйте символ =
. Наиболее подробнее об этом можете почитать в документации.
А вот так можно вывести произвольное количество атрибутов:
mixin link(href, name)
// Произвольные атрибуты
a(href= href)&attributes(attributes)= name
+link('link.html', 'Название ссылки')(target="_blank" data-type="link")
Неизвестное количество аргументов
В миксинах Pug есть возможность передавать неизвестное количество аргументов, используя синтаксис «rest arguments«.
mixin list(id, ...items)
ul(id= id)
each item in items
li= item
+list('myList', 1, 2, 3, 4)
<ul id="myList">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
</ul>
Наследование шаблонов
Pug позволяет создавать шаблоны страниц, то есть в последующем любую страницу сайта можно создать по заранее созданному шаблону. Таких шаблонов может быть сколько угодно.
Шаблон Pug
//- layout.pug
block variables
doctype html
html(lang="ru")
head
title #{title}
block scripts
script(src='/jquery.js')
body
block content
block footer
footer.footer
p Copyright
Страницы Pug
//- index.pug
//- Главная страница
extends ./layout.pug
block variables
- var title = 'Главная страница'
block content
h1= title
p Главная страница сайта... Lorem ipsum dolor sit amet, consectetur adipisicing elit...
//- about.pug
//- О нас
extends ./layout.pug
block variables
- var title = 'О нас'
block content
h1= title
p О нашей компании... Lorem ipsum dolor sit amet, consectetur adipisicing elit...
Наследование шаблона происходит через ключевое слово extends
, далее через пробел указываем относительный путь до файла шаблона. Расширение файла *.pug
указывать не обязательно, Pug подставит его сам.
Области в которых нам необходимо вывести содержимое обозначаются словом block
с указанием имени блока через пробел, например, block head
. Содержимое блока на страницах заменяется дочерним шаблоном. Этот процесс является рекурсивным.
Из примера выше видим, что страницы «Главная» и «О нас» сделаны по одному шаблону. Ориентироваться в коде на таких страницах намного проще, ведь здесь только основное его содержимое.
Содержимое блока в шаблоне может быть и по умолчанию, но это не обязательно. Например, в шаблоне выше у нас существуют блоки scripts
и footer
с содержимым по умолчанию. На созданных страницах мы их не выводили, так как их содержимое выведется по умолчанию. Если не нужен контент по умолчанию, то оставляем блок просто пустым, например block footer
.
Содержимое блока полностью заменяется дочерним шаблоном, но что, если нам необходимо просто добавить что-либо к содержимому по умолчанию?
Block append / prepend
В примере выше у нас есть блок scripts
в секции head
, в котором указано подключение библиотеки jquery. Теперь представьте, что на определенной странице нам необходимо подключить еще один скрипт в блоке scripts
. Можно поступить следующим образом:
//- index.pug
extends layout.pug
block variables
- var title = 'Главная страница'
block scripts
script(src='/jquery.js')
script(src='/scripts.js')
block content
То есть указывать везде заново подключение jquery, но можно поступить проще. Добавить в блок scripts
через append
или prepend
.
//- index.pug
extends layout.pug
block variables
- var title = 'Главная страница'
block append scripts
script(src='/scripts.js')
block content
block prepend
— добавляет в начало списка, block append
— в конец списка. Вообще слово block
можно опустить, например — append scripts.
Он является не обязательным.
Вообще следует отметить, что создание шаблонов — это мощная функция, которая позволяет разделять наш проект на простые и сложные конструкции страниц. Так что пользуйтесь данной возможностью.
Условия
Pug работает на основе JavaScript поэтому есть возможность использовать условия при написании кода, как и в любом другом языке программирования.
Фигурные скобки можно опустить, как и символ -
(если вы используете 2-ю версию Pug).
nav.menu
ul.menu__list
- var i = 1;
each name in ['Главная', 'О нас', 'Контакты']
if i == 1
li.active
a(href="#")= name
else
li
a(href="#")= name
Можно также использовать оператор условного если unless
, что является отрицанием if
. Следующие условия будут эквивалентны.
unless user.isAnonymous
p You're logged in as #{user.name}
if !user.isAnonymous
p You're logged in as #{user.name}
Интерполяция
В Pug существует несколько видов вывода переменных. Давайте обратимся к примеру.
- var title = "ООО Рога и копыта";
- var name = "Владимир";
- var state = "старший менеджер";
h1= title
p Компанию "#{title}" представляет #{state} !{name}
<h1>ООО Рога и копыта</h1>
<p>Компанию "ООО Рога и копыта" представляет старший менеджер Владимир</p>
Если нужно вывести переменную в строке (например в тексте) я использую вывод #{название_переменной}
или !{название_переменной}
, в остальных случаях — =название_переменной
.
Более подробнее про вывод переменных можете почитать в документации.
Конструкция Case
Оператор case
работает также, как и в JavaScript switch case
. Если вы знакомы с этим понятием в JavaScript, то понять вам будет проще. Впрочем, ничего сложного тут нет.
- var friends = 10
case friends
when 0
p вы не имеете друзей
when 1
p вы имеете одного друга
default
p вы имеете #{friends} друзей
<p>вы имеете 10 друзей</p>
Можно записать данный код более компактно.
- var friends = 10
case friends
when 0: p вы не имеете друзей
when 1: p вы имеете одного друга
default: p вы имеете #{friends} друзей
Если не хотим ничего выводить, то добавляем небуферизированный оператор break
.
- var friends = 0
case friends
when 0
- break
when 1
p you have very few friends
default
p you have #{friends} friends
Код
Pug позволяет использовать встроенный JavaScript код в ваших шаблонах. Существует 3 вида кода: небуферизированный, буферизированный и неэкранированный буферизированный.
Небуферизированный код
Небуферизированный код ничего не выводит и начинается с символа -
.
ul
- for (var x = 0; x < 3; x++)
li item
Небуферизированный код можно указать и как блок.
-
var list = ["One", "Two", "Three"]
ul
each item in list
li= item
Буферизированный код
Буферизированный код вычисляет выражение JavaScript и выводит его результат. Начинается он со знака =
. В целях безопасности Html код перед выводом экранируется.
p
= 'Строка текста с тегом <strong>выделения</strong>.'
Выведет…
<p>Строка текста с тегом <strong>выделения</strong>.</p>
Неэкранированный буферизированный код
Неэкранированный буферизированный код также выводит результат выражения JavaScript, но спец. символы он не экранирует. Начинается с символа !=
. Использование такого кода не безопасно.
p
!= 'Строка текста с тегом <strong>выделения</strong>.'
<p>Строка текста с тегом <strong>выделения</strong>.
Фуф… Не маленькая получилась статья. На этом скорее всего завершу. Пока писал данную документацию сам узнал много чего новенького .
На этом все… Все спасибо за терпение (если дочитали до конца ). Пишите комменты, с удовольствием отвечу на вопросы. До встречи в других постах!