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
- : stylus must already be installed stylus
- : less must already be installed less.js
- : markdown must already be installed markdown-js perhaps node-discount
- :cdata
- : coffeescript must already be installed coffee-script
- 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} <#{email}>
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