Angular Templates

Precompiling all AngularJS HTML templates into single javascript bundle.

Background

When I write AngularJs, all I want to do is to write custom directives. The power to create new HTML elements went to my head really quickly. The directives can take HTML markup either using template property, or via external URL specified via templateUrl property.

1
2
3
4
5
6
7
app.directive('colorPusher', colorPusherDirective);
function colorPusherDirective() {
return {
restrict: 'E',
templateUrl: 'color-pusher.tpl.html'
};
}

A good example with several widgets is color-pusher directive with its corresponding color-pusher.tpl.html template, part of color-pusher project.

When AngularJs creates the color-pusher element it looks inside its templateCache to see if there is something under color-pusher.tpl.html key. If not, it makes an Ajax request, received the template, stores it in the cache and returns to the rendering function.

Keeping templates separate from the rest of the code means every template is a separate request. If you custom directive depends on other custom directives, the templates and javascript requests waterfall, causing slow initial page load.

Template HTML -> JavaScript

There is a work around: you can put stuff into templateCache yourself, for example as part of the build process. All you need is to convert HTML source into JavaScript

widget.tpl.html
1
2
3
4
5
6
7
8
<div>something</div>
<script>
// put then content of widget.tpl.html into templateCache yourself
// widget.tpl.js
angular.module("widget.tpl.html", []).run(["$templateCache", function($templateCache) {
$templateCache.put("widget.tpl.html", "<div>something</div>");
}]);
</script>

Then change your directive to depend on the template module

widget.js
1
2
3
4
5
6
7
app.module('widget', ['widget.tpl.html']);
app.directive('widget', function () {
return {
restrict: 'E',
templateUrl: 'widget.tpl.html'
};
});

During the build step, concatenate both widget.tpl.js and widget.js together in any order (AngularJs dependency resolution will sort out the order). That's it, you don't need separate template download.

Build using grunt and html2js

Converting AngularJs templates to JavaScript is very simple using grunt-html2js. Look at the example Gruntfile.js

1
2
3
4
5
6
7
8
9
10
11
12
13
// html2js goal inside Gruntfile.js
html2js: {
main: {
options: {
base: 'src',
module: 'widget.templates'
// add angular dependency on `widget.templates`
},
src: [ 'src/*.tpl.html' ],
dest: 'tmp/<%= pkg.name %>.templates.js'
// include tmp/*.templates.js as URL or in concatenate step
}
}