Skip to content

Commit 3ba8bc9

Browse files
committed
Added functionality to create statically compiled templates.
Updated Templates library to use a wrapper function instead of arguments.callee to reference the tmpl object.
1 parent 2fceec9 commit 3ba8bc9

File tree

9 files changed

+178
-29
lines changed

9 files changed

+178
-29
lines changed

README.md

Lines changed: 35 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@ Include the (minified) JavaScript Templates script in your HTML markup:
1212
<script src="tmpl.min.js"></script>
1313
```
1414

15-
Add a script section with type **"text/html"** and your template definition as content:
15+
Add a script section with type **"text/x-tmpl"**, a unique **id** property and your template definition as content:
1616

1717
```html
18-
<script type="text/html" id="tmpl-demo">
18+
<script type="text/x-tmpl" id="tmpl-demo">
1919
<h3>{%=o.title%}</h3>
2020
<p>Released under the
2121
<a href="{%=o.license.url%}">{%=o.license.name%}</a>.</p>
@@ -104,7 +104,7 @@ require("http").createServer(function (req, res) {
104104
console.log("Loading " + filename);
105105
return fs.readFileSync(filename, "utf8");
106106
};
107-
res.writeHead(200, {"Content-Type": "text/html"});
107+
res.writeHead(200, {"Content-Type": "text/x-tmpl"});
108108
// Render the content:
109109
res.end(tmpl("template", data));
110110
}).listen(8080, "localhost");
@@ -143,14 +143,15 @@ document.getElementById("result").innerHTML = func(data);
143143
```
144144

145145
### Templates cache
146-
Templates loaded by id are cached in the map **tmpl.cache**, which can be modified:
146+
Templates loaded by id are cached in the map **tmpl.cache**:
147147

148148
```js
149-
var func = tmpl("tmpl-demo");
150-
var cached = typeof tmpl.cache["tmpl-demo"] === "function"; // true
149+
var func = tmpl("tmpl-demo"), // Loads and parses the template
150+
cached = typeof tmpl.cache["tmpl-demo"] === "function", // true
151+
result = tmpl("tmpl-demo", data); // Uses cached template function
151152

