Jade - HTML Template Engine from Node.js

Posted by fael097 on Sun, 11 Aug 2019 20:30:25 +0200

Original Link: http://www.cnblogs.com/smallstupidwife/p/4823511.html

Jade is a high-performance template engine that is well received Haml Influences, which are implemented in JavaScript and are available for Node Use.

demo

You can go online Try Jade.

Characteristic

  • Client support
  • Code is highly readable
  • Flexible indentation
  • Block Expansion
  • Mixins
  • Static Inclusion
  • Property override
  • Security, default code is escaped
  • Context Error Reporting at Runtime and at Edit
  • Compile jade templates from the command line
  • HTML5 mode (use!!! 5 document type)
  • Cache in memory (optional)
  • Merge dynamic and static label classes
  • Trees can be modified through filters
  • Template Inheritance
  • Native Support Express JS
  • Enumerating objects, arrays, or even objects that cannot be enumerated through an each
  • Block Comments
  • Label without prefix
  • AST Filters
  • Filter
  • Emacs Mode
  • Vim Syntax
  • TextMate Bundle
  • Coda/SubEtha syntax Mode
  • Screencasts
  • html2jade Converter

Other implementations

jade has other language implementations that can unify front-end and back-end rendering:

install

npm install jade

Browser support

Compiling Jade into a single file for browsers requires simple execution:

make jade.js

If you have installed uglify JS (npm install uglify-js), you can execute the following command and it will generate all the files.In fact, every official version helps you do this.

make jade.min.js

By default, Jade organizes templates into line numbers such as u.lineno = 3 for debugging purposes.When used in browsers, you can remove this by passing an option {compileDebug: false}.The following template

p Hello #{name}

Will be translated into the following functions:

function anonymous(locals, attrs, escape, rethrow) {
  var buf = [];
  with (locals || {}) {
    var interp;
    buf.push('\n<p>Hello ' + escape((interp = name) == null ? '' : interp) + '\n</p>');
  }
  return buf.join("");
}

By using Jade's. /runtime.js, you can use these precompiled templates in your browser without using Jade. All you need to do is use the tool functions in runtime.js, which are placed in jade.attrs, jade.escape.Pass the option {client: true} to Jade.compile(), and Jade places references to these help functions in jade.attrs, jade.escape.

function anonymous(locals, attrs, escape, rethrow) {
  var attrs = jade.attrs, escape = jade.escape, rethrow = jade.rethrow;
  var buf = [];
  with (locals || {}) {
    var interp;
    buf.push('\n<p>Hello ' + escape((interp = name) == null ? '' : interp) + '\n</p>');
  }
  return buf.join("");
}

API

var jade = require('jade');

// Compile a function
var fn = jade.compile('string of jade', options);
fn(locals);

option

  • Self) Use the self namespace to hold local variables. (Default is false)
  • locals. Local variable object
  • Used when filename exception occurs, required when includes
  • debug. Output token and translated function body
  • Compiler replaces jade's default compiler
  • The structure debugged when compileDebug false is not output
  • pretty) Add nice space indentation to the output (default is false)

Label

A label is a simple word:

html

It will be converted to <html></html>

Labels can also have id s:

div#container

It will be converted to <div id="container"></div>

How to add class?

div.user-details

Convert to <div class="user-details"></div>

Multiple class es and id s? Can also be done:

div#foo.bar.baz

Convert to <div id="foo" class="bar baz"></div>

Non-stop div div is annoying, you can do this:

#foo
.bar

This is our grammar sugar. It's already well supported. It will output:

<div id="foo"></div><div class="bar"></div>

Label Text

Simply put the content after the label:

p wahoo!

It will be rendered as <p>wahoo!</p>.

It's handsome, but what about large sections of text:

p
  | foo bar baz
  | rawr rawr
  | super cool
  | go jade go

Render as <p>foo bar Baz rawr.... </p>

How can I combine data?All types of text presentations can be combined with data. If we pass {name:'tj', email:'tj@vision-media.ca'} to a compiler function, here's how the template is written:

#user #{name} &lt;#{email}&gt;

It will be rendered as <div id="user">tj <tj@vision-media.ca></div>

What do I do when I just want to output #{}? Escape it!

p \#{something}

It will output <p>#{something}</p>

