Skip to content

Commit 78d80de

Browse files
committed
Initial commit
0 parents  commit 78d80de

9 files changed

+317
-0
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
.idea
2+
node_modules

README.md

+108
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
# Angular Template loader for webpack
2+
3+
Puts HTML partials in the Angular's $templateCache so directives can use templates without initial downloading.
4+
5+
## Webpack and loaders
6+
7+
Webpack is the [webpack](http://webpack.github.io/) and it's module bundler. [Loaders](http://webpack.github.io/docs/using-loaders.html) wrap content in the javascript code that executes in the browser.
8+
9+
# Install
10+
11+
`npm install ng-cache-loader`
12+
13+
# Usage
14+
15+
You can require html partials via `ng-cache-loader`:
16+
17+
``` javascript
18+
require('ng-cache!./demo/template/myPartial.html');
19+
```
20+
21+
Partial will be available as `ng-include="'myPartial.html'"`
22+
or `templateUrl: 'myPartial.html'`.
23+
24+
## Named templates
25+
26+
You can wrap template in the `script` tag:
27+
28+
``` html
29+
<!-- ./demo/template/myPartial.html -->
30+
31+
<script type ="text/ng-template" id="myFirstTemplate">
32+
<!-- then use ng-include="'myFirstTemplate'" -->
33+
</script>
34+
```
35+
36+
You can have multiple templates in one file:
37+
38+
``` html
39+
<!-- ./demo/template/myPartial.html -->
40+
41+
<script type ="text/ng-template" id="myFirstTemplate">
42+
<!-- then use ng-include="'myFirstTemplate'" -->
43+
</script>
44+
45+
<script type ="text/ng-template" id="mySecondTemplate">
46+
<!-- then use ng-include="'mySecondTemplate'" -->
47+
</script>
48+
```
49+
50+
You can mix named templates and simple markup:
51+
52+
``` html
53+
<!-- ./demo/template/myPartial.html -->
54+
55+
<script type ="text/ng-template" id="myFirstTemplate">
56+
<!-- then use ng-include="'myFirstTemplate'" -->
57+
</script>
58+
59+
<!-- markup outside script tags available as ng-include="'myPartial.html'" -->
60+
<div>...</div>
61+
62+
<script type ="text/ng-template" id="mySecondTemplate">
63+
<!-- then use ng-include="'mySecondTemplate'" -->
64+
</script>
65+
```
66+
67+
## Prefix
68+
69+
Prefix adds path left of template name:
70+
71+
``` javascript
72+
require('ng-cache?prefix=public/templates!./path/to/myPartial.html')
73+
// => ng-include="'public/templates/myPartial.html'"
74+
```
75+
76+
Prefix can mask the real directory with the explicit value
77+
or retrieve the real directory name (use `[dir]`):
78+
79+
``` javascript
80+
require('ng-cache?prefix=public/[dir]/templates!./path/to/myPartial.html')
81+
// => ng-include="'public/path/templates/myPartial.html'"
82+
```
83+
84+
Prefix can strip the real directory name (use `//`):
85+
86+
``` javascript
87+
require('ng-cache?prefix=public/[dir]//[dir]/templates!./far/far/away/path/to/myPartial.html')
88+
// => ng-include="'public/far/path/templates/myPartial.html'"
89+
```
90+
91+
## webpack config
92+
93+
Match `.html` extension with loader:
94+
95+
``` javascript
96+
module: {
97+
loaders: [
98+
{
99+
test: /.html$/,
100+
loader: "ng-cache?prefix=[dir]/[dir]"
101+
}
102+
]
103+
},
104+
```
105+
106+
# License
107+
108+
MIT (http://www.opensource.org/licenses/mit-license.php)

index.js

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
var htmlMinifier = require("html-minifier");
2+
var parser = require('./lib/scriptParser.js');
3+
var getTemplateId = require('./lib/templateId.js');
4+
5+
var stub = 'angular.module(["ng"])' +
6+
'.run(["$templateCache", function (c) {\n' +
7+
' c.put("$key", $val);' +
8+
'\n}]);';
9+
10+
module.exports = function (source) {
11+
var result = [],
12+
scripts,
13+
html,
14+
scr;
15+
16+
this.cacheable && this.cacheable();
17+
18+
source = htmlMinifier.minify(source, {
19+
removeComments: true,
20+
collapseWhitespace: true,
21+
removeRedundantAttributes: true,
22+
removeEmptyAttributes: true
23+
});
24+
scripts = parser.parse("root", source, { scripts: [] }).scripts;
25+
source = Array.prototype.slice.apply(source);
26+
27+
// Prepare named templates
28+
while (scripts.length) {
29+
scr = scripts.pop();
30+
html = source
31+
.splice(scr.idx, scr.len)
32+
.splice(scr.contIdx, scr.contLen)
33+
.join('');
34+
if (scr.id) {
35+
result.push({
36+
key: scr.id,
37+
val: JSON.stringify(html)
38+
});
39+
} else {
40+
source.splice(scr.idx, 0, html);
41+
}
42+
}
43+
// Prepare the ramaining templates (means w/o `script` tag or w/o `id` attribute)
44+
source = source.join('');
45+
if (/[^\s]/.test(source)) {
46+
result.push({
47+
key: getTemplateId.apply(this),
48+
val: JSON.stringify(source)
49+
});
50+
}
51+
52+
result.forEach(function (res, i) {
53+
result[i] = stub.replace(/\$([\w\d_\-]+)/g, function (match, name) {
54+
return res[name] ? res[name] : match;
55+
});
56+
});
57+
return result.join('\n');
58+
};

lib/scriptParser.js

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
var Parser = require('fastparse');
2+
3+
module.exports = new Parser({
4+
root: {
5+
'<script': function (match, idx) {
6+
this.idx = idx;
7+
return 'scriptTag';
8+
},
9+
'<\\/script[\\s\\n]*>': function (match, idx, len) {
10+
if (this.isTemplate) {
11+
this.scripts.push({
12+
id: this.id, // template name
13+
idx: this.idx, // script begin index
14+
len: idx + len - this.idx, // script including final script tag length
15+
contIdx: this.contIdx, // content begin index
16+
contLen: idx - this.idx - this.contIdx // content up to final script tag length
17+
});
18+
}
19+
this.isTemplate = this.idx = this.contIdx = this.id = undefined;
20+
}
21+
},
22+
scriptTag: {
23+
'type[\\s\\n]*=[\\s\\n]*[\'\"]': 'typeAttr',
24+
'id[\\s\\n]*=[\\s\\n]*[\'\"]': 'idAttr',
25+
'>': function (match, idx) {
26+
this.contIdx = idx - this.idx + 1;
27+
return 'root';
28+
}
29+
},
30+
typeAttr: {
31+
'text/ng-template': function () {
32+
this.isTemplate = true;
33+
},
34+
'[\'\"]': 'scriptTag'
35+
},
36+
idAttr: {
37+
'[^\'\"\\s\\n]+': function (match) {
38+
this.id = match;
39+
},
40+
'[\'\"]': 'scriptTag'
41+
}
42+
});

lib/templateId.js

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
var loaderUtils = require("loader-utils");
2+
3+
module.exports = function () {
4+
var query = loaderUtils.parseQuery(this.query),
5+
resource = this.resource.split('/'),
6+
fileName = resource.pop(),
7+
prefix,
8+
dir,
9+
i;
10+
11+
if (!query.prefix) {
12+
return fileName;
13+
}
14+
resource.reverse();
15+
prefix = query.prefix.split('/');
16+
i = prefix.length;
17+
while (i--) {
18+
dir = prefix.pop();
19+
if (dir !== '[dir]') {
20+
resource[0] = dir;
21+
}
22+
dir = resource.shift();
23+
if (dir || !i) {
24+
prefix.unshift(dir);
25+
}
26+
}
27+
prefix.push(fileName);
28+
return prefix.join('/');
29+
};

package.json

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
{
2+
"name": "ng-cache-loader",
3+
"version": "0.0.1",
4+
"description": "Puts HTML partials in the Angular's $templateCache.",
5+
"main": "index.js",
6+
"scripts": {
7+
"test": "./node_modules/webpack/bin/webpack.js --config=test/webpack.config.js"
8+
},
9+
"keywords": [
10+
"angular",
11+
"template",
12+
"cache",
13+
"webpack",
14+
"loader"
15+
],
16+
"author": "Andrey Koperskiy",
17+
"license": "MIT",
18+
"devDependencies": {
19+
"webpack": "^1.4.3"
20+
},
21+
"dependencies": {
22+
"fastparse": "^1.0.0",
23+
"html-minifier": "^0.6.8",
24+
"loader-utils": "^0.2.4"
25+
},
26+
"directories": {
27+
"test": "test"
28+
},
29+
"repository": {
30+
"type": "git",
31+
"url": "https://github.com/teux/ng-cache-loader.git"
32+
},
33+
"bugs": {
34+
"url": "https://github.com/teux/ng-cache-loader/issues"
35+
},
36+
"homepage": "https://github.com/teux/ng-cache-loader"
37+
}

test/entry.js

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
require('./src/template.html');

test/src/template.html

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<script type ="text/ng-template" id="myTemplate">
2+
<div class="view">
3+
<h2>First View</h2>
4+
<p>
5+
Search:<input type="text" ng-model="filterText" />
6+
</p>
7+
</div>
8+
</script>
9+
10+
<div class="view">
11+
<h2>Second View</h2>
12+
<p>About me</p>
13+
</div>
14+
15+
<script type="text/ng-template" id="myAnotherTemplate">
16+
<div class="view">
17+
<p>...</p>
18+
</div>
19+
</script>
20+
21+
<div class="view">
22+
<h2>Second View</h2>
23+
<p>About you</p>
24+
</div>
25+
26+
<script type="text/ng-template">
27+
<div class="view"></div>
28+
</script>

test/webpack.config.js

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
module.exports = {
2+
entry: './test/entry.js',
3+
output: {
4+
path: './test/out',
5+
filename: '[name].out.js'
6+
},
7+
module: {
8+
loaders: [
9+
{ test: /\.html$/, loader: '../index.js?prefix=grot/[dir]//[dir]//tmpl' }
10+
]
11+
}
12+
};

0 commit comments

Comments
 (0)