diff --git a/README.md b/README.md index b339f7450..d2bcc38aa 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ engine.render(tpl, {name: 'alice'}); // Alice ```javascript var engine = Liquid({ - root: path.resolve(__dirname, 'views/'), + root: path.resolve(__dirname, 'views/'), // for layouts and partials extname: '.liquid', cache: false }); @@ -49,6 +49,14 @@ var html = engine.renderFile("hello.html", {name: 'alice'}); `cache` default to `false`, `extname` default to `.liquid`, `root` default to `""`. +## Use with Express.js + +```javascript +app.engine('liquid', engine.express()); +app.set('views', './views'); // specify the views directory +app.set('view engine', 'liquid'); // register the template engine +``` + ## Includes ``` diff --git a/index.js b/index.js index f57f46b80..f0c798994 100644 --- a/index.js +++ b/index.js @@ -10,8 +10,8 @@ const Tag = require('./src/tag.js'); const Filter = require('./src/filter.js'); const Template = require('./src/parser'); const Expression = require('./src/expression.js'); -const tagsPath = path.join(__dirname, "tags/"); -const filtersPath = path.join(__dirname, "filters.js"); +const tags = require('./tags'); +const filters = require('./filters'); var _engine = { init: function(tag, filter, options) { @@ -23,6 +23,10 @@ var _engine = { this.filter = filter; this.parser = Template(tag, filter); this.renderer = Render(); + + tags(this); + filters(this); + return this; }, parse: function(html) { @@ -54,12 +58,22 @@ var _engine = { handleCache: function(filepath) { assert(filepath, 'filepath cannot be null'); filepath = path.resolve(this.options.root, filepath); - if(path.extname(filepath) === ''){ + if (path.extname(filepath) === '') { filepath += this.options.extname; } var tpl = this.options.cache && this.cache[filepath] || this.parse(fs.readFileSync(filepath, 'utf8')); return this.options.cache ? (this.cache[filepath] = tpl) : tpl; + }, + express: function() { + return (filePath, options, callback) => { + try { + var html = this.renderFile(filePath, options); + return callback(null, html); + } catch (e) { + return callback(e); + } + }; } }; @@ -71,19 +85,9 @@ function factory(options) { var engine = Object.create(_engine); engine.init(Tag(), Filter(), options); - registerTagsAndFilters(engine); return engine; } -function registerTagsAndFilters(engine) { - fs.readdirSync(tagsPath).map(f => { - var match = /^(\w+)\.js$/.exec(f); - if (!match) return; - require("./tags/" + f)(engine); - }); - require(filtersPath)(engine); -} - factory.lexical = lexical; factory.isTruthy = Expression.isTruthy; factory.isFalsy = Expression.isFalsy; diff --git a/src/express.js b/src/express.js new file mode 100644 index 000000000..245484a0b --- /dev/null +++ b/src/express.js @@ -0,0 +1,19 @@ +const Liquid = require('..'); + +module.exports = function() { + + var engine = Liquid({ + root: '/root/', + extname: '.html' + }); + function express(filePath, options, callback) { + fs.readFile(filePath, function(err, content) { + if (err) return callback(new Error(err)); + // this is an extremely simple template engine + var rendered = content.toString().replace('#title#', '
{{arr | join: "_"}}
'); engine.render(template, ctx).should.equal('-2_a
'); }); - it('should render file', function(){ - engine.renderFile('/root/files/foo.html', ctx).should.equal('foo'); - }); - it('should render file relative to root', function(){ - engine.renderFile('files/foo.html', ctx).should.equal('foo'); - }); - it('should render file with context', function(){ - engine.renderFile('/root/files/name.html', ctx).should.equal('My name is harttle.'); - }); - it('should render file with default extname', function() { - engine.renderFile('files/name', ctx).should.equal('My name is harttle.'); - }); - it('should disable cache by default', function(){ - mock({ - '/root/files/foo.html': 'bar' + describe('#renderFile()', function(){ + it('should render file', function() { + engine.renderFile('/root/files/foo.html', ctx).should.equal('foo'); + }); + it('should render file relative to root', function() { + engine.renderFile('files/foo.html', ctx).should.equal('foo'); + }); + it('should render file with context', function() { + engine.renderFile('/root/files/name.html', ctx).should.equal('My name is harttle.'); + }); + it('should render file with default extname', function() { + engine.renderFile('files/name', ctx).should.equal('My name is harttle.'); }); - engine.renderFile('files/foo', ctx).should.equal('bar'); }); - it('should respect cache option', function(){ - mock.restore(); - engine = Liquid({ - root: '/root/', - extname: '.html', - cache: true + describe('#express()', function() { + it('should render templates', function() { + engine.express()('/root/files/name.html', ctx, function(err, html) { + expect(err).to.equal(null); + expect(html).to.equal('My name is harttle.'); + }); }); - mock({ - '/root/files/foo.html': 'foo' + it('should pass error when file not found', function() { + engine.express()('/root/files/name1.html', ctx, function(err, html) { + expect(err.code).to.equal('ENOENT'); + }); }); - engine.renderFile('files/foo', ctx).should.equal('foo'); - mock({ - '/root/files/foo.html': 'bar' + }); + describe('cache', function() { + it('should be disabled by default', function() { + mock({ + '/root/files/foo.html': 'bar' + }); + engine.renderFile('files/foo', ctx).should.equal('bar'); + }); + it('should respect cache=true option', function() { + engine = Liquid({ + root: '/root/', + extname: '.html', + cache: true + }); + engine.renderFile('files/foo', ctx).should.equal('foo'); + mock({ + '/root/files/foo.html': 'bar' + }); + engine.renderFile('files/foo', ctx).should.equal('foo'); }); - engine.renderFile('files/foo', ctx).should.equal('foo'); }); });