UNPKG

14.1 kBMarkdownView Raw
1
2# Jade - template engine
3
4 Jade is a high performance template engine heavily influenced by [Haml](http://haml-lang.com)
5 and implemented with JavaScript for [node](http://nodejs.org).
6
7## Features
8
9 - client-side support
10 - great readability
11 - flexible indentation
12 - block-expansion
13 - attribute interpolation
14 - code is escaped by default for security
15 - contextual error reporting at compile & run time
16 - executable for compiling jade templates via the command line
17 - html 5 mode (using the _!!! 5_ doctype)
18 - optional memory caching
19 - combine dynamic and static tag classes
20 - parse tree manipulation via _filters_
21 - supports [Express JS](http://expressjs.com) out of the box
22 - transparent iteration over objects, arrays, and even non-enumerables via `- each`
23 - block comments
24 - no tag prefix
25 - AST filters
26 - filters
27 - :sass must have [sass.js](http://github.com/visionmedia/sass.js) installed
28 - :less must have [less.js](http://github.com/cloudhead/less.js) installed
29 - :markdown must have [markdown-js](http://github.com/evilstreak/markdown-js) installed or [node-discount](http://github.com/visionmedia/node-discount)
30 - :cdata
31 - :coffeescript must have [coffee-script](http://jashkenas.github.com/coffee-script/) installed
32 - [Vim Syntax](https://github.com/digitaltoad/vim-jade)
33 - [TextMate Bundle](http://github.com/miksago/jade-tmbundle)
34 - [Screencasts](http://tjholowaychuk.com/post/1004255394/jade-screencast-template-engine-for-nodejs)
35 - [html2jade](https://github.com/donpark/html2jade) converter
36
37## Implementations
38
39 - [php](http://github.com/everzet/jade.php)
40 - [scala](http://scalate.fusesource.org/versions/snapshot/documentation/scaml-reference.html)
41 - [ruby](http://github.com/stonean/slim)
42
43## Installation
44
45via npm:
46
47 npm install jade
48
49## Browser Support
50
51 To compile jade to a single file compatible for client-side use simply execute:
52
53 $ make jade.js
54
55 Alternatively, if uglifyjs is installed via npm (`npm install uglify-js`) you may execute the following which will create both files.
56
57 $ make jade.min.js
58
59## Public API
60
61```javascript
62 var jade = require('jade');
63
64 // Render a string
65 jade.render('string of jade', { options: 'here' });
66
67 // Render a file
68 jade.renderFile('path/to/some.jade', { options: 'here' }, function(err, html){
69 // options are optional,
70 // the callback can be the second arg
71 });
72
73 // Compile a function
74 var fn = jade.compile('string of jade', options);
75 fn.call(scope, locals);
76```
77
78### Options
79
80 - `scope` Evaluation scope (`this`)
81 - `self` Use a `self` namespace to hold the locals. _false by default_
82 - `locals` Local variable object
83 - `filename` Used in exceptions, and required by `cache`
84 - `cache` Cache intermediate JavaScript in memory keyed by `filename`
85 - `debug` Outputs tokens and function body generated
86 - `compiler` Compiler to replace jade's default
87
88## Syntax
89
90### Line Endings
91
92**CRLF** and **CR** are converted to **LF** before parsing.
93
94### Tags
95
96A tag is simply a leading word:
97
98 html
99
100for example is converted to `<html></html>`
101
102tags can also have ids:
103
104 div#container
105
106which would render `<div id="container"></div>`
107
108how about some classes?
109
110 div.user-details
111
112renders `<div class="user-details"></div>`
113
114multiple classes? _and_ an id? sure:
115
116 div#foo.bar.baz
117
118renders `<div id="foo" class="bar baz"></div>`
119
120div div div sure is annoying, how about:
121
122 #foo
123 .bar
124
125which is syntactic sugar for what we have already been doing, and outputs:
126
127 `<div id="foo"></div><div class="bar"></div>`
128
129### Tag Text
130
131Simply place some content after the tag:
132
133 p wahoo!
134
135renders `<p>wahoo!</p>`.
136
137well cool, but how about large bodies of text:
138
139 p
140 | foo bar baz
141 | rawr rawr
142 | super cool
143 | go jade go
144
145renders `<p>foo bar baz rawr.....</p>`
146
147interpolation? yup! both types of text can utilize interpolation,
148if we passed `{ locals: { name: 'tj', email: 'tj@vision-media.ca' }}` to `render()`
149we can do the following:
150
151 #user #{name} &lt;#{email}&gt;
152
153outputs `<div id="user">tj &lt;tj@vision-media.ca&gt;</div>`
154
155Actually want `#{}` for some reason? escape it!
156
157 p \#{something}
158
159now we have `<p>#{something}</p>`
160
161We can also utilize the unescaped variant `!{html}`, so the following
162will result in a literal script tag:
163
164 - var html = "<script></script>"
165 | !{html}
166
167Nested tags that also contain text can optionally use a text block:
168
169 label
170 | Username:
171 input(name='user[name]')
172
173or immediate tag text:
174
175 label Username:
176 input(name='user[name]')
177
178Tags that accept _only_ text such as `script`, `style`, and `textarea` do not
179need the leading `|` character, for example:
180
181 html
182 head
183 title Example
184 script
185 if (foo) {
186 bar();
187 } else {
188 baz();
189 }
190
191Once again as an alternative, we may use a leading '.' to indicate a text block, for example:
192
193 p.
194 foo asdf
195 asdf
196 asdfasdfaf
197 asdf
198 asd.
199
200outputs:
201
202 <p>foo asdf
203 asdf
204 asdfasdfaf
205 asdf
206 asd
207 .
208 </p>
209
210This however differs from a leading '.' followed by a space, which although is ignored by the Jade parser, tells Jade that this period is a literal:
211
212 p .
213
214outputs:
215
216 <p>.</p>
217
218### Comments
219
220Single line comments currently look the same as JavaScript comments,
221aka "//" and must be placed on their own line:
222
223 // just some paragraphs
224 p foo
225 p bar
226
227would output
228
229 <!-- just some paragraphs -->
230 <p>foo</p>
231 <p>bar</p>
232
233Jade also supports unbuffered comments, by simply adding a hyphen:
234
235 //- will not output within markup
236 p foo
237 p bar
238
239outputting
240
241 <p>foo</p>
242 <p>bar</p>
243
244### Block Comments
245
246 A block comment is legal as well:
247
248 body
249 //
250 #content
251 h1 Example
252
253outputting
254
255 <body>
256 <!--
257 <div id="content">
258 <h1>Example</h1>
259 </div>
260 -->
261 </body>
262
263Jade supports conditional-comments as well, for example:
264
265 body
266 /if IE
267 a(href='http://www.mozilla.com/en-US/firefox/') Get Firefox
268
269outputs:
270
271 <body>
272 <!--[if IE]>
273 <a href="http://www.mozilla.com/en-US/firefox/">Get Firefox</a>
274 <![endif]-->
275 </body>
276
277
278### Nesting
279
280 Jade supports nesting to define the tags in a natural way:
281
282 ul
283 li.first
284 a(href='#') foo
285 li
286 a(href='#') bar
287 li.last
288 a(href='#') baz
289
290### Block Expansion
291
292 Block expansion allows you to create terse single-line nested tags,
293 the following example is equivalent to the nesting example above.
294
295 ul
296 li.first: a(href='#') foo
297 li: a(href='#') bar
298 li.last: a(href='#') baz
299
300
301### Attributes
302
303Jade currently supports '(' and ')' as attribute delimiters.
304
305 a(href='/login', title='View login page') Login
306
307Boolean attributes are also supported:
308
309 input(type="checkbox", checked)
310
311Boolean attributes with code will only output the attribute when `true`:
312
313 input(type="checkbox", checked= someValue)
314
315Multiple lines work too:
316
317 input(type='checkbox',
318 name='agreement',
319 checked)
320
321Multiple lines without the comma work fine:
322
323 input(type='checkbox'
324 name='agreement'
325 checked)
326
327Funky whitespace? fine:
328
329
330 input(
331 type='checkbox'
332 name='agreement'
333 checked)
334
335Colons work:
336
337 rss(xmlns:atom="atom")
338
339Suppose we have the `user` local `{ id: 12, name: 'tobi' }`
340and we wish to create an anchor tag with `href` pointing to "/user/12"
341we could use regular javascript concatenation:
342
343 a(href='/user/' + user.id)= user.name
344
345or we could use jade's interpolation:
346
347 a(href='/user/#{user.id}')= user.name
348
349### Doctypes
350
351To add a doctype simply use `!!!`, or `doctype` followed by an optional value:
352
353 !!!
354
355Will output the _transitional_ doctype, however:
356
357 !!! 5
358
359or
360
361 !!! html
362
363or
364
365 doctype html
366
367doctypes are case-insensitive, so the following are equivalent:
368
369 doctype Basic
370 doctype basic
371
372Will output the _html 5_ doctype. Below are the doctypes
373defined by default, which can easily be extended:
374
375```javascript
376 var doctypes = exports.doctypes = {
377 '5': '<!DOCTYPE html>',
378 'xml': '<?xml version="1.0" encoding="utf-8" ?>',
379 'default': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">',
380 'transitional': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">',
381 'strict': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">',
382 'frameset': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">',
383 '1.1': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">',
384 'basic': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd">',
385 'mobile': '<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.2//EN" "http://www.openmobilealliance.org/tech/DTD/xhtml-mobile12.dtd">'
386 };
387```
388
389To alter the default simply change:
390
391```javascript
392 jade.doctypes.default = 'whatever you want';
393```
394
395## Filters
396
397Filters are prefixed with `:`, for example `:markdown` and
398pass the following block of text to an arbitrary function for processing. View the _features_
399at the top of this document for available filters.
400
401 body
402 :markdown
403 Woah! jade _and_ markdown, very **cool**
404 we can even link to [stuff](http://google.com)
405
406Renders:
407
408 <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>
409
410Filters may also manipulate the parse tree. For example perhaps I want to
411bake conditionals right into jade, we could do so with a filter named _conditionals_. Typically filters work on text blocks, however by passing a regular block our filter can do anything it wants with the tags nested within it.
412
413 body
414 conditionals:
415 if role == 'admin'
416 p You are amazing
417 else
418 p Not so amazing
419
420Not that we no longer prefix with "-" for these code blocks. Examples of
421how to manipulate the parse tree can be found at _./examples/conditionals.js_ and _./examples/model.js_, basically we subclass and re-implement visitor methods as needed. There are several interesting use-cases for this functionality above what was shown above such as transparently aggregating / compressing assets to reduce the number of HTTP requests, transparent record error reporting, and more.
422
423## Code
424
425Jade currently supports three classifications of executable code. The first
426is prefixed by `-`, and is not buffered:
427
428 - var foo = 'bar';
429
430This can be used for conditionals, or iteration:
431
432 - for (var key in obj)
433 p= obj[key]
434
435Due to Jade's buffering techniques the following is valid as well:
436
437 - if (foo)
438 ul
439 li yay
440 li foo
441 li worked
442 - else
443 p oh no! didnt work
444
445Hell, even verbose iteration:
446
447 - if (items.length)
448 ul
449 - items.forEach(function(item){
450 li= item
451 - })
452
453Anything you want!
454
455Next up we have _escaped_ buffered code, which is used to
456buffer a return value, which is prefixed by `=`:
457
458 - var foo = 'bar'
459 = foo
460 h1= foo
461
462Which outputs `bar<h1>bar</h1>`. Code buffered by `=` is escaped
463by default for security, however to output unescaped return values
464you may use `!=`:
465
466 p!= aVarContainingMoreHTML
467
468The on exception made in terms of allowing "vanilla" JavaScript, is
469the `- each` token. This takes the form of:
470
471 - each VAL[, KEY] in OBJ
472
473An example iterating over an array:
474
475 - var items = ["one", "two", "three"]
476 - each item in items
477 li= item
478
479outputs:
480
481 <li>one</li>
482 <li>two</li>
483 <li>three</li>
484
485iterating an object's keys and values:
486
487 - var obj = { foo: 'bar' }
488 - each val, key in obj
489 li #{key}: #{val}
490
491would output `<li>foo: bar</li>`
492
493You can also nest these!
494
495 - each user in users
496 - each role in user.roles
497 li= role
498
499When a property is undefined, Jade will output an empty string. For example:
500
501 textarea= user.signature
502
503when undefined would normally output "undefined" in your html, however recent
504versions of Jade will simply render:
505
506 <textarea></textarea>
507
508## bin/jade
509
510Output html to _stdout_:
511
512 jade examples/*.jade --pipe
513
514Generate _examples/*.html_:
515
516 jade examples/*.jade
517
518Pass options:
519
520 jade examples/layout.jade --options '{ locals: { title: "foo" }}'
521
522Usage info:
523
524 Usage: jade [options] <path ...>
525
526 Options:
527 -o, --options STR JavaScript options object passed
528 -p, --pipe Output to stdout instead of PATH.html
529 -h, --help Output help information
530
531## License
532
533(The MIT License)
534
535Copyright (c) 2009-2010 TJ Holowaychuk &lt;tj@vision-media.ca&gt;
536
537Permission is hereby granted, free of charge, to any person obtaining
538a copy of this software and associated documentation files (the
539'Software'), to deal in the Software without restriction, including
540without limitation the rights to use, copy, modify, merge, publish,
541distribute, sublicense, and/or sell copies of the Software, and to
542permit persons to whom the Software is furnished to do so, subject to
543the following conditions:
544
545The above copyright notice and this permission notice shall be
546included in all copies or substantial portions of the Software.
547
548THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
549EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
550MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
551IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
552CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
553TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
554SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.