pug template engine (original jade)

Keywords: Javascript Attribute JSON JQuery

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']
}

Posted by youropensource on Tue, 11 Jun 2019 14:51:16 -0700