Гайды

Шаблонизатор PUG

Данный гайд не описывает все возможности Pug и все варианты использования этих возможностей. Задача данного гайда дать необходимый минимум знаний для работы в Лиге А, показать пример того, как пишем мы и то, как мы хотим, чтобы писали вы, начиная работу в нашей команде.

Что такое Pug?

Pug — это шаблонизатор и Html-препроцессор, написанный на JavaScript для платформы Node.js с целью ускорения верстки.

После интерпретации синтаксис Pug превращается в Нtml-код. Старое название Pug — Jade. Так что, если вы встретите упоминание Jade, знайте, что речь идет о Pug. Pug — это инструмент, который позволяет проще писать разметку, делить её на компоненты и связывать с данными.

Проблемы, с которыми мы сталкиваемся в вёрстке и которые нам помогает решить Pug.

  1. Верстая на Html, мы постоянно сталкиваемся с необходимостью копировать определённые блоки на странице, будь то крупные, такие как head, header, footer и т.д., в зависимости от проекта, и небольшие повторяющиеся блоки, такие как кнопки, карточки товаров и т.д. Pug дает нам возможность создавать шаблоны и компоненты и размещать их в нужном месте на проекте. Это позволяет избегать ошибок при копировании.

  2. Верстая на Html, при изменениях в каком-либо блоке (добавление или изменение шрифта в head, добавление, изменение или смена порядка пунктов меню в header или footer, добавление классов и т.д.) нам придётся менять их вручную на каждой странице. Использование шаблонов и компонентов позволит нам внести изменение только в шаблоне или компоненте, и они применятся везде, где они используются на проекте. Это очень сильно ускорит разработку и не даст нам возможности пропустить изменения в каком-либо месте на проекте.

  3. При большом количестве контента и верстке на Html наша разметка очень сильно разрастается. Это усложняет чтение кода, поиск нужных элементов и, как следствие, усложняет поддержку проекта. Используя Pug, мы можем поделить наш код на шаблоны и компоненты, которые подключим к странице и которые намного проще редактировать, так как они находятся в отдельных файлах.

  4. Синтаксис Pug очень прост, в нём нет открывающихся и закрывающихся тегов. Вложенность регулируется за счёт отступов. Это помогает исключить многие ошибки при разработке.

  5. Используя Html, мы ограничены в возможностях. В Pug можно встраивать JavaScript код. Использование переменных, циклов, условий и других конструкций делают Pug очень вариативным инструментом в разработке.

  6. Используя Html, мы не можем разделить данные и представление. Pug даёт нам возможность это сделать.

Синтаксис Pug

Теги

В Pug нет закрывающих тегов. Тег указывается только один раз и его не нужно экранировать.

Для определения вложенности тегов Pug использует строгую табуляцию (или отступы).

Pug

ul
  li
    p Lorem
  li
    p Lorem
  li
    p Lorem

Html

<ul>
  <li>
    <p>Lorem</p>
  </li>
  <li>
    <p>Lorem</p>
  </li>
  <li>
    <p>Lorem</p>
  </li>
</ul>

Классы и идентификаторы

Классы в Pug задаются через точку (.)

Идентификаторы в Pug задаются через решетку (#)

Pug

p.text-item#text Lorem

Html

<p class="text-item" id="text">Lorem</p>

Атрибуты

Атрибуты в Pug задаются в круглых скобках ().

Pug

a(href="#") Lorem

Html

<a href="#">Lorem</a>

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

Pug

a(href="#", target="_blank") Lorem

Html

<a href="#" target="_blank">Lorem</a>

Если атрибутов много, то их можно распределить по нескольким строкам.

Pug

a(
  href="#",
  target="_blank",
  aria-label="Ссылка",
  data-href="link"
) Lorem

Html

<a href="#" target="_blank" aria-label="Ссылка" data-href="link">Lorem</a>

Если с атрибутами вам необходимо указать класс и/или идентификатор, то они указываются до атрибутов.

Pug

a.link-item#link(href="#", target="_blank") Lorem

Html

<a class="link-item" id="link" href="#" target="_blank">Lorem</a>

Текст

Для вложения контента внутрь тегов существуют следующие варианты:

Инлайн-стиль. Весь контент располагается сразу после обозначения тега.

Pug

p Lorem ipsum dolor sit amet consectetur adipisicing elit.

Html

<p>Lorem ipsum dolor sit amet consectetur adipisicing elit.</p>

Pipe-стиль. Контент можно располагать в несколько строк. Каждая строка начинается с символа (|). Этот стиль является основным в Лиге.

Pug

p
  | Lorem ipsum dolor sit amet consectetur adipisicing elit.
  | Tempore suscipit possimus officia ea illo tempora doloremque
  | provident earum illum nemo ad excepturi similique,
  | repudiandae reiciendis beatae voluptates ducimus aperiam aspernatur!

Html

<p>
  Lorem ipsum dolor sit amet consectetur adipisicing elit.
  Tempore suscipit possimus officia ea illo tempora doloremque
  provident earum illum nemo ad excepturi similique,
  repudiandae reiciendis beatae voluptates ducimus aperiam aspernatur!
</p>

Блочный стиль. Контент можно располагать в несколько строк. Для этого сразу после тега указывается точка (.). Дополнительные символы (|) использовать не нужно.

Pug

p.
  Lorem ipsum dolor sit amet consectetur adipisicing elit.
  Tempore suscipit possimus officia ea illo tempora doloremque
  provident earum illum nemo ad excepturi similique,
  repudiandae reiciendis beatae voluptates ducimus aperiam aspernatur!

Html

<p>
  Lorem ipsum dolor sit amet consectetur adipisicing elit.
  Tempore suscipit possimus officia ea illo tempora doloremque
  provident earum illum nemo ad excepturi similique,
  repudiandae reiciendis beatae voluptates ducimus aperiam aspernatur!
</p>

Интерполяция тегов

Pug позволяет использовать внутри тега с текстом обычные Html-теги.

Pug

p Lorem ipsum dolor sit <a href="#">amet consectetur</a> adipisicing elit.

Html

<p>Lorem ipsum dolor sit <a href="#">amet consectetur</a> adipisicing elit.</p>

Но в этом случае теряется смысловая семантика использования препроцессора. Ведь мы смешиваем обычный Html с синтаксисом Pug.

Избежать этого поможет конструкция #[тег контент].

Pug

p Lorem ipsum dolor sit #[a(href="#") amet consectetur] adipisicing elit.

Html

<p>Lorem ipsum dolor sit <a href="#">amet consectetur</a> adipisicing elit.</p>

Также можно использовать Pipe-стиль.

Pug

p
  | Lorem ipsum dolor sit
  a(href="#") amet consectetur
  | adipisicing elit.

Html

<p>Lorem ipsum dolor sit<a href="#">amet consectetur</a>adipisicing elit.</p>

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

Управление пробельными символами

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

Использование инлайн стиля и конструкции #[тег контент].

Pug

p Lorem ipsum dolor sit #[a(href="#") amet consectetur] adipisicing elit.

При использовании Pipe-стиля можно добавлять пробельные символы там, где это необходимо.

Pug

p
| Lorem ipsum dolor sit
|
a(href="#") amet consectetur
|
| adipisicing elit.

Также можно добавить пробельные символы и другим способом.

Pug

p
| Lorem ipsum dolor sit
=" "
a(href="#") amet consectetur
=" "
| adipisicing elit.

Можно использовать Html-мнемоник - неразрывный пробел  .

Pug

p
| Lorem ipsum dolor sit 
a(href="#") amet consectetur
|  adipisicing elit.

Но данный вариант свяжет ссылку с символами до и после неё.

Добавление инлайн стилей и скриптов

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

Pug

style.
  .some-section {
    color: red;
  }

script.
  if (isSunnyDay) {
    alert("I am happy");
  } else {
    alert("I am sad");
  }

Html

<style>
  .some-section {
    color: red;
  }
</style>

<script>
  if (isSunnyDay) {
    alert("I am happy");
  } else {
    alert("I am sad");
  }
</script>

Комментарии

Для добавления комментариев в Pug перед текстом комментария надо добавить два слеша (//).

Pug

// Lorem ipsum dolor sit amet consectetur adipisicing elit.

Html

<!-- Lorem ipsum dolor sit amet consectetur adipisicing elit. -->

Ниже приведён пример многострочного комментария.

Pug

//
  Lorem ipsum dolor sit amet consectetur adipisicing elit.
  Amet molestias accusamus ad porro voluptatum labore excepturi
  suscipit ex minus a quia, inventore, neque nemo aut, illum commodi.
  Itaque, facere rem.

Html

<!--
  Lorem ipsum dolor sit amet consectetur adipisicing elit.
  Amet molestias accusamus ad porro voluptatum labore excepturi
  suscipit ex minus a quia, inventore, neque nemo aut, illum commodi.
  Itaque, facere rem.
-->

Чтобы комментарии были только в Pug и не попадали в итоговый Html, сразу после слешей надо добавить дефис (//-).

Pug

//- Lorem ipsum dolor sit amet consectetur adipisicing elit.

Использование JavaScript в Pug

Переменные

В Pug, как и в JavaScript, переменные объявляются с помощью ключевого слова const. Но в Pug перед переменной необходимо ставить символ дефиса (-).

Pug

- const text = "Text"
- const number = 69
- const array = ["Text", "One more text"]
- const object = {
    page: "main",
    href: "#"
  }

Интерполяция переменных

В Pug есть различные способы вывода переменных.

Pug

- const text = "Text"
h1= text
p Written with love by #{text}

Такие варианты будут работать с экранированием. Поэтому если нам понадобится вставить теги или Html-мнемоники, мы получим нет тот результат, который ожидали.

Pug

- const textWithMnemonics = "text text"
- const textWithTags = "<span>text</span>"
h1= textWithMnemonics
p Written with love by #{textWithTags}

Html

<h1>text&nbsp;text</h1>
<p>Written with love by <span>text</span></p>

Чтобы избежать экранирования, необходимо использовать символ восклицательного знака (!)

Pug

- const textWithMnemonics = "text text"
- const textWithTags = "<span>text</span>"
h1!= textWithMnemonics
p Written with love by !{textWithTags}

Html

<h1>text text</h1>
<p>Written with love by text</p>

Условия

Условный синтаксис Pug очень похож на Javascript, но в отличие от Javascript в Pug при использовании условий не нужны скобки.

Pug

- const condition = true
if condition
  p condition is true
else
  p condition is false

Html

<p>condition is true</p>

При использовании операторов сравнения с нечисловым значением необходимо применять кавычки, иначе Pug будет искать переменную с таким именем.

Pug

- const page = "index"

Неверно

if page === index

В примере выше Pug будет искать переменную index, которой нет, и это вызовет ошибку

Верно

if page === "index"

Циклы

Циклы используются для выполнения одинакового действия определённое количество раз. Pug поддерживает два вида итерации: each и while. Мы рассмотрим только each, так как while не используем.

Pug

- const names = ["Иван", "Дмитрий", "Наталия"]
ul
  each item in names
    li= item

Html

<ul>
  <li>Иван</li>
  <li>Дмитрий</li>
  <li>Наталия</li>
</ul>

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

Pug

- const names = ["Иван", "Дмитрий", "Наталия"]
  ul
    each item, index in names
      li= `Под индексом ${index} в массиве расположено имя ${item}`

Html

<ul>
  <li>Под индексом 0 в массиве расположено имя Иван</li>
  <li>Под индексом 1 в массиве расположено имя Дмитрий</li>
  <li>Под индексом 2 в массиве расположено имя Наталия</li>
</ul>

Обратите внимание на то, что мы используем шаблонные строки, а не конкатенацию.

Pug

li= `Под индексом ${index} в массиве расположено имя ${item}`

// Вместо:

li= "Под индексом " + index + " в массиве расположено имя " + item

Также с помощью цикла each мы можем перебирать и объекты.

Pug

-
  const users = {
    1: {
      name: "Иван",
      age: "30"
    },
    2: {
      name: "Дмитрий",
      age: "27"
    }
  }

each value in users
  div
    p= `Имя пользователя: ${value.name}`
    p= `Возраст пользователя: ${value.age}`

Html

<div>
  <p>Имя пользователя: Иван</p>
  <p>Возраст пользователя: 30</p>
</div>
<div>
  <p>Имя пользователя: Дмитрий</p>
  <p>Возраст пользователя: 27</p>
</div>

Мы можем получить и ключ объекта, указав его через запятую.

Pug

-
  const users = {
    1: {
      name: "Иван",
      age: "30"
    },
    2: {
      name: "Дмитрий",
      age: "27"
    }
  }

each value, key in users
  div
    p= `По ключу ${key} в объекте users находится объект со следующими значениями:`
    p= `Имя пользователя: ${value.name}`
    p= `Возраст пользователя: ${value.age}`

Html

<div>
  <p>По ключу 1 в объекте users находится объект со следующими значениями:</p>
  <p>Имя пользователя: Иван</p>
  <p>Возраст пользователя: 30</p>
</div>
<div>
  <p>По ключу 2 в объекте users находится объект со следующими значениями:</p>
  <p>Имя пользователя: Дмитрий</p>
  <p>Возраст пользователя: 27</p>
</div>

Миксины в Pug

Mиксины

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

Объявление миксина начинается с ключевого слова mixin, а затем через пробел указывается имя миксина и круглые скобки (). Их мы указываем всегда, независимо от того, будет ли принимать миксин какие-либо параметры или нет.

Pug

mixin button()
  button.button(type="button") Button

Вызов миксина начинается со знака плюс (+), затем имя миксина, затем круглые скобки (). Их мы указываем всегда, независимо от того, передаём мы какие-либо параметры или нет.

Pug

mixin button()
  button.button(type="button") Button
+button()
+button()
+button()

Html

<button class="button" type="button">Button</button>
<button class="button" type="button">Button</button>
<button class="button" type="button">Button</button>

При создании миксина в круглых скобках мы можем указать аргументы которые будет принимать в себя миксин. И с помощью интерполяции мы сможем использовать переданные аргументы как значение для элементов внутри миксина.

Pug

mixin button(text)
  button.button(type="button")= text

+button(Button-1)
+button(Button-2)
+button(Button-3)

Html

<button class="button" type="button">Button-1</button>
<button class="button" type="button">Button-2</button>
<button class="button" type="button">Button-3</button>

Атрибуты в миксине (&attributes(attributes))

Чтобы не усложнять миксин передачей в него различных атрибутов, в Pug существует конструкция &attributes(attributes). Она добавляется при создании миксина к тому тегу, к которому необходимо будет добавлять атрибуты при вызове миксина. Это позволяет сделать миксин более универсальным и гибким, так как при создании мы не можем точно знать, какие параметры нам могут понадобиться при вызове в будущем.

Pug

// Неверно:
mixin button(text, type, ariaLabel)

button.button(type=type, aria-label=ariaLabel)= text
+button("Button-1", "button", "Button-1")
+button("Button-2", "submit", "Button-2")
+button("Button-3", "reset", "Button-3")

// Верно:
mixin button(text)
  button.button&attributes(attributes)= text

+button("Button-1")(type="button", aria-label="Button-1")
+button("Button-2")(type="submit", aria-label="Button-2")
+button("Button-3")(type="reset", aria-label="Button-3")

Обратите внимание, что класс .button мы оставляем в миксине, так как он постоянный.

Важно

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

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

В разработке мы стараемся создавать миксины принимающие параметрами именно объект, а не просто строки. Некоторые параметры будут не всегда использоваться и вызов миксина может стать нечитаемым https://skr.sh/sCWmecxJ8f2?a. Такой код не только тяжело читать и поддерживать, нужно ещё время на понимание того, что там происходит, и велика вероятность ошибки при его использовании. Исключением являются миксины, в которых все параметры передаются всегда (папка utils в сборке Лиги).

Сборка Лиги А

Файловая структура Pug в сборке Лиги

pug
  components
    base
    blocks
    mixins
    modals
    utils
  pages

В папке pug находятся две папки components и pages

В папке pages находятся все страницы проекта

В папке components находятся папки:

  • base папка с базовыми элементами

  • blocks папка с крупными компонентами страницы(section)

  • mixins папка с более мелкими переиспользуемыми компонентами

  • modals папка с модальными окнами

  • utils папка со вспомогательными миксинами

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