You can also use non-escaped variables! {html}, the following template will output a <script>tag directly:

- var html = "<script></script>"
| !{html}

Inline tags can also use text blocks to contain text:

label
  | Username:
  input(name='user[name]')

Or use label text directly:

label Username:
  input(name='user[name]')

Labels that contain only text, such as <script>, <style>, and <textarea>, do not require a prefix | character, such as:

html
  head
    title Example
    script
      if (foo) {
        bar();
      } else {
        baz();
      }

There is also an option to start a piece of text with.Such as:

p.
  foo asdf
  asdf
   asdfasdfaf
   asdf
  asd.

Will be rendered as:

<p>foo asdf
asdf
  asdfasdfaf
  asdf
asd
.
</p>

This is not the same as with a space. Spaces are ignored by Jade's parser as ordinary text:

p .

Render as:

<p>.</p>

Note that the text block needs to be escaped twice.For example, you want to output the following text:

</p>foo\bar</p>

Use:

p.
  foo\\bar

Notes

Single-line comments are the same as in JavaScript, start with // and must be on a separate line:

// just some paragraphs
p foo
p bar

Render as:

<!-- just some paragraphs -->
<p>foo</p>
<p>bar</p>

Jade also supports non-output annotations, just add a dash:

//- will not output within markup
p foo
p bar

Render as:

<p>foo</p>
<p>bar</p>

Block Comments

Block annotations are also supported:

body
  //
    #content
      h1 Example

Render as:

<body>
  <!--
  <div id="content">
    <h1>Example</h1>
  </div>
  -->
</body>

Jade also supports the conditional notes very well:

body
  //if IE
    a(href='http://www.mozilla.com/en-US/firefox/') Get Firefox

Render as:

<body>
  <!--[if IE]>
    <a href="http://www.mozilla.com/en-US/firefox/">Get Firefox</a>
  <![endif]-->
</body>

inline

Jade supports defining tag nesting in a natural way:

ul
  li.first
    a(href='#') foo
  li
    a(href='#') bar
  li.last
    a(href='#') baz

Block Expansion

Block expansion can help you create nested labels in one line, as shown in the following example:

ul
  li.first: a(href='#') foo
  li: a(href='#') bar
  li.last: a(href='#') baz

Case

The case expression is written as follows:

html
  body
    friends = 10
    case friends
      when 0
        p you have no friends
      when 1
        p you have a friend
      default
        p you have #{friends} friends

Block expansion can also be used here:

friends = 5

html
  body
    case friends
      when 0: p you have no friends
      when 1: p you have a friend
      default: p you have #{friends} friends

attribute

Jade now supports the use of (and) as attribute delimiters

a(href='/login', title='View login page') Login

When a value is undefined or the null attribute is not added, so it does not compile'something='null'.

div(something=null)

The Boolean property is also supported:

input(type="checkbox", checked)

Boolean properties that use code only output when the property is true:

input(type="checkbox", checked=someValue)

Multiline is also available:

input(type='checkbox',
  name='agreement',
  checked)

Multiple lines without commas:

input(type='checkbox'
  name='agreement'
  checked)

Add a space and have a nice format?Similarly supported

input(
  type='checkbox'
  name='agreement'
  checked)

Colons are also supported:

rss(xmlns:atom="atom")

If I have a user object {id: 12, name:'tobi'} and we want to create a link href to/user/12, we can use a normal JavaScript string connection as follows:

a(href='/user/' + user.id)= user.name

Or let's use Jade's modification, which I think many people who use Ruby or CoffeeScript will look like normal JS..

a(href='/user/#{user.id}')= user.name

The class attribute is a special property that you can pass directly an array, such as bodyClasses = ['user','authenticated']:

body(class=bodyClasses)

HTML

Inline HTML is possible, and we can use pipelines to define a piece of text:

html
  body
    | <h1>Title</h1>
    | <p>foo bar baz</p>

Or we can use.To tell Jade that we need a piece of text:

html
  body.
    <h1>Title</h1>
    <p>foo bar baz</p>

Both examples above render the same result:

<html><body><h1>Title</h1>
<p>foo bar baz</p>
</body></html>

This rule applies to any text in Jade:

html
  body
    h1 User <em>#{name}</em>

Doctypes

Adding a document type requires simple use!!!, or doctype follows the options below:

!!!

The transitional document type is rendered, or:

!!! 5

or

!!! html

or

doctype html

Doctype is case insensitive, so the following two are the same:

doctype Basic
doctype basic

Of course, you can also pass a piece of document-type text directly:

doctype html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN"

After rendering:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN">

The following default document types can be easily extended:

var doctypes = exports.doctypes = {
  '5': '<!DOCTYPE html>',
  'xml': '<?xml version="1.0" encoding="utf-8" ?>',
  'default': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">',
  'transitional': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">',
  'strict': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">',
  'frameset': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">',
  '1.1': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">',
  'basic': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd">',
  'mobile': '<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.2//EN" "http://www.openmobilealliance.org/tech/DTD/xhtml-mobile12.dtd">'
};

The following code allows you to easily change the default document type:

    jade.doctypes.default = 'whatever you want';

Filter

Filter prefix: for example, markdown handles the text in the following block to a special function.See what filters are available in the top feature.

body
  :markdown
    Woah! jade _and_ markdown, very **cool**
    we can even link to [stuff](http://google.com)

Render as:

<body><p>Woah! jade <em>and</em> markdown, very <strong>cool</strong> we can even link to <a href="http://google.com">stuff</a></p></body>

Code

Jade currently supports three types of executable code.The first is the prefix -, which is not output:

- var foo = 'bar';

This can be used in conditional statements or loops:

- for (var key in obj)
  p= obj[key]

Due to Jade's caching technology, the following code is also possible:

- if (foo)
  ul
    li yay
    li foo
    li worked
- else
  p oh no! didnt work

Ha-ha, even a long cycle is possible:

- if (items.length)
  ul
    - items.forEach(function(item){
      li= item
    - })

So what you want!

The next step is to escape the output code, for example, if we return a value with only one prefix=:

- var foo = 'bar'
= foo
h1= foo

It will be rendered as bar<h1>bar</h1>.For security reasons, code using = output is escaped by default, and can be used if you want to output values that are not escaped directly!=:

p!= aVarContainingMoreHTML

Jade is also designer-friendly, making JavaScript more direct and expressive.For example, the following assignment statements are equal, and the expression is usually JavaScript:

- var foo = 'foo ' + 'bar'
foo = 'foo ' + 'bar'

Jade will give priority to if, else if, else, until, while, unless as well, but you have to remember that they are normal JavaScript:

if foo == 'bar'
  ul
    li yay
    li foo
    li worked
else
  p oh no! didnt work  

loop

Although JavaScript native code is already supported, Jade also supports special tags that make templates easier to understand, one of which is each, in this form:

each VAL[, KEY] in OBJ

An example of traversing an array:

- var items = ["one", "two", "three"]
each item in items
  li= item

Render as:

<li>one</li>
<li>two</li>
<li>three</li>

Traverse an array with indexes:

items = ["one", "two", "three"]
each item, i in items
  li #{item}: #{i}

Render as:

<li>one: 0</li>
<li>two: 1</li>
<li>three: 2</li>

Traverse through the key values of an array:

obj = { foo: 'bar' }
each val, key in obj
  li #{key}: #{val}

Will render as: <li>foo: bar</li>

Jade internally converts these statements into native JavaScript statements, just like using users.forEach(function(user){, lexical scopes and nesting are the same as in normal JavaScript:

each user in users
  each role in user.roles
    li= role

If you like, you can also use for:

for user in users
  for role in user.roles
    li= role

Conditional statement

The Jade conditional statement is consistent with the JavaScript statement that uses the (-) prefix, and then it allows you to avoid parentheses, which makes it look a little more friendly to the designer, keeping in mind that this expression renders regular JavaScript:

for user in users
  if user.role == 'admin'
    p #{user.name} is an admin
  else
    p= user.name

Equal to the following code that uses regular JavaScript:

for user in users
  - if (user.role == 'admin')
    p #{user.name} is an admin
  - else
    p= user.name

Jade also supports unless, which is equivalent to if (! (expr):

for user in users
  unless user.isAnonymous
    p
      | Click to view
      a(href='/users/' + user.id)= user.name 

Template Inheritance

Jade supports template inheritance through the block and extends keywords.A block is a Jade block, which is implemented in a sub-template and supports recursion.

If a Jade block has no content, Jade adds default content. The following code outputs block scripts, block content, and block foot by default.

html
  head
    h1 My Site - #{title}
    block scripts
      script(src='/jquery.js')
  body
    block content
    block foot
      #footer
        p some footer content

Now let's inherit this layout and simply create a new file that uses extends directly, given the path (with or without the.jade extension). You can define one or more blocks to overwrite the parent block content, noting that the foot block here is undefined, so it also outputs"some footer content" of the parent.

extends extend-layout

block scripts
  script(src='/jquery.js')
  script(src='/pets.js')

block content
  h1= title
  each pet in pets
    include pet

Blocks can also be added to a subblock, as defined in the block context implemented below are two blocks sidebar and primary that can be implemented, or sub-templates can implement content directly.

extends regular-layout

block content
  .sidebar
    block sidebar
      p nothing
  .primary
    block primary
      p nothing

Prefix, Append Code Blocks

Jade allows you to replace (default), prefix, and append blocks. For example, suppose you want to add a default script to the top of all pages, you can do this:

html
  head
    block head
      script(src='/vendor/jquery.js')
      script(src='/vendor/caustic.js')
  body
    block content

Now suppose you have a page for Javascript games and you want to add some game-related scripts in addition to the default scripts, you can append the code block directly:

extends layout

block append head
  script(src='/vendor/three.js')
  script(src='/game.js')

Blocks are optional when using block append or block prepend:

extends layout

append head
  script(src='/vendor/three.js')
  script(src='/game.js')

Contain

Includes allows you to include a piece of Jade statically, or something else stored in a single file, such as CSS. A very common example of HTML is including headers and footers.Suppose we have a folder with the following directory structure:

./layout.jade
./includes/
  ./head.jade
  ./tail.jade

Here's what layout.jade does:

html
  include includes/head  
  body
    h1 My Site
    p Welcome to my super amazing site.
    include includes/foot

Both include/head and include/foot read files relative to the path given to the layout.jade parameter filename, which is an absolute path, so don't worry about Express helping you with this.Include parses these files, inserts them into the generated grammar tree, and renders what you expect:

<html>
  <head>
    <title>My Site</title>
    <script src="/javascripts/jquery.js">
    </script><script src="/javascripts/app.js"></script>
  </head>
  <body>
    <h1>My Site</h1>
    <p>Welcome to my super lame site.</p>
    <div id="footer">
      <p>Copyright>(c) foobar</p>
    </div>
  </body>
</html>

As mentioned earlier, includes can contain content such as HTML or CSS.Given an extension, Jade does not treat this file as a Jade source code and will include it as plain text:

html
  head
    //- css and js have simple filters that wrap them in
        <style> and <script> tags, respectively
    include stylesheet.css
    include script.js
  body
    //- "markdown" files will use the "markdown" filter
        to convert Markdown to HTML
    include introduction.markdown
    //- html files have no filter and are included verbatim
    include content.html

Include can also accept block content, and the given block will be appended to the last block containing the file.For example, head.jade contains the following:

head
  script(src='/jquery.js')

We can add content to include head like below, here are two scripts.

html
  include head
    script(src='/foo.js')
    script(src='/bar.js')
  body
    h1 test

In included templates, you can also use the yield statement.The yield statement allows you to clearly indicate where the include block is placed.For example, suppose you want to place the code block before scripts, not after them:

head
  yield
  script(src='/jquery.js')
  script(src='/jquery.ui.js')

Since the included Jade is literally parsed and merged into AST, lexical range variables have the same effect as those written directly in the same file.This means that includes can be used as an alternative to partial s, for example, suppose we have a user.jade`file that references the user variable:

h1= user.name
p= user.occupation

Next, when we iterate over users, we simply add include user.Because the user variable is already defined in the loop, the included template can access it.

users = [{ name: 'Tobi', occupation: 'Ferret' }]

each user in users
  .user
    include user

The above code generates:

<div class="user">
  <h1>Tobi</h1>
  <p>Ferret</p>
</div>

user.jade refers to the user variable, and if we want to use a different variable, user, we can directly define a new variable, user = person, as follows:

each person in users
  .user
    user = person
    include user

Mixins

Mixins is converted from Jade to a regular JavaScript function in the compiled template.Mixins can take parameters, but are not required:

mixin list
  ul
    li foo
    li bar
    li baz

Using mixin s without parameters looks very simple, outside one block:

h2 Groceries
mixin list

Mixins can also take one or more parameters, which are common JavaScript expressions, such as the following example:

mixin pets(pets)
  ul.pets
    - each pet in pets
      li= pet

mixin profile(user)
  .user
    h2= user.name
    mixin pets(user.pets)

It will output HTML like the following:

<div class="user">
  <h2>tj</h2>
  <ul class="pets">
    <li>tobi</li>
    <li>loki</li>
    <li>jane</li>
    <li>manny</li>
  </ul>
</div>

Generate Output

Suppose we have the following Jade source:

- var title = 'yay'
h1.title #{title}
p Just an example

When the compileDebug option is not false, Jade compiles with u.lineno = n; this parameter is passed to rethrow() when a compilation error occurs, and this function gives a useful error message when Jade initially outputs.

function anonymous(locals) {
  var __ = { lineno: 1, input: "- var title = 'yay'\nh1.title #{title}\np Just an example", filename: "testing/test.js" };
  var rethrow = jade.rethrow;
  try {
    var attrs = jade.attrs, escape = jade.escape;
    var buf = [];
    with (locals || {}) {
      var interp;
      __.lineno = 1;
       var title = 'yay'
      __.lineno = 2;
      buf.push('<h1');
      buf.push(attrs({ "class": ('title') }));
      buf.push('>');
      buf.push('' + escape((interp = title) == null ? '' : interp) + '');
      buf.push('</h1>');
      __.lineno = 3;
      buf.push('<p>');
      buf.push('Just an example');
      buf.push('</p>');
    }
    return buf.join("");
  } catch (err) {
    rethrow(err, __.input, __.filename, __.lineno);
  }
}

When the compileDebug parameter is false, it is removed, which is useful for lightweight browser-side templates.Combined with Jade's parameters and the. /runtime.js file in the current source library, you can compile the template with toString() without running the entire Jade library on the browser side, which can improve performance and reduce the number of JavaScript s loaded.

function anonymous(locals) {
  var attrs = jade.attrs, escape = jade.escape;
  var buf = [];
  with (locals || {}) {
    var interp;
    var title = 'yay'
    buf.push('<h1');
    buf.push(attrs({ "class": ('title') }));
    buf.push('>');
    buf.push('' + escape((interp = title) == null ? '' : interp) + '');
    buf.push('</h1>');
    buf.push('<p>');
    buf.push('Just an example');
    buf.push('</p>');
  }
  return buf.join("");
}

An example of Makefile

By making, the following Makefile example compiles pages/*.jade to pages/*.html.

JADE = $(shell find pages/*.jade)
HTML = $(JADE:.jade=.html)

all: $(HTML)

%.html: %.jade
    jade < $< --path $< > $@

clean:
    rm -f $(HTML)

.PHONY: clean

This can be combined with the watch(1) command to produce behavior like the following:

$ watch make

Jade on the command line

 Use: jade [options] [dir|file...]

Options:

  -h, --help output help information
  -v, --version output version number
  -o, --out <dir>Output compiled HTML to <dir>
  -O, --obj <str> JavaScript option
  -p, --path <path>Find the path to find when processing stdio to include files
  -P, --pretty Formatting HTML Output
  -c, --client compiles runtime.js available on the browser side
  -D, --no-debug turns off debugging options for compilation (functions will be smaller)
  -w, --watch monitors file changes to automatically refresh compilation results

Examples:

  #Compile the entire directory
  $ jade templates

  #Generate {foo,bar}.html
  $ jade {foo,bar}.jade

  #Use jade under Standard IO 
  $ jade < my.jade > my.html

  #Use jade under Standard IO, specifying to find included files
  $ jade < my.jade -p my.jade > my.html

  #Use jade under Standard IO 
  $ echo "h1 Jade!" | jade

  Render # foo, bar directory to/tmp
  $ jade foo bar --out /tmp 

Note: The -o option from v0.31.0 already points to -out, -O is swapped accordingly

Reprinted at: https://www.cnblogs.com/smallstupidwife/p/4823511.html

Topics: Javascript JQuery Firefox Attribute