UNPKG

20.3 kBMarkdownView Raw
1# Jade - template engine
2
3 Jade is a high performance template engine heavily influenced by [Haml](http://haml-lang.com)
4 and implemented with JavaScript for [node](http://nodejs.org).
5
6## Features
7
8 - client-side support
9 - great readability
10 - flexible indentation
11 - block-expansion
12 - mixins
13 - static includes
14 - attribute interpolation
15 - code is escaped by default for security
16 - contextual error reporting at compile & run time
17 - executable for compiling jade templates via the command line
18 - html 5 mode (using the _!!! 5_ doctype)
19 - optional memory caching
20 - combine dynamic and static tag classes
21 - parse tree manipulation via _filters_
22 - supports [Express JS](http://expressjs.com) out of the box
23 - transparent iteration over objects, arrays, and even non-enumerables via `- each`
24 - block comments
25 - no tag prefix
26 - AST filters
27 - filters
28 - :sass must have [sass.js](http://github.com/visionmedia/sass.js) installed
29 - :less must have [less.js](http://github.com/cloudhead/less.js) installed
30 - :markdown must have [markdown-js](http://github.com/evilstreak/markdown-js) installed or [node-discount](http://github.com/visionmedia/node-discount)
31 - :cdata
32 - :coffeescript must have [coffee-script](http://jashkenas.github.com/coffee-script/) installed
33 - [Vim Syntax](https://github.com/digitaltoad/vim-jade)
34 - [TextMate Bundle](http://github.com/miksago/jade-tmbundle)
35 - [Screencasts](http://tjholowaychuk.com/post/1004255394/jade-screencast-template-engine-for-nodejs)
36 - [html2jade](https://github.com/donpark/html2jade) converter
37
38## Implementations
39
40 - [php](http://github.com/everzet/jade.php)
41 - [scala](http://scalate.fusesource.org/versions/snapshot/documentation/scaml-reference.html)
42 - [ruby](http://github.com/stonean/slim)
43
44## Installation
45
46via npm:
47
48 npm install jade
49
50## Browser Support
51
52 To compile jade to a single file compatible for client-side use simply execute:
53
54 $ make jade.js
55
56 Alternatively, if uglifyjs is installed via npm (`npm install uglify-js`) you may execute the following which will create both files. However each release builds these for you.
57
58 $ make jade.min.js
59
60 By default Jade inlines its utility functions within the template functions generated, such as `escape()` and `attrs()`. Jade also instruments templates with line number statements such as `__.lineno = 3` for debugging purposes. When used in a browser it's useful to minimize this boiler plate, you can do so by passing the option `{ compileDebug: false }`, and `{ inline: false }`. The following template
61
62 p Hello #{name}
63
64 Can then be as small as the following generated function:
65
66```js
67function anonymous(locals) {
68 var attrs = jade.attrs, escape = jade.escape;
69 var buf = [];
70 with (locals || {}) {
71 var interp;
72 buf.push('<p>');
73 buf.push('Hello ' + escape((interp = name) == null ? '' : interp) + '');
74 buf.push('</p>');
75 }
76 return buf.join("");
77}
78```
79
80 Through the use of Jade's `./runtime.js` you may utilize these pre-compiled templates on the client-side _without_ Jade itself, all you need is the associated utility functions (in runtime.js), which are then available as `jade.attrs`, `jade.escape` etc.
81
82## Public API
83
84```javascript
85 var jade = require('jade');
86
87 // Render a string
88 jade.render('string of jade', { options: 'here' });
89
90 // Render a file
91 jade.renderFile('path/to/some.jade', { options: 'here' }, function(err, html){
92 // options are optional,
93 // the callback can be the second arg
94 });
95
96 // Compile a function
97 var fn = jade.compile('string of jade', options);
98 fn.call(scope, locals);
99```
100
101### Options
102
103 - `scope` Evaluation scope (`this`)
104 - `self` Use a `self` namespace to hold the locals. _false by default_
105 - `locals` Local variable object
106 - `filename` Used in exceptions, and required when using includes
107 - `debug` Outputs tokens and function body generated
108 - `compiler` Compiler to replace jade's default
109 - `compileDebug` When `false` no debug instrumentation is compiled
110 - `inline` When `false` the helpers are not inlined (ideal for client-side use)
111
112## Syntax
113
114### Line Endings
115
116**CRLF** and **CR** are converted to **LF** before parsing.
117
118### Tags
119
120A tag is simply a leading word:
121
122 html
123
124for example is converted to `<html></html>`
125
126tags can also have ids:
127
128 div#container
129
130which would render `<div id="container"></div>`
131
132how about some classes?
133
134 div.user-details
135
136renders `<div class="user-details"></div>`
137
138multiple classes? _and_ an id? sure:
139
140 div#foo.bar.baz
141
142renders `<div id="foo" class="bar baz"></div>`
143
144div div div sure is annoying, how about:
145
146 #foo
147 .bar
148
149which is syntactic sugar for what we have already been doing, and outputs:
150
151 `<div id="foo"></div><div class="bar"></div>`
152
153### Tag Text
154
155Simply place some content after the tag:
156
157 p wahoo!
158
159renders `<p>wahoo!</p>`.
160
161well cool, but how about large bodies of text:
162
163 p
164 | foo bar baz
165 | rawr rawr
166 | super cool
167 | go jade go
168
169renders `<p>foo bar baz rawr.....</p>`
170
171interpolation? yup! both types of text can utilize interpolation,
172if we passed `{ locals: { name: 'tj', email: 'tj@vision-media.ca' }}` to `render()`
173we can do the following:
174
175 #user #{name} &lt;#{email}&gt;
176
177outputs `<div id="user">tj &lt;tj@vision-media.ca&gt;</div>`
178
179Actually want `#{}` for some reason? escape it!
180
181 p \#{something}
182
183now we have `<p>#{something}</p>`
184
185We can also utilize the unescaped variant `!{html}`, so the following
186will result in a literal script tag:
187
188 - var html = "<script></script>"
189 | !{html}
190
191Nested tags that also contain text can optionally use a text block:
192
193 label
194 | Username:
195 input(name='user[name]')
196
197or immediate tag text:
198
199 label Username:
200 input(name='user[name]')
201
202Tags that accept _only_ text such as `script`, `style`, and `textarea` do not
203need the leading `|` character, for example:
204
205 html
206 head
207 title Example
208 script
209 if (foo) {
210 bar();
211 } else {
212 baz();
213 }
214
215Once again as an alternative, we may use a leading '.' to indicate a text block, for example:
216
217 p.
218 foo asdf
219 asdf
220 asdfasdfaf
221 asdf
222 asd.
223
224outputs:
225
226 <p>foo asdf
227 asdf
228 asdfasdfaf
229 asdf
230 asd
231 .
232 </p>
233
234This 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:
235
236 p .
237
238outputs:
239
240 <p>.</p>
241
242
243It should be noted that text blocks should be doubled escaped. For example if you desire the following output.
244
245 </p>foo\bar</p>
246
247use:
248
249 p.
250 foo\\bar
251
252### Comments
253
254Single line comments currently look the same as JavaScript comments,
255aka "//" and must be placed on their own line:
256
257 // just some paragraphs
258 p foo
259 p bar
260
261would output
262
263 <!-- just some paragraphs -->
264 <p>foo</p>
265 <p>bar</p>
266
267Jade also supports unbuffered comments, by simply adding a hyphen:
268
269 //- will not output within markup
270 p foo
271 p bar
272
273outputting
274
275 <p>foo</p>
276 <p>bar</p>
277
278### Block Comments
279
280 A block comment is legal as well:
281
282 body
283 //
284 #content
285 h1 Example
286
287outputting
288
289 <body>
290 <!--
291 <div id="content">
292 <h1>Example</h1>
293 </div>
294 -->
295 </body>
296
297Jade supports conditional-comments as well, for example:
298
299 body
300 //if IE
301 a(href='http://www.mozilla.com/en-US/firefox/') Get Firefox
302
303outputs:
304
305 <body>
306 <!--[if IE]>
307 <a href="http://www.mozilla.com/en-US/firefox/">Get Firefox</a>
308 <![endif]-->
309 </body>
310
311
312### Nesting
313
314 Jade supports nesting to define the tags in a natural way:
315
316 ul
317 li.first
318 a(href='#') foo
319 li
320 a(href='#') bar
321 li.last
322 a(href='#') baz
323
324### Block Expansion
325
326 Block expansion allows you to create terse single-line nested tags,
327 the following example is equivalent to the nesting example above.
328
329 ul
330 li.first: a(href='#') foo
331 li: a(href='#') bar
332 li.last: a(href='#') baz
333
334
335### Attributes
336
337Jade currently supports '(' and ')' as attribute delimiters.
338
339 a(href='/login', title='View login page') Login
340
341When a value is `undefined` or `null` the attribute is _not_ added,
342so this is fine, it will not compile 'something="null"'.
343
344 div(something=null)
345
346Boolean attributes are also supported:
347
348 input(type="checkbox", checked)
349
350Boolean attributes with code will only output the attribute when `true`:
351
352 input(type="checkbox", checked=someValue)
353
354Multiple lines work too:
355
356 input(type='checkbox',
357 name='agreement',
358 checked)
359
360Multiple lines without the comma work fine:
361
362 input(type='checkbox'
363 name='agreement'
364 checked)
365
366Funky whitespace? fine:
367
368
369 input(
370 type='checkbox'
371 name='agreement'
372 checked)
373
374Colons work:
375
376 rss(xmlns:atom="atom")
377
378Suppose we have the `user` local `{ id: 12, name: 'tobi' }`
379and we wish to create an anchor tag with `href` pointing to "/user/12"
380we could use regular javascript concatenation:
381
382 a(href='/user/' + user.id)= user.name
383
384or we could use jade's interpolation, which I added because everyone
385using Ruby or CoffeeScript seems to think this is legal js..:
386
387 a(href='/user/#{user.id}')= user.name
388
389The `class` attribute is special-cased when an array is given,
390allowing you to pass an array such as `bodyClasses = ['user', 'authenticated']` directly:
391
392 body(class=bodyClasses)
393
394### Doctypes
395
396To add a doctype simply use `!!!`, or `doctype` followed by an optional value:
397
398 !!!
399
400Will output the _transitional_ doctype, however:
401
402 !!! 5
403
404or
405
406 !!! html
407
408or
409
410 doctype html
411
412doctypes are case-insensitive, so the following are equivalent:
413
414 doctype Basic
415 doctype basic
416
417Will output the _html 5_ doctype. Below are the doctypes
418defined by default, which can easily be extended:
419
420```javascript
421 var doctypes = exports.doctypes = {
422 '5': '<!DOCTYPE html>',
423 'xml': '<?xml version="1.0" encoding="utf-8" ?>',
424 'default': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">',
425 'transitional': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">',
426 'strict': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">',
427 'frameset': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">',
428 '1.1': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">',
429 'basic': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd">',
430 'mobile': '<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.2//EN" "http://www.openmobilealliance.org/tech/DTD/xhtml-mobile12.dtd">'
431 };
432```
433
434To alter the default simply change:
435
436```javascript
437 jade.doctypes.default = 'whatever you want';
438```
439
440## Filters
441
442Filters are prefixed with `:`, for example `:markdown` and
443pass the following block of text to an arbitrary function for processing. View the _features_
444at the top of this document for available filters.
445
446 body
447 :markdown
448 Woah! jade _and_ markdown, very **cool**
449 we can even link to [stuff](http://google.com)
450
451Renders:
452
453 <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>
454
455Filters may also manipulate the parse tree. For example perhaps I want to
456bake 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.
457
458 body
459 conditionals:
460 if role == 'admin'
461 p You are amazing
462 else
463 p Not so amazing
464
465Not that we no longer prefix with "-" for these code blocks. Examples of
466how 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.
467
468## Code
469
470Jade currently supports three classifications of executable code. The first
471is prefixed by `-`, and is not buffered:
472
473 - var foo = 'bar';
474
475This can be used for conditionals, or iteration:
476
477 - for (var key in obj)
478 p= obj[key]
479
480Due to Jade's buffering techniques the following is valid as well:
481
482 - if (foo)
483 ul
484 li yay
485 li foo
486 li worked
487 - else
488 p oh no! didnt work
489
490Hell, even verbose iteration:
491
492 - if (items.length)
493 ul
494 - items.forEach(function(item){
495 li= item
496 - })
497
498Anything you want!
499
500Next up we have _escaped_ buffered code, which is used to
501buffer a return value, which is prefixed by `=`:
502
503 - var foo = 'bar'
504 = foo
505 h1= foo
506
507Which outputs `bar<h1>bar</h1>`. Code buffered by `=` is escaped
508by default for security, however to output unescaped return values
509you may use `!=`:
510
511 p!= aVarContainingMoreHTML
512
513The one exception made in terms of allowing "vanilla" JavaScript, is
514the `- each` token. This takes the form of:
515
516 - each VAL[, KEY] in OBJ
517
518An example iterating over an array:
519
520 - var items = ["one", "two", "three"]
521 - each item in items
522 li= item
523
524outputs:
525
526 <li>one</li>
527 <li>two</li>
528 <li>three</li>
529
530iterating an array with index:
531
532 - var items = ["one", "two", "three"]
533 - each item, i in items
534 li #{item}: #{i}
535
536outputs:
537
538 <li>one: 0</li>
539 <li>two: 1</li>
540 <li>three: 2</li>
541
542iterating an object's keys and values:
543
544 - var obj = { foo: 'bar' }
545 - each val, key in obj
546 li #{key}: #{val}
547
548would output `<li>foo: bar</li>`
549
550You can also nest these!
551
552 - each user in users
553 - each role in user.roles
554 li= role
555
556When a property is undefined, Jade will output an empty string. For example:
557
558 textarea= user.signature
559
560when undefined would normally output "undefined" in your html, however recent
561versions of Jade will simply render:
562
563 <textarea></textarea>
564
565## Includes
566
567 Includes allow you to statically include chunks of Jade
568 which lives in a separate file. The classical example is
569 including a header and footer. Suppose we have the following
570 directory structure:
571
572 ./layout.jade
573 ./includes/
574 ./head.jade
575 ./tail.jade
576
577and the following _layout.jade_:
578
579 html
580 include includes/head
581 body
582 h1 My Site
583 p Welcome to my super amazing site.
584 include includes/foot
585
586both includes _includes/head_ and _includes/foot_ are
587read relative to the `filename` option given to _layout.jade_,
588which should be an absolute path to this file, however Express
589and the `renderFile()` method do this for you. Include then parses
590these files, and injects the AST produced to render what you would expect:
591
592```html
593<html>
594 <head>
595 <title>My Site</title>
596 <script src="/javascripts/jquery.js">
597 </script><script src="/javascripts/app.js"></script>
598 </head>
599 <body>
600 <h1>My Site</h1>
601 <p>Welcome to my super lame site.</p>
602 <div id="footer">
603 <p>Copyright>(c) foobar</p>
604 </div>
605 </body>
606</html>
607```
608
609## Mixins
610
611 Mixins are converted to regular JavaScript functions in
612 the compiled template that Jade constructs. Mixins may
613 take arguments, though not required:
614
615 mixin list
616 ul
617 li foo
618 li bar
619 li baz
620
621 Utilizing a mixin without args looks similar, just without a block:
622
623 h2 Groceries
624 mixin list
625
626 Mixins may take one or more arguments as well, the arguments
627 are regular javascripts expressions, so for example the following:
628
629 mixin pets(pets)
630 ul.pets
631 - each pet in pets
632 li= pet
633
634 mixin profile(user)
635 .user
636 h2= user.name
637 mixin pets(user.pets)
638
639 Would yield something similar to the following html:
640
641```html
642<div class="user">
643 <h2>tj</h2>
644 <ul class="pets">
645 <li>tobi</li>
646 <li>loki</li>
647 <li>jane</li>
648 <li>manny</li>
649 </ul>
650</div>
651```
652
653## Generated Output
654
655 Suppose we have the following Jade:
656
657```
658- var title = 'yay'
659h1.title #{title}
660p Just an example
661```
662
663 When the `compileDebug` option is not explicitly `false`, Jade
664 will compile the function instrumented with `__.lineno = n;`, which
665 in the event of an exception is passed to `rethrow()` which constructs
666 a useful message relative to the initial Jade input.
667
668```js
669function anonymous(locals) {
670 var __ = { lineno: 1, input: "- var title = 'yay'\nh1.title #{title}\np Just an example", filename: "testing/test.js" };
671 var rethrow = jade.rethrow;
672 try {
673 var attrs = jade.attrs, escape = jade.escape;
674 var buf = [];
675 with (locals || {}) {
676 var interp;
677 __.lineno = 1;
678 var title = 'yay'
679 __.lineno = 2;
680 buf.push('<h1');
681 buf.push(attrs({ "class": ('title') }));
682 buf.push('>');
683 buf.push('' + escape((interp = title) == null ? '' : interp) + '');
684 buf.push('</h1>');
685 __.lineno = 3;
686 buf.push('<p>');
687 buf.push('Just an example');
688 buf.push('</p>');
689 }
690 return buf.join("");
691 } catch (err) {
692 rethrow(err, __.input, __.filename, __.lineno);
693 }
694}
695```
696
697When the `compileDebug` option _is_ explicitly `false`, this instrumentation
698is stripped, which is very helpful for light-weight client-side templates. Combining Jade's options with the `./runtime.js` file in this repo allows you
699to toString() compiled templates and avoid running the entire Jade library on
700the client, increasing performance, and decreasing the amount of JavaScript
701required.
702
703```js
704function anonymous(locals) {
705 var attrs = jade.attrs, escape = jade.escape;
706 var buf = [];
707 with (locals || {}) {
708 var interp;
709 var title = 'yay'
710 buf.push('<h1');
711 buf.push(attrs({ "class": ('title') }));
712 buf.push('>');
713 buf.push('' + escape((interp = title) == null ? '' : interp) + '');
714 buf.push('</h1>');
715 buf.push('<p>');
716 buf.push('Just an example');
717 buf.push('</p>');
718 }
719 return buf.join("");
720}
721```
722
723## bin/jade
724
725Output html to _stdout_:
726
727 jade < my.jade > my.html
728
729Generate _examples/*.html_:
730
731 jade examples/*.jade
732
733Pass options:
734
735 jade examples/layout.jade --options '{ locals: { title: "foo" }}'
736
737Usage info:
738
739 Usage: jade [options]
740 [path ...]
741 < in.jade > out.jade
742 Options:
743 -o, --options <str> JavaScript options object passed
744 -h, --help Output help information
745 -w, --watch Watch file(s) or folder(s) for changes and re-compile
746 -v, --version Output jade version
747 --out <dir> Output the compiled html to <dir>
748
749## License
750
751(The MIT License)
752
753Copyright (c) 2009-2010 TJ Holowaychuk &lt;tj@vision-media.ca&gt;
754
755Permission is hereby granted, free of charge, to any person obtaining
756a copy of this software and associated documentation files (the
757'Software'), to deal in the Software without restriction, including
758without limitation the rights to use, copy, modify, merge, publish,
759distribute, sublicense, and/or sell copies of the Software, and to
760permit persons to whom the Software is furnished to do so, subject to
761the following conditions:
762
763The above copyright notice and this permission notice shall be
764included in all copies or substantial portions of the Software.
765
766THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
767EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
768MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
769IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
770CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
771TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
772SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.