Препроцессор Pug / Jade
Отредактировано: 31 Января 2023
Препроцессор Pug изначально назывался Jade, поэтому теперь можно встретить разные названия с одним и тем же описанием.
Комментарии (Comments)
// однострочный комментарий, преобразуется в html
//- однострочный комментарий pug, не отображается в html
//-
Блочный комментрарий.
Не преобразуется в html.
//
Блочный комментрарий.
Преобразуется в html.
Условные комментарии
//[if lt IE 9]><html lang="en" class="lt-ie9"><![endif]
//[if lt IE 9]><script src="js/html5.js"></script><![endif]
Доктайп (Doctype)
//- doctype html
<!DOCTYPE html>
//- doctype xml
<?xml version="1.0" encoding="utf-8" ?>
//- doctype transitional
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
//- doctype strict
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
//- doctype frameset
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
//- doctype 1.1
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
//- doctype basic
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd">
//- doctype mobile
<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.2//EN" "http://www.openmobilealliance.org/tech/DTD/xhtml-mobile12.dtd">
//- doctype plist
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
//- собственный doctype
doctype html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN"
При создании собственного доктайпа следует учесть что:
- тип закрывающих скобок />, > зависит от указанной спецификации XML или HTML
- если нет возможности использовать слово doctype, но указать его все же хочется, можно воспользоваться специальными опциями. Больше информации на оф сайте pug
var pug = require('pug'); var source = 'img(src="foo.png")'; pug.render(source); // => '<img src="foo.png"/>' pug.render(source, {doctype: 'xml'}); // => '<img src="foo.png"></img>' pug.render(source, {doctype: 'html'}); // => '<img src="foo.png">'
Тэги (Tags)
Pug подразумевает что каждая новая строка начинается с тега, а вложенность определяется с помощью отступов. Пробелы в начале и конце тегов удаляются.
ul | <ul>
li Item A | <li>Item A</li>
li Item B | <li>Item B</li>
li Item C | <li>Item C</li>
| </ul>
//- pug знает большинство самозакрывающихся элементов,
//- но если не знает, можно добавить /
img
svg
use(xlink:href='img/icons.svg#logo')/
//- для сокращения кода в некоторых случаях можно использовать уплотняющую запись преобразования
a: img
Атрибуты (Attributes)
Для записи id и классов можно использовать короткую запись:
.block Текст | <div class="block">Текст</div>
span.icon Текст | <span class="icon">Текст</span>
#block Текст | <div id="block">Текст</div>
p#chapter Текст | <p id="chapter">Текст</p>
Атрибуты похожи на html, однако их значения — это обычный JavaScript. Поэтому, если вы вставите туда выражение JS, оно сработает.
a(href='google.com') Google
a(class='button' href='google.com') Google
a(class='button', href='google.com') Google
//- обработка js, присвоение класса в зависимости от переменной
- var authenticated = true
body(class=authenticated ? 'authed' : 'anonim')
//- запись в несколько строк
input(
type='checkbox'
name='agreement'
checked
)
//- не стандартные атрибуты.
//- атрибуты со скобками указываются через , либо обрамляются кавычками
div(class='div-class', (click)='play()')
div(class='div-class' '(click)'='play()')
//- переменные в атрибутах
- var url = 'test.html',
url_2 = 'https://example.com/'
a(href='/' + url) Текст ссылки
a(href=url_2) Вторая ссылка
//- устаревший синтаксис интерполяции
a(href="/#{url}") Текст ссылки
//- если есть поддержка ES2015
- var btnType = 'info'
- var btnSize = 'lg'
button(type='button' class='btn btn-' + btnType + ' btn-' + btnSize)
button(type='button' class=`btn btn-${btnType} btn-${btnSize}`)
//- чтобы символы не экранировались используется !=
div(escaped="<code>")
div(unescaped!="<code>")
//- стили можно записывать как привычной строкой, так и объектом
a(style="color: 'red', background: 'green'")
a(style={color: 'red', background: 'green'})
//- классы можно записывать как привычной строкой, так и массивом
- var classes = ['foo', 'bar', 'baz']
a(class=classes)
//- атрибут class может быть продублирован
a.bang(class=classes class=['bing'])
//- атрибут также может быть объектом, сопоставляющим значения true и false
- var currentUrl = '/about'
a(class={active: currentUrl === '/'} href='/') Home | <a href="/">Home</a>
a(class={active: currentUrl === '/about'} href='/about') About | <a class="active" href="/about">About</a>
Логический тип данных
input(type='checkbox' checked) | <input type="checkbox" checked="checked" />
input(type='checkbox' checked=true) | <input type="checkbox" checked="checked" />
input(type='checkbox' checked=false) | <input type="checkbox" />
input(type='checkbox' checked=true.toString()) | <input type="checkbox" checked="true" />
//- если указан docktype html, pug использует краткую запись
doctype html | <!DOCTYPE html>
input(type='checkbox' checked) | <input type="checkbox" checked>
input(type='checkbox' checked=true) | <input type="checkbox" checked>
input(type='checkbox' checked=false) | <input type="checkbox">
input(type='checkbox' checked=true && 'checked')| <input type="checkbox" checked="checked">
Запись &attributes
Может использоваться для разбивания объекта с атрибутами на части. Символы при этом не экранируются, если используются вне миксинов.
div.foo(data-bar="foo")&attributes({'data-foo': 'bar'}) | <div class="foo" data-bar="foo" data-foo="bar"></div>
- var attributes = {};
- attributes.class = 'baz';
div.foo(data-bar="foo")&attributes(attributes) | <div class="foo baz" data-bar="foo"></div>
Case (Case)
Сокращенный вариант JS условия switch.
- var friends = 10
case friends
when 0
p you have no friends
when 1
p you have a friend
default
p you have #{friends} friends
//- как и в js можно пропускать значения
- var friends = 0
case friends
when 0
when 1
p you have very few friends
default
p you have #{friends} friends
//- для прерывания условия стоит использовать break
- var friends = 0
case friends
when 0
- break
when 1
p you have very few friends
default
p you have #{friends} friends
//- запись в 1 строку
- var friends = 1
case friends
when 0: p you have no friends
when 1: p you have a friend
default: p you have #{friends} friends
Код (Code)
Пуг позволяет обрабатывать JS код, разделяя его на 3 типа: буферизированный, небуферизированный, неэкранированный буферизированный.
Небуферизованный код ничего не добавляет к выводам и начинается с —
//- запись в строку
- for (var x = 0; x < 3; x++)
li item
//- запись блоком
-
var list = ["Uno", "Dos", "Tres",
"Cuatro", "Cinco", "Seis"]
each item in list
li= item
Буферизированный код начинается с =, он вычисляет JS и выводит результат. Для безопасности html символы экранируются.
p
= 'This code is <escaped>!'
//- инлайновая запись
p= 'This code is' + ' <escaped>!'
Неэкранированный буферизированный код начинается с !=, он вычисляет JS и выводит результат, без какой-либо экранизации, что не безопасно при использования пользователями.
p
!= 'This code is <strong>not</strong> escaped!'
//- инлайновая запись
p!= 'This code is' + ' <strong>not</strong> escaped!'
Условия (Conditionals)
Условия if, else if, else
- var user = { description: 'foo bar baz' }
- var authorised = false
#user
if user.description
h2.green Description
p.description= user.description
else if authorised
h2.blue Description
p.description.
User has no description,
why not add one...
else
h2.red Description
p.description User has no description
с оператором сравнения:
if var=='text'
p #{text}
условие unless (отрицательный if)
unless user.isAnonymous
p You're logged in as #{user.name}
Фильтры (Filters)
Фильтры позволяют использовать другие языки в шаблонах Pug. Все модули JSTransformer могут использоваться в качестве фильтров Pug. Популярные фильтры: :babel, :uglify-js, :scss и :markdown-it.
Можно использовать как уже существующие, так и собственные фильтры.
Для вставки опций в фильтры заключите их в скобки записав после вызова фильтра: :less(ieCompat=false).
Если вы хотите использовать CoffeeScript и Markdown (используя Markdown-it renderer) в шаблоне Pug, сначала убедитесь, что эти функции установлены:
$ npm install --save jstransformer-coffee-script
$ npm install --save jstransformer-markdown-it
Запись условия с фильтрами:
:markdown-it(linkify langPrefix='highlight-')
# Markdown
Markdown document with http://links.com and
```js
var codeBlocks;
```
script
:coffee-script
console.log 'This is coffee script'
Фильтры отображаются во время компиляции. Это делает их быстрыми, но это также означает, что они не могут поддерживать динамический контент или параметры.
Инлайновая запись
p
:markdown-it(inline) **BOLD TEXT**
p.
In the midst of a large amount of plain
text, suddenly a wild #[:markdown-it(inline) *Markdown*]
appeared.
Использование вместе с include
//- index.pug
doctype html
html
head
title An Article
body
include:markdown-it article.md
# article.md
This is an article written in markdown.
Вложенные фильтры
Фильтры применяются в обратном порядке.
script
:cdata-js:babel(presets=['es2015'])
const myFunc = () => `This is ES2015 in a CD${'ATA'}`;
Пользовательские фильтры
Cобственные фильтры добавляются через опцию filters.
options.filters = {
'my-own-filter': function (text, options) {
if (options.addStart) text = 'Start\n' + text;
if (options.addEnd) text = text + '\nEnd';
return text;
}
};
p
:my-own-filter(addStart addEnd)
Filter
Body
Включения (Includes)
Includes позволяет включать содержимое одного файла в другой. Если подключать не pug файл, то в результат вставится содержимое файла.
//- includes/head.pug
head
title My Site
script(src='/javascripts/jquery.js')
script(src='/javascripts/app.js')
//- includes/foot.pug
footer#footer
p Copyright (c) foobar
//- index.pug
doctype html
html
include includes/head.pug
body
h1 My Site
p Welcome to my super lame site.
include includes/foot.pug
//- включения можно комбинировать с фильтрами
//- index.pug
doctype html
html
head
title An Article
body
include:markdown-it article.md
//- article.md
# article.md
This is an article written in markdown.
Наследование (Inheritance: Extends and Block)
Pug поддерживает шаблонное наследование, реализуемое с помощью ключевых слов block и extends.
block — блоки кода, которые можно перезаписывать. В блок можно включить контент «по умолчанию», тогда он будет доступен на всех страницах к которым подключается, если его не перезапишут принудительно.
Так выглядит объявление блоков:
//- layout.pug
html
head
title My Site - #{title}
block scripts
script(src='/jquery.js')
body
block content
block foot
#footer
p some footer content
Команда extends добавляет данные из основного макета к новой странице.
Так выглядит дополнительный файл к которому подключается основная разметка блоков. Блок scripts перезаписывается, блок content заполняется данными, блок foot остается неизменным:
//- page-a.pug
extends layout.pug
block scripts
script(src='/jquery.js')
script(src='/pets.js')
block content
h1= title
- var pets = ['cat', 'dog']
each petName in pets
include pet.pug
//- pet.pug
p= petName
Block append / prepend
Изменение и расширение данных в блоках.
block name — блок с именем. При размещении на другой странице текста в блоке — значение по умолчанию затрется.
block appends name — добавить к блоку. При размещении на другой странице значение прибавится к значению по умолчанию.
block prepends name — указывает что в этом блоке надо обрабатывать условия appends блока.
//- layout.pug
block vars
- var text="Базовый текст"
block content
p #{text}
Пример изменения текста переменной в блоке
//- page.pug
extends layout.pug
block append vars
- var text="Измененный текст"
block prepend content
p #{text}
Интерполяция (Interpolation)
Строковая интерполяция, экранируемая
- var simpletext = "Все, что сказано три раза, становится истиной";
- var numeric = 42;
- var htmlstring = "<span>текст в html тегах</span>";
h1= simpletext
p The Ultimate Question of Life, the Universe, and Everything: #{numeric}
p Html теги без обработки: #{htmlstring}
p Можно добавлять любые js выражения #{simpletext.toUpperCase()}
p Можно не экранировать фигурные скобки #{'}'}!
p Для отображения конструкции переменной можно использовать экранирование \#{interpolation}
p или заключить в конструкцию повторно #{'#{interpolation}'}
Строковая интерполяция, не экранируемая
p !{simpletext}
Интерполяция тегов
p.
В параграфы текста могут быть встроены интерполяторы тегов pug. Например:
#[strong жирный текст] или
#[em текст курсивный] и даже
#[q(title="¡Hola Mundo!") теги с атрибутами]
Интерполяция и пробелы
p
| Если при написании параграфа использовать подобный вид интерполяции тегов
strong жирный текст
| или
em курсив
| слова будут склеиваться, т.к. пробелы удаляются.
p.
Чтобы пробелы оставались на месте, используйте интерполяцию тегов pug
#[strong respected] и #[em everybody]
Итерации (Iteration)
Pug поддерживает основные методы итераций: each, for и while.
each
//- простейшая запись
ul
each val in [1, 2, 3, 4, 5]
li= val
//- вывод индекса и значения
ul
each val, index in ['zero', 'one', 'two']
li= index + ': ' + val
//- перебор объекта вместо массива
ul
each val, index in {1:'one',2:'two',3:'three'}
li= index + ': ' + val
//- в качестве массива может выступать любая js сущность
- var values = [];
ul
each val in values.length ? values : ['There are no values']
li= val
//- можно добавить блок else, выводящийся если у массивов или объектов нет каких-либо значений
- var values = [];
ul
each val in values
li= val
else
li There are no values
for
- for (var x = 0; x < 3; x++)
li item
while
- var n = 0;
ul
while n < 4
li= n++
Миксины (Mixins)
Миксины позволяют создавать повторяющиеся блоки
//- декларация
mixin list
ul
li foo
li bar
li baz
//- использование
+list
+list
Преобразуются в функции и могут принимать аргументы:
mixin pet(name)
li.pet= name
ul
+pet('cat')
+pet('dog')
+pet('pig')
Можно устанавливать значения по умолчанию:
mixin elements(num = 10)
- for (var i = 0; i < num; i++)
p #{i+1} из #{num}
+elements() // выведет 10 элементов
+elements(3) // выведет 3 элемента
// Для длинных "значений по умолчанию" проще будет написать условие:
mixin text(sometext)
- sometext = sometext || 'длинный и очень интересный текст-рыба установленный по умолчанию...'
p #{sometext}
Миксины могут принимать блоки pug контента, для последующего преобразования:
//- если под миксином указан контент, он будет добавлен в позицию block
mixin article(title)
.article
.article-wrapper
h1= title
if block
block
else
p No content provided
+article('Hello world')
+article('Hello world')
p This is my
p Amazing article
Двойные блоки в миксине можно создавать так
// initialization
- blocks = {}
mixin set(key)
- blocks[key] = this.block
// mixin definition
mixin layout
block
.main
if blocks.main
- blocks.main()
else
//- Do nothing
.side
if blocks.side
- blocks.side()
else
//- Do nothing
+set('main')
+set('side')
p first mixin call
+layout
+set('main')
p Main
+set('side')
p Side
p second mixin call
+layout
+set('main')
p new main
+set('side')
p Second side
p third mixin call
+layout
+set('side')
p Third side
Миксины могут принимать неявные аргументы, которые берутся из аргументов переданных в миксин
mixin link(href, name)
//- attributes == {class: "btn"}
a(class!=attributes.class href=href)= name
+link('/foo', 'foo')(class="btn")
//- по умолчанию значения в атрибутах экранированы,
//- что бы избежать повторной экранизации используйте !=
Миксины можно использовать с &attributes
mixin link(href, name)
a(href=href)&attributes(attributes)= name
+link('/foo', 'foo')(class="btn")
Поскольку Pug пытается определить, является ли содержимое скобок атрибутами или аргументами, лучше использовать запись +link()(class="btn"), во избежании возможных ошибок. Синтаксис +link(class="btn" ) также действителен, но не рекомендован.
Можно указать бесконечное количество аргументов, используя синтаксис “rest arguments”
mixin list(id, ...items)
ul(id=id)
each item in items
li= item
+list('my-list', 1, 2, 3, 4)
Переменная в атрибуте миксина:
- var name = 'Joe'
+user(name)
Миксин в атрибуте миксина:
+someMixin(['nextMixin'])
Миксины в атрибуте миксина:
// определяем миксины
mixin header(leftside,rightside)
header
.head-left-wrap
for mixleft in leftside
+#{mixleft}
.head-right-wrap.top-wrap
for mixright in rightside
+#{mixright}
mixin first
...
mixin second
...
mixin third
...
// вызываем
+header(['first', 'second'],['third'])
Вызов миксина в атрибуте блока:
.box(style="background:"+randcolor)
Такой вызов может сработать если в названии миксина нет сложных символов вроде «-» и если миксин не очень сложный. Иногда проще заменить миксин js функцией:
-
function backimg(url) {
return "background: url('"+url+"')";
}
div(style=backimg("../img/img.jpg"))
Динамические миксины:
+#{mixinName}()
Пример использования динамического миксина:
// создаем миксин который будет генерировать динамические миксины
mixin dynMixin(name)
+#{name}()
Используется так:
// имеем какие-то миксины
mixin a
p AAA
mixin b
p BBB
mixin c
p CCC
-
// объявляем переменные
var choiseMixin;
var someCondition = 2;
//
switch (someCondition) {
case 1: choiseMixin = 'b'; break;
case 2: choiseMixin = 'c'; break;
default: choiseMixin = 'a';
}
+dynMixin(choiseMixin)
//- равнознчно: +#{choiseMixin}()
Note: Имя динамического миксина должно быть строкой (string).
Простой html текст (Plain Text)
Для вывода html без обработки шаблонизатором есть несколько способов:
Обернуть текст тегом
p Тут находится обычный <em>длинный</em> текст.
Использовать html занимающий всю строку
<html>
body
p Indenting the body tag here would make no difference.
p HTML itself isn't whitespace-sensitive.
</html>
С использованием префикса | (pipe)
p
| The pipe always goes at the beginning of its own line,
| not counting indentation.
Для больших html блоков стоит использовать символ . (точка)
script.
if (usingPug)
console.log('you are awesome')
else
console.log('use pug')
div
p This text belongs to the paragraph tag.
br
.
This text belongs to the div tag.
Массивы Pug / Jade
Обычный массив:
-
var count = [
'one',
'two',
'tree',
]
Массив с ключом:
-
var text_cognitive = [
{
name:'Амплификация',
text: 'вложение в достижение цели больших усилий, чем необходимо, попытка «убить муху кувалдой». Вариант — чрезмерно детальное планирование в условиях отсутствия в достаточном объёме исходных данных и наличия сильно влияющих на результат неопределённых или случайных факторов.'
},
{
name: 'Ускорение',
text: 'выполнение работы со скоростью большей, чем необходимо или даже допустимо.'
},
{
name: 'Опережение',
text: 'неоправданно раннее начало действий по достижению цели.'
},
{
name: 'Уклон в сторону поиска информации',
text: 'тенденция искать информацию даже тогда, когда она не влияет на действия или результат.'
},
]
Выводятся массивы через итерации или с указанием ключей. Миксин с рандомным выводом из массива:
mixin fish(type)
- var num = Math.floor(Math.random()*txt.length);
| #{txt[num][type]}
Указание ключа массива в качестве переменной:
// Массив
- var books = [{"id": 1}, {"id": 2},{"id": 3}]
// Первый вариант вывода по id
ul
for book in books
li= book.id
else
li sorry, no books!
// Второй вариант вывода по id
ul
- if (books.length)
-for (var i = 0; i < books.length; i++)
li= books[i].id
- else
li sorry, no books!