Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

underscore-template-loader

Package Overview
Dependencies
Maintainers
1
Versions
23
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

underscore-template-loader - npm Package Compare versions

Comparing version 0.4.1 to 0.5.0

lib/attributeParser.js

150

index.js

@@ -1,7 +0,1 @@

var path = require('path');
var fs = require('fs');
var url = require("url");
var loaderUtils = require('loader-utils');
var attributeParser = require('./parser');
try {

@@ -14,40 +8,29 @@ var _ = require('underscore');

module.exports = function() {
var includeRegex = /<@include\s+([\/\w\.]*?[\w]+\.[\w]+)>/g;
var path = require('path');
var loaderUtils = require('loader-utils');
// Returns a template file content
var readFile = function(filepath, root) {
var self = readFile;
self.buffer = self.buffer || {};
// Parsers
var attributeParser = require('./lib/attributeParser');
var macroParser = require('./lib/macroParser');
if (filepath in self.buffer) {
return self.buffer[filepath];
}
// Extendable arguments
var macros = _.extend({}, require('./lib/macros'));
var content = readContent(fs.readFileSync(path.join(root, filepath), 'utf8'), root);
self.buffer[filepath] = content;
return self.buffer[filepath];
};
return function(content) {
this.cacheable && this.cacheable();
var callback = this.async();
// Parses an external file content
var readContent = function(content, root) {
var matches = includeRegex.exec(content);
// Default arguments
var root,
parseMacros = true,
attributes = ['img:src'];
while (matches != null) {
var file = loaderUtils.urlToRequest(matches[1]);
var rawContent = readFile(path.basename(file), path.join(root, path.dirname(file)));
content = content.replace(matches[0], rawContent);
matches = includeRegex.exec(content);
}
return content;
};
return function(content) {
// Parse arguments
var query = loaderUtils.parseQuery(this.query);
var root = query.root;
var attributes = ['img:src'];
if (_.isObject(query)) {
root = query.root;
// Apply template settings
_.each(_.pick(query, 'interpolate', 'escape', 'evaluate', 'attributes', 'prependFilenameComment'), function(value, key) {
_.each(_.pick(query, 'interpolate', 'escape', 'evaluate'), function(value, key) {
_.templateSettings[key] = new RegExp(value, 'g');

@@ -61,77 +44,46 @@ });

// Set include regex
if (query.includeRegex !== undefined) {
includeRegex = new RegExp(query.includeRegex, 'g');
// Parse / ignore macros
if (query.parseMacros !== undefined) {
parseMacros = !!query.parseMacros;
}
}
// Generates a random string for further proccessing
var randomIdent = function() {
return "@@@URL" + Math.random() + "@@@";
};
// Obtain external resource links
var links = attributeParser(content, function(tag, attr) {
return attributes.indexOf(tag + ':' + attr) >= 0;
});
links.reverse();
// Parse external resources
var data = {};
content = [content];
links.forEach(function(link) {
// Ignore absolute paths
if (/^\//.exec(link.value) && root == false) {
return;
// Prepend a html comment with the filename in it
if (query.prependFilenameComment) {
var filename = loaderUtils.getRemainingRequest(this);
var filenameRelative = path.relative(query.prependFilenameComment, filename);
content = "\n<!-- " + filenameRelative + " -->\n" + content;
}
}
if (!loaderUtils.isUrlRequest(link.value, root)) {
return;
}
// Include additional macros
if (_.isObject(this.options.macros)) {
_.extend(macros, this.options.macros);
}
var uri = url.parse(link.value);
if (uri.hash !== null && uri.hash !== undefined) {
uri.hash = null;
link.value = uri.format();
link.length = link.value.length;
}
// Parse macros
if (parseMacros) {
var macrosContext = macroParser(content, function (macro) {
return _.isFunction(macros[macro]);
}, 'MACRO');
content = macrosContext.replaceMatches(content);
}
do {
var ident = randomIdent();
} while (data[ident]);
// Parse attributes
var attributesContext = attributeParser(content, function (tag, attr) {
return attributes.indexOf(tag + ':' + attr) != -1;
}, 'ATTRIBUTE', root);
content = attributesContext.replaceMatches(content);
data[ident] = link.value;
var x = content.pop();
content.push(x.substr(link.start + link.length));
content.push(ident);
content.push(x.substr(0, link.start));
});
content.reverse();
content = content.join('');
// Compile template
var source = _.template(content).source;
this.cacheable && this.cacheable();
var callback = this.async();
// Read file content
content = readContent(content, this.context);
// Prepend a html comment with the filename in it
if (query.prependFilenameComment) {
var filename = loaderUtils.getRemainingRequest(this);
var filenameRelative = path.relative(query.prependFilenameComment, filename);
content = "\n<!-- " + filenameRelative + " -->\n" + content;
// Resolve macros
if (parseMacros) {
source = macrosContext.resolveMacros(source, macros);
}
// Replace random generated strings with require
var source = _.template(content).source;
content = source.replace(/@@@URL[0-9\.]+@@@/g, function(match) {
if (!data[match]) {
return match;
}
// Resolve attributes
source = attributesContext.resolveAttributes(source);
return "' + require(" + JSON.stringify(loaderUtils.urlToRequest(data[match], root)) + ") + '";
});
callback(null, "module.exports = " + content + ";");
callback(null, "module.exports = " + source + ";");
};

@@ -138,0 +90,0 @@ }();

{
"name": "underscore-template-loader",
"version": "0.4.1",
"version": "0.5.0",
"description": "An Underscore and Lodash template loader for Webpack",

@@ -5,0 +5,0 @@ "main": "index.js",

@@ -6,36 +6,38 @@ underscore-template-loader

<br/>
<br>
###Installation
<br/>
<br>
```bash
$ npm install underscore-template-loader
npm install underscore-template-loader
```
<br>
Make sure you have the `underscore` or `lodash` package installed.
<br/>
<br>
###Usage
<br/>
<br>
```javascript
module.exports = {
//...
loaders: [
//...
{ test: /\.html$/, loader: "underscore-template-loader" }
]
module: {
loaders: [
{ test: /\.html$/, loader: "underscore-template-loader" }
]
},
};
```
<br/>
<br>
####Loading templates
<br/>
<br>
```html
<!-- file: hello.html -->
<!-- File: hello.html -->
<p>Hello&nbsp;<%=name%></p>
```
<br>
```javascript

@@ -46,23 +48,28 @@ var compiled = require('./hello.html');

<br/>
<br>
####Prepending filename comment
<br>
When debugging a large single page app with the DevTools, it's often hard to find the template that contains a bug. With the following config a HTML comment is prepended to the template with the relative path in it (e.g. `<!-- view/user/edit.html -->`).
<br>
```javascript
module.exports = {
//...
loaders: [
//...
{
test: /\.html$/,
loader: "underscore-template-loader",
query: {
prependFilenameComment: __dirname,
module: {
loaders: [
{
test: /\.html$/,
loader: "underscore-template-loader",
query: {
prependFilenameComment: __dirname,
}
}
}
]
]
}
};
```
<br/>
<br>
####Template settings

@@ -74,67 +81,102 @@

//...
loaders: [
//...
{
test: /\.html$/,
loader: "underscore-template-loader",
query: {
interpolate : '\\{\\[(.+?)\\]\\}',
evaluate: '\\{%([\\s\\S]+?)%\\}',
escape : '\\{\\{(.+?)\\}\\}'
}
}
]
module: {
loaders: [
//...
{
test: /\.html$/,
loader: "underscore-template-loader",
query: {
interpolate : '\\{\\[(.+?)\\]\\}',
evaluate: '\\{%([\\s\\S]+?)%\\}',
escape : '\\{\\{(.+?)\\}\\}'
}
}
]
}
};
```
<br/>
####Include tag
<br>
####Images
<br/>
<br>
In order to load images you must install either the *file-loader* or the *url-loader* package.
<br>
```javascript
module.exports = {
//...
module: {
loaders: [
{ test: /\.html$/, loader: "underscore-template-loader" },
{ test: /\.jpg$/, loader: "file-loader" },
{ test: /\.png$/, loader: "url-loader?mimetype=image/png" },
]
}
};
```
<br>
```html
<!-- file: main.html -->
<p>Hello, <@include message.html></p>
<!-- Require image using file-loader -->
<img src="img/portrait.jpg">
<!-- Require image using url-loader -->
<img src="img/icon.png">
```
<br>
Images with an absolute path are not translated unless a `root` argument is defined
<br>
```html
<!-- file: message.html -->
<em>how are you?</em>
<!-- Using root = undefined => no translation -->
<img src="/not_translated.jpg">
<!-- Using root = 'images' => require('images/image.jpg') -->
<img src="/image.jpg">
```
<br/>
Include tag can be overrided through the *includeRegex* argument.
<br>
In order to deactivate image processing define `attributes` as an empty array.
<br/>
```javascript
module.exports = {
//...
loaders: [
//...
{
test: /\.html$/,
loader: "underscore-template-loader",
query: {
includeRegex: '<#include\\s+([\\/\\w\\.]*?[\\w]+\\.[\\w]+)>'
}
}
]
module: {
loaders: [
{
test: /\.html$/,
loader: "underscore-template-loader",
query: {
attributes: []
}
}
]
}
};
```
<br/>
####Images
<br>
You could also add which attributes need to be processed in the form of pairs *tag:attribute*.
<br/>
In order to load images you must install either the *file-loader* or the *url-loader* packages.
```javascript
module.exports = {
//...
loaders: [
//...
{ test: /\.html/, loader: "underscore-template-loader" },
{ test: /\.jpg$/, loader: "file-loader" },
{ test: /\.png$/, loader: "url-loader?mimetype=image/png" },
]
module: {
loaders: [
//...
{
test: /\.html$/,
loader: "underscore-template-loader",
query: {
attributes: ['img:src', 'x-img:src']
}
}
]
}
};

@@ -144,71 +186,125 @@ ```

<br>
###Macros
<br>
Macros allow additional features like including templates or inserting custom text in compiled templates.
<br>
####The *require* macro
<br>
The `require` macro expects a path to a underscore template. The macro is then translated into a webpack require expression that evaluates the template using the same arguments.
<br>
```html
<!-- Require image using file-loader -->
<img src="img/portrait.jpg">
<h4>Profile</h4>
<!-- Require image using url-loader -->
<img src="img/icon.png">
Name: <strong><%=name%></strong>
<br>
Surname: <strong><%=surname%></strong>
<div class="profile-details">
@require('profile-details.html')
</div>
```
<br/>
Images with an absolute path are not translated unless a *root* argument is defined
<br>
####The *include* macro
<br>
While the `require` macro expects a resource that returns a function, the `include` macro can be used for resources that return plain text. For example, we can include text loaded through the `html-loader` directly in our template.
```html
<!-- Using root = undefined => no translation -->
<img src="/not_translated.jpg">
<div class="wiki">
<h3>Introduction</h3>
@include('intro.htm')
<h3>Authors</h3>
@include('authors.htm')
</div>
```
<!-- Using root = 'images' => require('images/image.jpg') -->
<img src="/image.jpg">
<br>
####'br' and 'nl'
<br>
The `br` and `nl` macros insert a `<br>` tag and a new line respectively. They accept a optional argument with the amount of strings to insert.
```html
<p>Lorem ipsum</p>
@br(3)
<p>Sit amet</p>
@nl()
```
<br>
In order to deactivate image processing define *attributes* as an empty array.
####Custom macros
<br>
We can include additional macros by defining them in the webpack configuration file. Remember that the value returned by a macro is inserted as plain javascript, so in order to insert a custom text we need to use nested quotes. For example, let's say that we want a macro that includes a copyright string in our template.
<br>
```javascript
// File: webpack.config.js
module.exports = {
//...
loaders: [
//...
{
test: /\.html$/,
loader: "underscore-template-loader",
query: {
attributes: []
}
// ...
module: {
loaders: {
// ...
{ test: /\.html$/, loader: "underscore-template-loader" },
}
]
};
},
macros: {
'copyright': function () {
return "'<p>Copyright FakeCorp 2014 - 2015</p>'";
}
}
}
```
<br/>
<br>
We then invoke this macro from within the template as usual.
You could also add which attributes need to be processed in the form of pairs *tag:attribute*.
<br>
```html
<footer>
@copyright()
</footer>
```
<br>
####Disabling macros
<br>
You can disable macros if you are a bit unsure about their usage or just simply want faster processing. This is achieved by setting the `parseMacros` options to false.
<br>
```javascript
module.exports = {
//...
loaders: [
//...
{
test: /\.html$/,
loader: "underscore-template-loader",
query: {
attributes: ['img:src', 'x-img:src']
}
// ...
module: {
loaders: {
// ...
{
test: /\.html$/,
loader: "underscore-template-loader",
query: {
parseMacros: false
}
},
}
]
};
}
}
```
<br/>
<br>
####Known issues
<br/>
* Trying to use different template settings (interpolate, escape, evaluate) for different extensions. Underscore/Lodash template settings are defined globally.
* Attributes not parsed on included templates (needs fix).
<br>
* Trying to use different template settings (interpolate, escape, evaluate) for different extensions. Underscore / Lodash template settings are defined globally.
<br/>
<br>
###License
Released under the MIT license.
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc