Previous remarks
Why do we introduce pug? What's so special about pug? There are some deeper nested pages that may appear nested, as shown in the following figure
In later maintenance and modification, carelessly missing an angle bracket, or the beginning and closing of a label does not correspond, will lead to the DOM structure confusion or even errors. So somebody invented HAML, and its biggest feature is to use indentation instead of paired tags. Inspired by HAML, pug implements javascript.
Pug Originally named Pug, it was a famous jade. Later, because of the trademark, it was changed to Pug, a pug. It's just a change of name. The grammar is the same as that of jade. In the past, Pug has its own shortcomings: poor portability, difficult debugging, poor performance, but it can speed up development efficiency. This article describes the pug template engine in detail
install
Installing pug with npm
$ npm install pug
But when you run the pug command, you are prompted that the pug command is not found
At this point, you need to install the pug command-line tool pug-cli
[Note] pug-cli must be installed globally, otherwise it will not compile properly
npm install pug-cli -g
When the pug command is run again, it is executed normally.
command line
Before you learn the basic grammar of pug, you first need to understand the use of the command line of pug
[Basic Compilation]
Enter the following into the file and name it index.pug
html
head
title aaa
body
The basic compilation can be achieved by typing pug index.pug on the command line
Generate an index.html in the current directory as a result of compiling index.pug
[sublime two-column settings]
However, this view is not convenient. Next, set sublime to two columns, and index.pug and index.html to the left and right columns for easy viewing.
[Automatic compilation]
Automatic compilation can be achieved by using pug-w function
After changing the index.pug file and saving it, the index.html file will be updated to the latest compiled file in real time.
[Standard HTML]
As shown above, by default, the HTML files compiled by pug are compressed. If you want to compile standard HTML files, you need to set the - P parameter
pug index.html -P
[Path setting]
If you do not want to enter a compiled HTML file in the current directory, but have the need to customize the directory, you need to set the - o parameter
In the following settings, index.html will be entered under directory a. If directory a does not exist, a new directory a will be created.
pug index.pug -o a
[Rename]
By default, the compiled HTML has the same name as the pug file. If you need to rename, you can do the following settings
With the following settings, you can set both paths and names
[Note] The path here must be established in advance, otherwise it will not succeed.
pug <xx.pug> <xx/xx.html>
Finally, the test.html file is saved in the templates directory
[bulk compilation]
Assume that all pug files in the href directory are compiled
Structural Grammar
The basic grammar of structure is introduced below.
Label
[Tree]
By default, the name of the HTML tag is written at the beginning of each line of text (or immediately after the white character part). Using indentation to represent nested relationships between tags can build a tree structure of HTML code.
ul
li Item A
li Item B
li Item C
[Inline]
To save space, Pug nested tags provide an inline syntax
a: img
[Self-closure]
Pug knows which elements are self-closing and can also explicitly declare that the tag is self-closing by adding / after the tag
img input img/ input/
[DOCTYPE]
DOCTYPE for HTML5 is written as follows
doctype html
You can also customize a doctype literal value
doctype html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN"
content
Pug provides three common ways to place content
[Pipeline Text]
This is the simplest way to add plain text to a template. Just add a | character in front of each line, which is often used as a "pipe" function in Unix-like systems, so it gets its name.
| Plain text can also include <strong>HTML</strong> Content.
p
| But it has to be a separate line.
[Text in Label]
In fact, this is the most common case. Text only needs to be separated by a space from the label name.
p plain text can also include < strong > HTML </strong > content, of course.
[Embedding large text]
Sometimes you may want to write a large block of text. For example, embedded scripts or styles. Just add one after the label.
[Note] Do not have spaces
script. if (usingPug) console.log('This is a wise choice.') else console.log('Please use Pug. ')
attribute
Label attributes are very similar to HTML syntax, and their values are normal JavaScript expressions. You can use commas as attribute separators, or you can use no commas.
a(href='baidu.com') Baidu = '\n' a(class='button' href='baidu.com') Baidu = '\n' a(class='button', href='baidu.com') Baidu
[Multi-line attributes]
If there are many attributes, you can write them in several lines.
input( type='checkbox' name='agreement' checked )
[Long Attribute]
If you have a long attribute and the JavaScript runtime engine supports the ES2015 template string, you can use it to write attribute values
input(data-json=` { "very": "Long", "data": true } `)
[Special Characters]
If attribute names contain some strange characters that may conflict with JavaScript syntax, they can be enclosed in "" or ". You can also use commas to split different attributes
div(class='div-class', (click)='play()') div(class='div-class' '(click)'='play()')
[Essential attributes]
By default, all attributes are escaped (that is, special characters are converted into escape sequences) to prevent attacks such as cross-site scripting attacks. If you want to use special symbols, you need to use!= instead of=
[Note] Unescaped cache code is dangerous. User input must be properly processed and filtered to avoid cross-site scripting attacks
div(escaped="<code>") div(unescaped!="<code>")
[Boolean Value]
In Pug, Boolean value attributes are mapped so that Boolean values (true and false) can be accepted. When there is no specified value, the default is true
input(type='checkbox' checked) = '\n' input(type='checkbox' checked=true) = '\n' input(type='checkbox' checked=false) = '\n' input(type='checkbox' checked=true.toString())
[In-line Style]
style attributes can be a string (like other common attributes) or an object
a(style={color: 'red', background: 'green'})
[Class and ID]
Classes can be defined using the. classname grammar, and ID s can be defined using the # idname grammar
Considering how common it is to use div as a label name, it is the default if the label name is omitted.
a.button .content ="\n" a#main-link #content
Label Embedding
Labels support a tag embedding approach in the following form
# [label name (label attribute) label content]
For inline tags, this is a relatively simple way to write
p. It's a long and boring passage. It's not over yet. Yes, it's very, very long. Suddenly a [strong words full of power], which is really difficult to [em neglect].
[Space adjustment]
Pug removes all the spaces before and after a tag by default, and tag embedding can handle the spaces before and after where they need to be embedded.
p | If I don't use embedded functions to write, some tags like strong strong He he em em | There may be unexpected results. p. If I use embedding, the spaces next to # [strong] and # [em] will make me much more comfortable.
Notes
[Single line commentary]
Single-line annotations are similar to JavaScript, but must be a separate line
// Some Contents p foo p bar
[No comment output]
Just add a bar and you can use no-output comments
//- This line will not appear in the result. p foo p bar
[Block Notes]
body // Write as many words as you like. It doesn't matter.
[Conditional Notes]
Pug has no special grammar to represent conditional comments. But since all lines that start with < are treated as plain text, it's okay to write an HTML-style conditional comment directly.
<!--[if IE 8]> <html lang="en" class="lt-ie9"> <![endif]--> <!--[if gt IE 8]><!--> <html lang="en"> <!--<![endif]-->
Logical grammar
The following is about the syntax of template logic
JS code
[No Output Code]
Use - to start a piece of code that does not output directly
- for (var x = 0; x < 3; x++) li item
[Output code]
Start with = a piece of code with output, which should be a JavaScript expression that can be evaluated. For security, it will be escaped by HTML
p = 'This code is <Transferred meaning> Now!' p= 'This code is <Transferred meaning> Now!'
[Unescaped output code]
Use!= Start a non-escape code with output. This will not do any escaping, so the input used to execute the user will be unsafe.
p != 'This passage <strong>No</strong> Transliterated!' p!= 'This passage' + ' <strong>No</strong> Transliterated!'
variable
[Content variables]
Use = or #{} to replace the true value of a variable
- var title = "On Dogs: Man's Best Friend";
- var author = "enlore";
- var theGreat = "<span>Transferred meaning!</span>";
h1= title
p #Written by {author} from the true feelings of the creation.
p This is safe:#{theGreat}
The code in # {and} is also evaluated, escaped, and ultimately embedded in the rendering output of the template
- var msg = "not my inside voice";
p This is #{msg.toUpperCase()}
Pug is smart enough to tell where the embedded expression ends, so you don't have to worry about having} in the expression, and you don't need additional escapes.
p Don't escape {'}'!
If you need to represent a {text, you can escape it, or you can generate it with embedded functionality
p Escaping works with \#{interpolation}
p Interpolation works with #{'#{interpolation}'} too!
Use!{} to embed text without escape into the template
- var riskyBusiness = "<em>I hope to pass through foreign teachers. Peter Find an English pen pal.</em>";
.quote
p Li Hua:!{riskyBusiness}
[Note] If user-supplied data is used directly, content that is not escaped may pose security risks
[Attribute Variables]
If you want to use variables in attributes, you need to do the following
- var url = 'pug-test.html'; a(href='/' + url) link = '\n' - url = 'https://example.com/' a(href=url) Another link
If ECMAScript 2015 template string is supported at JavaScript runtime, you can also simplify attribute values in the following ways
- var btnType = 'info' - var btnSize = 'lg' button(type='button' class='btn btn-' + btnType + ' btn-' + btnSize) = '\n' button(type='button' class=`btn btn-${btnType} btn-${btnSize}`)
& Attributes grammar converts an object into a list of attributes of an element
div#foo(data-bar="foo")&attributes({'data-foo': 'bar'}) - var attributes = {}; - attributes.class = 'baz'; div#foo(data-bar="foo")&attributes(attributes)
[Source of Variables]
There are three sources of variables: inside the pug file, command line parameters, and outside JSON files.
1. pug file interior
2. Command-line parameters
Using the -- obj parameter, you can follow parameters in the form of an object
3. External JSON files
Use - O to follow the path of a JSON file
Among the three ways, the variable priority in pug file is the most, while that in external JSON file and command line parameter is the same.
As shown below, both external JSON files and command-line parameterization exist, because -- obj is written after - w, and ultimately command-line parameterization prevails.
condition
The general form of parentheses in Pug's conditional judgment is optional, so the beginning can be omitted, and the effect is exactly the same. Similar to a regular JavaScript grammar
[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. The user did not add a description. Don't you write anything... else h2.red description p.description User Not Described
Pug also provides its antisense version unless
unless user.isAnonymous
p You have #Identity login of {user.name}.
[switch]
case is the abbreviation of JavaScript's switch instruction, and it takes the following form
- var friends = 10 case friends when 0 p You have no friends when 1 p You have a friend default p You have #friends} A Friend
In some cases, if you don't want to output anything, you can explicitly add a native break statement
- var friends = 0 case friends when 0 - break when 1 p You have very few friends. default p You have #friends} A Friend
Block expansion grammar can also be used
- var friends = 1 case friends when 0: p You have no friends when 1: p You have a friend default: p You have #friends} A Friend
loop
Pug currently supports two main iterations: each and while
[each]
This is Pug's preferred iteration
ul each val in [1, 2, 3, 4, 5] li= val
Index values can be obtained at iteration time
ul each val, index in ['0', 'One', 'Two'] li= index + ': ' + val
Ability to iterate over key values in objects
ul each val, index in {1:'One',2:'Two',3:'Three'} li= index + ': ' + val
The object or array used for iteration is just a JavaScript expression, so it can be the result of a variable, a function call, or something else.
- var values = []; ul each val in values.length ? values : ['No content'] li= val
You can also add an else block, which will be executed when there is no iterative value for the array and object
- var values = []; ul each val in values li= val else li No content
[Note] For can also be used as an alias for each
[while]
You can also use while to create a loop
- var n = 0; ul while n < 4 li= n++
Mix in
Mixing is a way to allow the reuse of an entire block of code in Pug
//- Definition mixin list ul li foo li bar li baz //- Use +list +list
Mixing can be compiled into functional form and passed some parameters.
mixin pet(name) li.pet= name ul +pet('cat') +pet('Dog') +pet('pig')
Mixing can also pass in an entire block of code like content.
mixin article(title) .article .article-wrapper h1= title if block block else p No content was provided. +article('Hello world') +article('Hello world') p This is me p A random article
Mixing can also implicitly get a parameter attributes from "tag properties"
You can also pass attributes parameters directly using the & attributes method
mixin link(href, name) a(class!=attributes.class href=href)= name +link('/foo', 'foo')(class="btn")
[Note]+link(class="btn") is equivalent to +link()(class="btn"), because Pug determines whether the content in parentheses is an attribute or a parameter. But it's better to use the following notation to explicitly pass empty parameters to ensure that the first pair of parentheses is always a list of parameters.
The rest arguments grammar can be used to represent the last number of parameters passed into the parameter list with varying lengths.
mixin list(id, ...items) ul(id=id) each item in items li= item +list('my-list', 1, 2, 3, 4)
File contains
Inclusion allows insertion of additional file contents
//- index.pug doctype html html include includes/head.pug body h1 My website p Welcome to my humble website. include includes/foot.pug
//- includes/head.pug head title My website script(src='/javascripts/jquery.js') script(src='/javascripts/app.js')
//- includes/foot.pug footer#footer p Copyright (c) foobar
If it is not a Pug file, it will only be introduced as text content.
//- index.pug doctype html html head style include style.css body h1 My website p Welcome to my humble website. script include script.js
/* style.css */ h1 { color: red; }
// script.js console.log('That's amazing!');
Document Inheritance
[Coverage]
Pug supports template inheritance using block and extends keywords. A code block called a "block" can be overwritten and replaced by sub-templates. This process is recursive.
Pug blocks can provide a default content, which is optional, of course
//- layout.pug html head
meta(charset="UTF-8") title My site - #{title} block scripts script(src='/jquery.js') body block content block foot #footer p Some footer content
Now extend the layout by simply creating a new file and using an extension as shown below to indicate the path of the inherited template. Now you can define several new blocks to override the corresponding "parent block" in the parent template. It's worth noting that because the foot block here is not redefined, it still outputs "some footer content"
//- pet.pug p= petName
//- 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
Similarly, a block can be overwritten and some new blocks can be provided. As shown below, content blocks now expose two new blocks, sidebar and primary, to be extended. Of course, its sub-templates can also override the entire content.
//- sub-layout.pug extends layout.pug block content .sidebar block sidebar p Nothing there? .primary block primary p Nothing there?
//- page-b.pug extends sub-layout.pug block content .sidebar block sidebar p Nothing there? .primary block primary p Nothing there?
[Expansion]
Pug allows you to replace (default behavior), prepend (add content to the head), or append (add content to the tail) a block. Assuming that there is a default script in the head block and that you want to apply it to each page, you can do the following
//- layout.pug html head block head script(src='/vendor/jquery.js') script(src='/vendor/caustic.js') body block content
Now suppose there is a page, which is a game written in JavaScript. Hope to put some game-related scripts in the same way as the default scripts, then simply append this block:
//- page.pug extends layout.pug block prepend head script(src='/vendor/three.js') block append head script(src='/game.js')
Block keywords can be omitted when using block append or block prepend:
//- page.pug extends layout.pug prepend head script(src='/vendor/three.js') append head script(src='/game.js')
Simple template
//- index.pug doctype html html head meta(charset="UTF-8") title= documentTitle each val in srcStyles link(href= baseStyle +'/' + val) body header.hd nav.hd-navbar.m-navbar.m-navbar_primary .hd-navbar-tel Contact information: #{tel} ul.hd-navbar-nav each val in mainNavItem li.Hnn-item.m-btn.m-btn_info a(href="#")= val section.main h1.main-title My Document p.main-content. //It's a long and boring passage. It's not over yet. Yes, it's very, very long. //Suddenly a [strong words full of power], which is really difficult to [em neglect]. footer.ft p Copyright (c) Blue Ideal of Small Match each val in srcScripts script(src=baseScript + '/' + val)
//- data.json { "documentTitle":"Test documentation", "tel":"400-888-8888", "mainNavItem":['Sign in','register','about','Help'], "baseStyle":'style', "srcStyles":['bootstrap.css','main.css'], "baseScript":'/js', "srcScripts":['jquery.js','app.js'] }