152-
tmpl.cache["tmpl-demo"] = tmpl("<h3>{%=o.title%}</h3>");
153-
var result = tmpl("tmpl-demo", {title: "JS"}); // Renders "<h3>JS</h3>"
153+
tmpl.cache["tmpl-demo"] = null;
154+
result = tmpl("tmpl-demo", data); // Loads and parses the template again
154155
```
155156

156157
### Output encoding
@@ -174,11 +175,11 @@ var output = tmpl.encode("<>&\"'\x00"); // Renders "&lt;&gt;&amp;&quot;&#39;"
174175
The local variables available inside the templates are the following:
175176

176177
* **o**: The data object given as parameter to the template function (see the next section on how to modify the parameter name).
178+
* **tmpl**: A reference to the **tmpl** function object.
177179
* **_s**: The string for the rendered result content.
178-
* **_t**: A reference to the **tmpl** function object.
179180
* **_e**: A reference to the **tmpl.encode** method.
180-
* **print**: Function to add content to the rendered result string.
181-
* **include**: Function to include the return value of a different template in the result.
181+
* **print**: Helper function to add content to the rendered result string.
182+
* **include**: Helper function to include the return value of a different template in the result.
182183

183184
To introduce additional local helper variables, the string **tmpl.helper** can be extended. The following adds a convenience function for *console.log* and a streaming function, that streams the template rendering result back to the callback argument (note the comma at the beginning of each variable declaration):
184185

@@ -190,7 +191,7 @@ tmpl.helper += ",log=function(){console.log.apply(console, arguments)}" +
190191
Those new helper functions could be used to stream the template contents to the console output:
191192

192193
```html
193-
<script type="text/html" id="tmpl-demo">
194+
<script type="text/x-tmpl" id="tmpl-demo">
194195
<h3>{%=o.title%}</h3>
195196
{% stream(log); %}
196197
<p>Released under the
@@ -305,5 +306,27 @@ For loop:
305306
</ul>
306307
```
307308

309+
## Compiled templates
310+
The JavaScript Templates project comes with a compilation script, that allows you to compile your templates into JavaScript code and combine them with a minimal Templates runtime into one minified JavaScript file.
311+
312+
The compilation script is built for [node.js](http://nodejs.org/) and also requires [UglifyJS](https://github.com/mishoo/UglifyJS).
313+
To use it, first install both the JavaScript Templates project and UglifyJS via [npm](http://npmjs.org/):
314+
315+
```sh
316+
npm install uglify-js
317+
npm install blueimp-tmpl
318+
```
319+
320+
This will put the executables **uglifyjs** and **tmpl.js** into the folder **node_modules/.bin**. It will also make them available on your PATH if you install the packages globally (by adding the **-g** flag to the install command).
321+
322+
The **tmpl.js** executable accepts the paths to one or multiple template files as command line arguments and prints the generated JavaScript code to the console output. The following command line shows you how to store the generated code in a new JavaScript file that can be included in your project:
323+
324+
```sh
325+
tmpl.js templates/upload.html templates/download.html > tmpl.min.js
326+
```
327+
328+
The files given as command line arguments to **tmpl.js** can either be pure template files or HTML documents with embedded template script sections. For the pure template files, the file names (without extension) serve as template ids.
329+
The generated file can be included in your project as a replacement for the original **tmpl.js** runtime. It provides you with the same API and provides a **tmpl(id, data)** function that accepts the id of one of your templates as first and a data object as optional second parameter.
330+
308331
## License
309332
The JavaScript Templates script is released under the [MIT license](http://www.opensource.org/licenses/MIT).

compile.js

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
#!/usr/bin/env node
2+
/*
3+
* JavaScript Templates Compiler 2.0
4+
* https://github.com/blueimp/JavaScript-Templates
5+
*
6+
* Copyright 2011, Sebastian Tschan
7+
* https://blueimp.net
8+
*
9+
* Licensed under the MIT license:
10+
* http://www.opensource.org/licenses/MIT
11+
*/
12+
13+
/*jslint nomen: true */
14+
/*global require, __dirname, process, console */
15+
16+
(function () {
17+
"use strict";
18+
var tmpl = require("./tmpl.js").tmpl,
19+
fs = require("fs"),
20+
jsp = require("uglify-js").parser,
21+
pro = require("uglify-js").uglify,
22+
// Retrieve the content of the minimal runtime:
23+
runtime = fs.readFileSync(__dirname + "/runtime.js", "utf8"),
24+
// A regular expression to parse templates from script tags in a HTML page:
25+
regexp = /<script( id="([\w\-]+)")? type="text\/x-tmpl"( id="([\w\-]+)")?>([\s\S]+?)<\/script>/gi,
26+
// A regular expression to match the helper function names:
27+
helperRegexp = new RegExp(
28+
tmpl.helper.match(/\w+(?=\s*=\s*function\s*\()/g).join("\\s*\\(|") + "\\s*\\("
29+
),
30+
// A list to store the function bodies:
31+
list = [],
32+
code,
33+
ast;
34+
// Extend the Templating engine with a print method for the generated functions:
35+
tmpl.print = function (str) {
36+
var helper = helperRegexp.test(str) ? tmpl.helper : "";
37+
return "function(" + tmpl.arg + ",tmpl){" +
38+
("var _s='',_e=tmpl.encode" + helper + ";_s+='" +
39+
str.replace(tmpl.regexp, tmpl.func) +
40+
"';return _s;").split("_s+='';").join("") +
41+
"}";
42+
};
43+
// Loop through the command line arguments:
44+
process.argv.forEach(function (file, index) {
45+
var listLength = list.length,
46+
content,
47+
result,
48+
id;
49+
// Skipt the first two arguments, which are "node" and the script:
50+
if (index > 1) {
51+
content = fs.readFileSync(file, "utf8");
52+
while (true) {
53+
// Find templates in script tags:
54+
result = regexp.exec(content);
55+
if (!result) {
56+
break;
57+
}
58+
id = result[2] || result[4];
59+
list.push("'" + id + "':" + tmpl.print(result[5]));
60+
}
61+
if (listLength === list.length) {
62+
// No template script tags found, use the complete content:
63+
list.push("'" + id + "':" + tmpl.print(content));
64+
}
65+
}
66+
});
67+
// Combine the generated functions as cache of the minimal runtime:
68+
code = runtime.replace("{}", "{" + list.join(",") + "}");
69+
// Parse the code and get the initial AST (Abstract Syntac Tree):
70+
ast = jsp.parse(code);
71+
// Get a new AST with mangled names:
72+
ast = pro.ast_mangle(ast);
73+
// Get an AST with compression optimizations:
74+
ast = pro.ast_squeeze(ast);
75+
// Generate the code and print it to the console output:
76+
console.log(pro.gen_code(ast));
77+
}());

index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<!DOCTYPE HTML>
22
<!--
33
/*
4-
* JavaScript Templates Demo 1.0.3
4+
* JavaScript Templates Demo 2.0
55
* https://github.com/blueimp/JavaScript-Templates
66
*
77
* Copyright 2011, Sebastian Tschan

package.json

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "blueimp-tmpl",
3-
"version": "1.0.2",
3+
"version": "2.0.0",
44
"title": "JavaScript Templates",
55
"description": "< 1KB lightweight, fast & powerful JavaScript templating engine with zero dependencies. Compatible with server-side environments like node.js, module loaders like RequireJS and all web browsers.",
66
"keywords": [
@@ -32,11 +32,15 @@
3232
],
3333
"devDependencies": {
3434
"mocha": "latest",
35-
"expect.js": "latest"
35+
"expect.js": "latest",
36+
"uglify-js": "latest"
3637
},
3738
"scripts": {
3839
"test": "mocha --reporter spec"
3940
},
41+
"bin": {
42+
"tmpl.js": "./compile.js"
43+
},
4044
"files": [
4145
"tmpl.js"
4246
],

runtime.js

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* JavaScript Templates Runtime 2.0
3+
* https://github.com/blueimp/JavaScript-Templates
4+
*
5+
* Copyright 2011, Sebastian Tschan
6+
* https://blueimp.net
7+
*
8+
* Licensed under the MIT license:
9+
* http://www.opensource.org/licenses/MIT
10+
*/
11+
12+
/*jslint sloppy: true */
13+
/*global define */
14+
15+
(function ($) {
16+
var tmpl = function (id, data) {
17+
var f = tmpl.cache[id];
18+
return data ? f(data, tmpl) : function (data) {
19+
return f(data, tmpl);
20+
};
21+
};
22+
tmpl.cache = {};
23+
tmpl.encReg = /[<>&"\x00]/g;
24+
tmpl.encMap = {
25+
"<": "&lt;",
26+
">": "&gt;",
27+
"&": "&amp;",
28+
"\"": "&quot;",
29+
"\x00": ""
30+
};
31+
tmpl.encode = function (s) {
32+
return String(s || "").replace(
33+
tmpl.encReg,
34+
function (c) {
35+
return tmpl.encMap[c];
36+
}
37+
);
38+
};
39+
if (typeof define === "function" && define.amd) {
40+
define(function () {
41+
return tmpl;
42+
});
43+
} else {
44+
$.tmpl = tmpl;
45+
}
46+
}(this));

test/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<!DOCTYPE HTML>
22
<!--
33
/*
4-
* JavaScript Templates Test 1.0.1
4+
* JavaScript Templates Test 2.0
55
* https://github.com/blueimp/JavaScript-Templates
66
*
77
* Copyright 2011, Sebastian Tschan

test/test.js

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* JavaScript Templates Test 1.0.2
2+
* JavaScript Templates Test 2.0
33
* https://github.com/blueimp/JavaScript-Templates
44
*
55
* Copyright 2011, Sebastian Tschan
@@ -72,9 +72,8 @@
7272
it('Cache templates loaded by id', function () {
7373
tmpl('template');
7474
expect(
75-
tmpl.cache.template(data),
76-
'value'
77-
);
75+
tmpl.cache.template
76+
).to.be.a('function');
7877
});
7978

8079
});

tmpl.js

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* JavaScript Templates 1.0.2
2+
* JavaScript Templates 2.0
33
* https://github.com/blueimp/JavaScript-Templates
44
*
55
* Copyright 2011, Sebastian Tschan
@@ -21,13 +21,14 @@
2121
var f = !/[^\-\w]/.test(str) ? tmpl.cache[str] = tmpl.cache[str] ||
2222
tmpl(tmpl.load(str)) :
2323
new Function(
24-
tmpl.arg,
25-
("var _s=''" + tmpl.helper + ";_s+='" +
24+
tmpl.arg + ',tmpl',
25+
("var _s='',_e=tmpl.encode" + tmpl.helper + ";_s+='" +
2626
str.replace(tmpl.regexp, tmpl.func) +
2727
"';return _s;").split("_s+='';").join("")
2828
);
29-
f.tmpl = f.tmpl || tmpl;
30-
return data ? f(data) : f;
29+
return data ? f(data, tmpl) : function (data) {
30+
return f(data, tmpl);
31+
};
3132
};
3233
tmpl.cache = {};
3334
tmpl.load = function (id) {
@@ -71,9 +72,8 @@
7172
);
7273
};
7374
tmpl.arg = "o";
74-
tmpl.helper = ",_t=arguments.callee.tmpl,_e=_t.encode" +
75-
",print=function(s,e){_s+=e&&(s||'')||_e(s);}" +
76-
",include=function(s,d){_s+=_t(s,d);}";
75+
tmpl.helper = ",print=function(s,e){_s+=e&&(s||'')||_e(s);}" +
76+
",include=function(s,d){_s+=tmpl(s,d);}";
7777
if (typeof define === "function" && define.amd) {
7878
define(function () {
7979
return tmpl;

tmpl.min.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)