Tenjin - the fastest template engine in the world
description
Transcript of Tenjin - the fastest template engine in the world
The Fastest Template Engine in the World
Makoto Kuwatahttp://www.kuwata-lab.com/
Tenjin
YAPC::ASIA 20081
copyright(c) 2008 kuwata-lab.com all rights reserved.
Agenda
‣ Introduction
‣ Features
‣ Preprocessing
‣ Conclusion
2
copyright(c) 2008 kuwata-lab.com all rights reserved.
Introduction
YAPC::ASIA 20083
copyright(c) 2008 kuwata-lab.com all rights reserved.
Tenjin - a template engine‣ Very fast•About x5 faster than Template-Toolkit
‣ Full-featured•Layout, partial, capturing, ...
‣ Easy to use•You can get all power of Perl
‣ Multi-language•Perl, Python, Ruby, PHP, JavaScript
4
copyright(c) 2008 kuwata-lab.com all rights reserved.
Example (html template)
<table> <?pl my $i = 0; ?> <?pl for my $item (@$items) { ?> <?pl $i++; ?> <tr> <td>[==$i=]</td> <td>[=$item=]</td> </tr> <?pl } ?> </table>
Perl statements
Perl expression
Perl expression(with html escape)
5
copyright(c) 2008 kuwata-lab.com all rights reserved.
Example (converted script)
my @_buf = (); push(@_buf, q`<table>`, ); my $i = 0;for my $item (@$items) { $i++;push(@_buf, q` <tr> <td>`, $i, q`</td> <td>`, escape($item), q`</td> </tr>`, ); }push(@_buf, q`</table>`, ); join('', @_buf);
Returns joined String
Escape function is changeable
Temporary list
6
copyright(c) 2008 kuwata-lab.com all rights reserved.
Example (main program)
## create engineuse Tenjin;$Tenjin::USE_STRICT=1; # optionalmy $engine = new Tenjin::Engine();
## render template with context datamy $context = { 'items' => ['<AAA>','B&B','"CCC"'] };my $output = $engine->render('ex.plhtml', $context);print $output;
Choosable to use strict or not
7
copyright(c) 2008 kuwata-lab.com all rights reserved.
Example (output)<table> <tr> <td>1</td> <td><AAA></td> </tr> <tr> <td>2</td> <td>B&B</td> </tr> <tr> <td>3</td> <td>"CCC"</td> </tr> </table>
Spaces around '<?pl .. ?>' are trimmed
[=expression=] is html escaped
8
copyright(c) 2008 kuwata-lab.com all rights reserved.
Benchmark
Tenjin 10.4 5.7Template::Toolkit (XS) 103.6 26.3
HTM::Template 46.7 30.2Velocity 1.5 (Java) 20.8 8.4
Template Engine Test#1 Test#2
(sec)• Generates a 400-line HTML page 10,000 times• Test#1 generates template objects for each time (like CGI)• Test#2 uses the same template object for each time (like modperl)• Environment: MacOS X 10.4, Intel CoreDuo 1.83GHz
9
copyright(c) 2008 kuwata-lab.com all rights reserved.
Benchmark
0
500
1,000
1,500
2,000
Tenjin TT H::T Velocity
Test#1 Test#2Pages/sec
10
copyright(c) 2008 kuwata-lab.com all rights reserved.
Why so fast?
‣ Tenjin uses Perl as the template lang
•Perl is fast, rich, and easy to learn (because you already know it!)
‣ Other template engines have their own template languages
•Slow, poor, and you have to learn them
11
copyright(c) 2008 kuwata-lab.com all rights reserved.
Impact to app speed (1)
after
before
0 25 50 75 100
M&C V
• Assume that the view-layer costs 25%.• Making view-layer 5 times faster results in a 25% speed increase.
25% faster!
75 25
75 5
12
copyright(c) 2008 kuwata-lab.com all rights reserved.
Impact to app speed (2)
after
before
0 25 50 75 100
M&C V
• Assume the view-layer costs 60%.• Making the view-layer 6 times faster results in a 100% speed increase.
100% faster!
40 60
40 10
13
copyright(c) 2008 kuwata-lab.com all rights reserved.
Features
YAPC::ASIA 200814
copyright(c) 2008 kuwata-lab.com all rights reserved.
Features‣ Nestable layout
templates
‣ Include partial templates
‣ Capture a part of output
‣ Override a part of layout template
‣ Script cache into file & memory
‣ Template arguments
‣ Retrieve only code from template
‣ Syntax checking
15
copyright(c) 2008 kuwata-lab.com all rights reserved.
Nestable layout template
<html> <body>[==$_content=] </body></html>
<div>[==$_content=]</div>
Parent layout Child layout Content
<p>Hello [=$user=]!</p>
• Nestable to any depth• Able to specify parent name in child
(useful to change the layout for a specific page)
16
copyright(c) 2008 kuwata-lab.com all rights reserved.
Include partial template
<?pl $_context->{val}='Create'; ?><form action="create"><?pl include('form.plhtml'); ?></form>
create.plhtml
<?pl $_context->{val}='Update'; ?><form action="update"><?pl include('form.plhtml'); ?></form>
update.plhtml<input><select><textarea>
form.plhtml
17
copyright(c) 2008 kuwata-lab.com all rights reserved.
Capture & overwrite
<?pl if (!captured_as('head')) { ?><h1>[=$title=]</h1><?pl } ?>
Layout
<?pl start_capture('head'); ?><h1 class="h1">[=$title=]</h1><?pl stop_capture(); ?>
Content
Capturing
Overwritten if captured in child template
18
copyright(c) 2008 kuwata-lab.com all rights reserved.
Script cache
Template
Script(Perl,Ruby,JS,...)
Closure, Proc
Cache script into file(minimize cost of conversion)
Cache script into memory(as fast as function/method)
19
copyright(c) 2008 kuwata-lab.com all rights reserved.
Template arguments
<?xml version="1.0" ?><?pl #@ARGS title, items ?><h1>[=$title=]</h1>
my @_buf=(); push(@_buf, ...);my $title = $_context->{title}; my $items = $_context->{items}; push(@_buf, ...);
Script
Template
20
copyright(c) 2008 kuwata-lab.com all rights reserved.
Retrieve code
<table><?pl my $i = 0; ?><?pl for my $item in (@$items) { ?><?pl $i += 1; ?> <tr> <td>[==$i=]</td> <td>[=$item=]</td> </tr><?pl } ?></table>
$ cat file.plhtml
21
copyright(c) 2008 kuwata-lab.com all rights reserved.
Retrieve code
my $i = 0; for my $item in (@$items) { $i += 1;
$i; escape($item);
}
$ pltenjin -bS file.plhtml
Retrieve only Perl code
22
copyright(c) 2008 kuwata-lab.com all rights reserved.
Retrieve code
my $i = 0; for my $item in (@$items) { $i += 1;
}
$ pltenjin -bX file.plhtml
Retrieve only statements
23
copyright(c) 2008 kuwata-lab.com all rights reserved.
Retrieve code
1: 2: my $i = 0; 3: for my $item in (@$items) { 4: $i += 1; 5: 6: 7: 8: 9: }10:
$ pltenjin -bXN file.plhtml
Add line numbers
24
copyright(c) 2008 kuwata-lab.com all rights reserved.
Retrieve code
1: 2: my $i = 0; 3: for my $item in (@$items) { 4: $i += 1;
9: }
$ pltenjin -bXU file.plhtml
Compress empty lines
25
copyright(c) 2008 kuwata-lab.com all rights reserved.
Preprocessing
YAPC::ASIA 200826
copyright(c) 2008 kuwata-lab.com all rights reserved.
What is Preprocessing?
Template
Script(Perl,Ruby,JS,...)
Output(html)
convert
render
Logics are executedwhen rendering
Execute some logicswhen conversion(preprocessing)
27
copyright(c) 2008 kuwata-lab.com all rights reserved.
Stages
<p>[=$DOMAIN=]</p> <p>[*=$DOMAIN=*]</p>
preprocess
convert
<p>example.com</p>
push(@_buf, q`<p>`, $DOMAIN, q`</p>`, );
render
<p>example.com</p>
convert
push(@_buf, q`<p>example.com</p>`, );
preprocessing disabled preprocessing enabled
render
<p>example.com</p>
28
copyright(c) 2008 kuwata-lab.com all rights reserved.
Merits & Demerits
‣ Merits
• Makes view-layer much faster
• Removes costs of I18N/L10N, helper functions, and so on.
‣ Demerits
• Complex
• Hard to debug (line number will be changed)
• Expensive learning cost
29
copyright(c) 2008 kuwata-lab.com all rights reserved.
Notation
‣ <?PL ...statements... ?>
‣ [*== ...expression... =*]
‣ [*= ...expr (with html escape)... =*]
‣ _p("expression"), _P("expression")•returns "[=expression=]", "[==expression=]"
30
copyright(c) 2008 kuwata-lab.com all rights reserved.
I18N & L10NTemplate
Preprocessed
[=i18n('Hello')=] [=$name=]![*=i18n('Hello')=*] [=$name=]!
[=i18n('Hello')=] [=$name=]!こんにちは [=$name=]!
push(@_buf, i18n('Hello'), ' ', $name, '!こんにちは ', $name, '!', ); ...
Converted Script
Remove I18N overhead
preprocess
convert
31
copyright(c) 2008 kuwata-lab.com all rights reserved.
Helper functions[*= link_to(_P('$item->{name}'), { action=>'show', id=>_p('$item->{id}') }) =*]
<a href="/items/show/[==$item->{id}=]"> [=$item->{name}=]</a>
Eliminates cost of helper funcions
_p('x') <=> [=x=], _P('x') <=> [==x=]
Template
Preprocessedpreprocess
32
copyright(c) 2008 kuwata-lab.com all rights reserved.
Loop expansionTemplate
Preprocessed
<select><?PL my $i = 0; ?><?PL for my $m (@$months) { ?> <option value="[[==++$i=]]">[[=$m=]]</option><?PL } ?></select>
<select> <option value="1">January</option> <option value="2">February</option> <option value="3">March</option> ...</select> Expanded BEFORE rendering
preprocessExecuted at conversion statge
33
copyright(c) 2008 kuwata-lab.com all rights reserved.
Mixed preprocessing(1)Template
<select><?pl my %h = ($params->{month} => ' selected'); ?><?PL my $i = 0; ?><?PL for my $m (@$months) { ?> <option value="[*==++$i=*]"[==$h{[*==$i=*]}=]>[*=$m=*]</option><?PL } ?></select> Mixed preprocessing
34
copyright(c) 2008 kuwata-lab.com all rights reserved.
Mixed preprocessing(2)Preprocessed
<select><?pl my %h = ($params->{month} => ' selected'); ?> <option value="1"[==$h{1}=]>January</option> <option value="2"[==$h{2}=]>February</option> <option value="3"[==$h{3}=]>March</option> ...</select>
Non-preprocessing code is leaved
35
copyright(c) 2008 kuwata-lab.com all rights reserved.
Conclusion
YAPC::ASIA 200836
copyright(c) 2008 kuwata-lab.com all rights reserved.
Conclusion (1)
‣ Tenjin - a fast template engine•Very fast & lightweight
•Full-featured
•Easy to use
•Preprocessing
•Available in multi-language
•http://www.kuwata-lab.com/tenjin/
37
copyright(c) 2008 kuwata-lab.com all rights reserved.
Conclusion (2)
‣ Template-original lang is bad idea•Slow, poor, complicated
•High cost to learn
‣ Perl itself is the best template lang
•Fast, rich, simple
•You already know it very well!
38
copyright(c) 2008 kuwata-lab.com all rights reserved.
Any questions?
39
copyright(c) 2008 kuwata-lab.com all rights reserved.
One more minute...
40
copyright(c) 2008 kuwata-lab.com all rights reserved.
Kwartz - Designer Friendly Template System
<?xml ver="1.0" ?><html><body><table> <tr id="mark:list1"> <td id="mark:item1">foo</td> </tr></table></body></html>
#list1 { logic: { for my $item (@$items) { _stag; # start tag _cont; # content _etag; # end tag } }}
#item1 { value: $item; # print value}
template file presentation logic file
Plain Old HTML CSS-like Syntax
Interested?Go http://www.kuwata-lab.com/kwartz/
41
copyright(c) 2008 kuwata-lab.com all rights reserved.
Thank You
42