├── test
├── fixtures
│ ├── different.ext
│ ├── template.html
│ ├── interpolate.html
│ └── nested
│ │ ├── template.html
│ │ └── module.js
├── curl.html
├── dojo.html
├── requirejs.html
└── spec
│ ├── dojo.js
│ ├── requirejs.js
│ └── curl.js
├── .gitignore
├── .travis.yml
├── bower.json
├── package.json
├── Gruntfile.coffee
├── loader.js
└── README.md
/test/fixtures/different.ext:
--------------------------------------------------------------------------------
1 | It works!
2 |
--------------------------------------------------------------------------------
/test/fixtures/template.html:
--------------------------------------------------------------------------------
1 | It works!
2 |
--------------------------------------------------------------------------------
/test/fixtures/interpolate.html:
--------------------------------------------------------------------------------
1 | {{ msg }}
2 |
--------------------------------------------------------------------------------
/test/fixtures/nested/template.html:
--------------------------------------------------------------------------------
1 | It works!
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /test/reports/
2 | /bower_components/
3 | /node_modules/
4 |
--------------------------------------------------------------------------------
/test/fixtures/nested/module.js:
--------------------------------------------------------------------------------
1 | define(function(require, exports) {
2 | "use strict";
3 |
4 | exports.template = require("ldsh!./template");
5 | });
6 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - 0.8
4 |
5 | branches:
6 | only:
7 | - master
8 |
9 | before_install:
10 | - npm install -gq grunt-cli bower
11 | - bower install
12 |
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "lodash-template-loader",
3 | "version": "0.1.2",
4 | "main": "loader.js",
5 | "dependencies": {
6 | "lodash": "~2.2.0"
7 | },
8 | "devDependencies": {
9 | "qunit": "~1.12.0",
10 | "requirejs": "~2.1.8",
11 | "curl": "~0.8.2",
12 | "dojo": "~1.9.1"
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "lodash-template-loader",
3 | "version": "0.1.2",
4 | "description": "A Lo-Dash template loader plugin for AMD projects.",
5 | "main": "loader.js",
6 | "author": "Tim Branyen (@tbranyen)",
7 | "license": "MIT",
8 | "devDependencies": {
9 | "grunt-contrib-clean": "~0.5.0",
10 | "grunt": "~0.4.1",
11 | "grunt-contrib-jshint": "~0.6.4",
12 | "grunt-contrib-watch": "~0.5.3",
13 | "grunt-clear": "~0.2.1",
14 | "grunt-contrib-connect": "~0.5.0",
15 | "grunt-contrib-qunit": "~0.3.0"
16 | },
17 | "scripts": {
18 | "test": "grunt",
19 | "postinstall": "bower i -s"
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Gruntfile.coffee:
--------------------------------------------------------------------------------
1 | module.exports = ->
2 | @initConfig
3 |
4 | jshint: ["loader.js"]
5 |
6 | connect:
7 | test:
8 | options:
9 | port: 8000
10 |
11 | watch:
12 | files: ["loader.js", "test/**/*", "Gruntfile.coffee"]
13 | tasks: ["clear", "default"]
14 |
15 | qunit:
16 | test:
17 | options:
18 | urls: [
19 | "http://localhost:8000/test/requirejs.html"
20 | "http://localhost:8000/test/dojo.html"
21 | "http://localhost:8000/test/curl.html"
22 | ]
23 |
24 | @loadNpmTasks "grunt-contrib-jshint"
25 | @loadNpmTasks "grunt-contrib-watch"
26 | @loadNpmTasks "grunt-contrib-connect"
27 | @loadNpmTasks "grunt-contrib-qunit"
28 | @loadNpmTasks "grunt-clear"
29 |
30 | @registerTask "default", ["jshint", "connect", "qunit"]
31 |
--------------------------------------------------------------------------------
/test/curl.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Lo-Dash Template Loader: Curl Tests
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | test markup
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/test/dojo.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Lo-Dash Template Loader: Dojo Tests
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | test markup
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/test/requirejs.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Lo-Dash Template Loader: RequireJS Tests
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | test markup
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/test/spec/dojo.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Test Module: Dojo
3 | * Ensures that the loader loads and functions in Dojo.
4 | *
5 | */
6 | QUnit.module("dojo");
7 |
8 | asyncTest("AMD support", 1, function() {
9 | require({
10 | baseUrl: "../",
11 |
12 | paths: {
13 | lodash: "bower_components/lodash/dist/lodash",
14 | ldsh: "loader",
15 | fixtures: "test/fixtures"
16 | }
17 | }, ["ldsh!fixtures/template"], function(template) {
18 | ok(template(), "It works!");
19 |
20 | start();
21 | });
22 | });
23 |
24 | asyncTest("change extension", function() {
25 | require({
26 | lodashLoader: {
27 | ext: ".ext"
28 | }
29 | }, ["ldsh!fixtures/different"], function(template) {
30 | ok(template(), "It works!");
31 |
32 | start();
33 | });
34 | });
35 |
36 | asyncTest("templateSettings", function() {
37 | require({
38 | lodashLoader: {
39 | templateSettings: {
40 | "interpolate": /{{([\s\S]+?)}}/g
41 | }
42 | }
43 | }, ["ldsh!fixtures/interpolate"], function(template) {
44 | ok(template({ msg: "It works!" }), "It works!");
45 |
46 | start();
47 | });
48 | });
49 |
50 | asyncTest("relative paths", 1, function() {
51 | require(["fixtures/nested/module"], function(exports) {
52 | ok(exports.template(), "It works!");
53 |
54 | start();
55 | });
56 | });
57 |
--------------------------------------------------------------------------------
/test/spec/requirejs.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Test Module: RequireJS
3 | * Ensures that the loader loads and functions in RequireJS.
4 | *
5 | */
6 | QUnit.module("requirejs");
7 |
8 | asyncTest("AMD support", 1, function() {
9 | require.config({
10 | baseUrl: "../",
11 |
12 | paths: {
13 | lodash: "bower_components/lodash/dist/lodash",
14 | ldsh: "loader",
15 | fixtures: "test/fixtures"
16 | }
17 | });
18 |
19 | require(["ldsh!fixtures/template"], function(template) {
20 | ok(template(), "It works!");
21 |
22 | start();
23 | });
24 | });
25 |
26 | asyncTest("change extension", 1, function() {
27 | require({
28 | lodashLoader: {
29 | ext: ".ext"
30 | }
31 | }, ["ldsh!fixtures/different"], function(template) {
32 | ok(template(), "It works!");
33 |
34 | start();
35 | });
36 | });
37 |
38 | asyncTest("templateSettings", 1, function() {
39 | require({
40 | lodashLoader: {
41 | templateSettings: {
42 | "interpolate": /{{([\s\S]+?)}}/g
43 | }
44 | }
45 | }, ["ldsh!fixtures/interpolate"], function(template) {
46 | ok(template({ msg: "It works!" }), "It works!");
47 |
48 | start();
49 | });
50 | });
51 |
52 | asyncTest("relative paths", 1, function() {
53 | require(["fixtures/nested/module"], function(exports) {
54 | ok(exports.template(), "It works!");
55 |
56 | start();
57 | });
58 | });
59 |
--------------------------------------------------------------------------------
/test/spec/curl.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Test Module: Curl
3 | * Ensures that the loader loads and functions in Curl.
4 | *
5 | */
6 | /*global QUnit asyncTest curl ok start */
7 | QUnit.module("curl");
8 |
9 | curl.config({
10 | baseUrl: "../",
11 |
12 | paths: {
13 | "lodash": "bower_components/lodash/dist/lodash",
14 | "ldsh": "loader",
15 | "fixtures": "test/fixtures"
16 | }
17 | });
18 |
19 | asyncTest("AMD support", 1, function() {
20 | curl(["ldsh!fixtures/template"]).then(
21 | function(template) {
22 | ok(template(), "It works!");
23 |
24 | start();
25 | },
26 | function(ex) {
27 | ok(false, ex.message);
28 | start();
29 | }
30 | );
31 | });
32 |
33 | asyncTest("change extension", function() {
34 | curl({
35 | lodashLoader: {
36 | ext: ".ext"
37 | }
38 | }, ["ldsh!fixtures/different"]).then(
39 | function(template) {
40 | ok(template(), "It works!");
41 |
42 | start();
43 | },
44 | function(ex) {
45 | ok(false, ex.message);
46 | start();
47 | }
48 | );
49 | });
50 |
51 | asyncTest("templateSettings", function() {
52 | curl({
53 | lodashLoader: {
54 | templateSettings: {
55 | "interpolate": /{{([\s\S]+?)}}/g
56 | }
57 | }
58 | }, ["ldsh!fixtures/interpolate"]).then(
59 | function(template) {
60 | ok(template({ msg: "It works!" }), "It works!");
61 |
62 | start();
63 | },
64 | function(ex) {
65 | ok(false, ex.message);
66 | start();
67 | }
68 | );
69 | });
70 |
71 | asyncTest("relative paths", 1, function() {
72 | curl(["fixtures/nested/module"], function(exports) {
73 | ok(exports.template(), "It works!");
74 |
75 | start();
76 | });
77 | });
78 |
--------------------------------------------------------------------------------
/loader.js:
--------------------------------------------------------------------------------
1 | /* Lo-Dash Template Loader v0.1.2
2 | * Copyright 2013, Tim Branyen (@tbranyen).
3 | * loader.js may be freely distributed under the MIT license.
4 | */
5 | (function(global) {
6 | "use strict";
7 |
8 | // Cache used to map configuration options between load and write.
9 | var buildMap = {};
10 |
11 | // Alias the correct `nodeRequire` method.
12 | var nodeRequire = typeof requirejs === "function" && requirejs.nodeRequire;
13 |
14 | // If in Node, get access to the filesystem.
15 | if (nodeRequire) {
16 | var fs = nodeRequire("fs");
17 | }
18 |
19 | // Define the plugin using the CommonJS syntax.
20 | define(function(require, exports) {
21 | var _ = require("lodash");
22 |
23 | exports.version = "0.1.2";
24 |
25 | // Invoked by the AMD builder, passed the path to resolve, the require
26 | // function, done callback, and the configuration options.
27 | exports.load = function(name, req, load, config) {
28 | // Dojo provides access to the config object through the req function.
29 | if (!config) {
30 | config = require.rawConfig;
31 | }
32 |
33 | var settings = configure(config);
34 |
35 | // Builds must happen with Node.
36 | if (config.isBuild) {
37 | var path = settings.root + name + settings.ext;
38 |
39 | // Read in the file synchronously, as RequireJS expects, and return the
40 | // contents. Process as a Lo-Dash template.
41 | buildMap[name] = _.template(String(fs.readFileSync(path)));
42 |
43 | return load();
44 | }
45 |
46 | // Create a basic XHR.
47 | var xhr = new XMLHttpRequest();
48 |
49 | // Wait for it to load.
50 | xhr.onreadystatechange = function() {
51 | if (xhr.readyState === 4) {
52 | // Process as a Lo-Dash template and cache.
53 | buildMap[name] = _.template(xhr.responseText);
54 |
55 | // Return the compiled template.
56 | load(buildMap[name]);
57 | }
58 | };
59 |
60 | // Initiate the fetch.
61 | xhr.open("GET", "/" + settings.root + name + settings.ext, true);
62 | xhr.send(null);
63 | };
64 |
65 | // Also invoked by the AMD builder, this writes out a compatible define
66 | // call that will work with loaders such as almond.js that cannot read
67 | // the configuration data.
68 | exports.write = function(pluginName, moduleName, write) {
69 | var template = buildMap[moduleName].source;
70 |
71 | // Write out the actual definition
72 | write(strDefine(pluginName, moduleName, template));
73 | };
74 |
75 | // This is for curl.js/cram.js build-time support.
76 | exports.compile = function(pluginName, moduleName, req, io, config) {
77 | configure(config);
78 |
79 | // Ask cram to fetch the template file (resId) and pass it to `write`.
80 | io.read(moduleName, write, io.error);
81 |
82 | function write(template) {
83 | // Write-out define(id,function(){return{/* template */}});
84 | io.write(strDefine(pluginName, moduleName, template));
85 | }
86 | };
87 |
88 | // Crafts the written definition form of the module during a build.
89 | function strDefine(pluginName, moduleName, template) {
90 | return [
91 | "define('", pluginName, "!", moduleName, "', ", "[], ",
92 | [
93 | "function() {",
94 | "return ", template, ";",
95 | "}"
96 | ].join(""),
97 | ");\n"
98 | ].join("");
99 | }
100 |
101 | function configure(config) {
102 | // Default settings point to the project root and using html files.
103 | var settings = _.extend({
104 | ext: ".html",
105 | root: config.baseUrl,
106 | templateSettings: {}
107 | }, config.lodashLoader);
108 |
109 | // Set the custom passed in template settings.
110 | _.extend(_.templateSettings, settings.templateSettings);
111 |
112 | return settings;
113 | }
114 | });
115 |
116 | })(typeof global === "object" ? global : this);
117 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Lo-Dash AMD Template Loader
2 | ---------------------------
3 |
4 | [](https://travis-ci.org/tbranyen/lodash-template-loader)
5 |
6 | Created by Tim Branyen [@tbranyen](http://twitter.com/tbranyen)
7 |
8 | RequireJS, Dojo, and Curl are excellent module loaders, but through the
9 | flexibility of plugin architecture they should really be seen as resource
10 | loaders.
11 |
12 | We've come to expect our development environments to be raw and our builds to
13 | be as optimized as possible. This plugin will fetch your Lo-Dash templates
14 | during development and inline them in a production build.
15 |
16 | Unlike [requirejs-tpl](https://github.com/ZeeAgency/requirejs-tpl) it does not
17 | use a hardcoded template function, but instead uses the exact one from your
18 | copy of Lo-Dash. Consistency is a key difference here.
19 |
20 | Almost every single article and tutorial on using client side templates with
21 | AMD, will advocate the use of the RequireJS text! plugin. While this is a fine
22 | tool for loading text, it is not optimized for templates. It requires the
23 | duplicative act of compiling the templates before use in production.
24 |
25 | ### Installing: ###
26 |
27 | This plugin has been registered with Bower, install with:
28 |
29 | ``` bash
30 | bower install lodash-template-loader
31 | ```
32 |
33 | Alternatively you can download the `loader.js` file and place anywhere in your
34 | project.
35 |
36 | ### Loading the plugin: ###
37 |
38 | ``` javascript
39 | require.config({
40 | paths: {
41 | // You can change the plugin name to be whatever you want, maybe tpl?
42 | "ldsh": "path/to/lodash-template-loader/loader"
43 | }
44 | });
45 | ```
46 |
47 | You must not end the path in `.js` unless you are providing a url.
48 |
49 | Examples:
50 |
51 | * `vendor/libraries/loader`
52 | * `http://cdn.mysite.com/vendor/libraries/loader.js`
53 |
54 | ### Using: ###
55 |
56 | Inside an AMD module you can now load templates like so:
57 |
58 | ``` javascript
59 | // Omit the extension and root path.
60 | define(["ldsh!path/to/template"], function(template) {
61 | var contents = template({
62 | // Some data.
63 | });
64 | });
65 | ```
66 |
67 | The path to your templates directory can be configured as well as the default
68 | extension to search for. More details below.
69 |
70 | ### Configuring templateSettings: ###
71 |
72 | There are a few default settings in place to make consumption easier.
73 |
74 | The extension appended by default is `.html`. The default root path is your
75 | configuration's `baseUrl`. No `templateSettings` are configured by default.
76 |
77 | To change these options, add the following to your configuration:
78 |
79 | ``` javascript
80 | require.config({
81 | // The Lo-Dash loader configuration.
82 | lodashLoader: {
83 | // This is the default extension, you can change to whatever you like.
84 | // Setting this to "" will disable automatic extensions.
85 | ext: ".html",
86 |
87 | // The path to where your templates live relative to the `baseUrl`.
88 | root: "/",
89 |
90 | // Globally configured template settings to be applied to any templates
91 | // loaded. This correlates directly to `_.templateSettings`.
92 | templateSettings: {}
93 | }
94 | });
95 | ```
96 |
97 | ### What about Underscore? ###
98 |
99 | I've decided to go with the compatible `.source` attribute for obtaining the
100 | template function source string, which makes this plugin work with Underscore
101 | as well. You'll have to manually map the resource identifier which is
102 | explained in detail below.
103 |
104 | ### Mapping Underscore to Lo-Dash: ###
105 |
106 | In order to use Underscore with this plugin, you must map the identifier.
107 | Internally the plugin specifically looks for the identifier `lodash`. In the
108 | configuration simply:
109 |
110 | ``` javascript
111 | require.config({
112 | // Define a new object literal, named map.
113 | map: {
114 | // Ensure the mapping works globally across any modules using this plugin.
115 | "*": {
116 | // Map the lodash identifier to whatever module you want here.
117 | "lodash": "underscore"
118 | }
119 | }
120 | });
121 | ```
122 |
123 | ### Using with Dojo: ###
124 |
125 | Ensure Dojo's loader is in `async` mode:
126 |
127 | ``` html
128 |
129 | ```
130 |
131 | Set up your configuration:
132 |
133 | ``` javascript
134 | require({
135 | paths: {
136 | "ldsh": "path/to/loader"
137 | }
138 | });
139 | ```
140 |
141 | And Require in your template:
142 |
143 | ``` javascript
144 | require(["ldsh!path/to/template"], function(template) {
145 | var contents = template({
146 | // Some data.
147 | });
148 | });
149 | ```
150 |
151 | ### Using with Curl: ###
152 |
153 | Set up your configuration:
154 |
155 | ``` javascript
156 | curl.config({
157 | paths: {
158 | "ldsh": "path/to/loader"
159 | }
160 | });
161 | ```
162 |
163 | And Curl in your template:
164 |
165 | ``` javascript
166 | curl(["ldsh!path/to/template"], function(template) {
167 | var contents = template({
168 | // Some data.
169 | });
170 | });
171 | ```
172 |
173 | ### Running tests ###
174 |
175 | You will need Node.js and Grunt installed to run tests.
176 |
177 | Clone this project, open the directory in a terminal, and execute the following
178 | commands:
179 |
180 | ``` bash
181 | # Install dependencies.
182 | npm i -q
183 |
184 | # Run the tests.
185 | grunt
186 | ```
187 |
188 | You can also run an http-server in the root and hit the tests directly. Since
189 | XHR is used, tests must be run from a server.
190 |
191 | ### Release notes: ###
192 |
193 | #### 0.1.2 ####
194 |
195 | * Resolved issue with baseUrl concatenation to moduleName.
196 |
197 | #### 0.1.1 ####
198 |
199 | * Hotfix for building in r.js projects.
200 |
201 | #### 0.1.0 ####
202 |
203 | * Open sourced on GitHub.
204 |
--------------------------------------------------------------------------------