Make loading template from String template source easier

This commit is contained in:
Phillip Gates-Idem 2015-10-06 10:28:14 -04:00
parent 620e2bc010
commit c90b1bf885
4 changed files with 124 additions and 11 deletions

View File

@ -7,21 +7,68 @@ JavaScript API
## Methods
### load(templatePath[, options]) : Template
### load(templatePath[, templateSrc][, options]) : Template
Loads a template instance for the given template path.
Both `templateSrc` and `options` are optional.
Example usage:
Template loading is supported in the browser and on
the server but the behavior differs slightly.
**On the server,**
if `templateSrc` is not provided then `templatePath` is expected
to be the path to a Marko template file. If `templateSrc`
is provided then it is expected to be a `String` and its value
will be the raw template. The `templatePath`
argument is only used for reporting error stack traces if
`templateSrc` is provided.
**In the browser,**
`templatePath` is expected to path to be the module name
of the compiled template and the module will be loaded
via `require(templatePath)`. The `templateSrc` argument
is ignored if the `load` function is called in the browser.
If `options` is provided then it is expected to be the last argument
and should be an `Object`.
Example usage for browser and server:
```javascript
var templatePath = require.resolve('./template.marko');
var template = require('marko')require('marko')(templatePath);
var template = require('marko').load(templatePath);
template.render({ name: 'Frank' }, process.stdout);
```
Example **server-side** template loading with `writeToDisk: false` option:
```javascript
var templatePath = './sample.marko';
var template = require('marko').load(templatePath, {writeToDisk: false});
template.render({ name: 'Frank' }, process.stdout);
```
Example **server-side** template compilation from string:
```javascript
var templatePath = 'sample.marko';
var templateSrc = 'Hello $!{data.name}';
var template = require('marko').load(templatePath, templateSrc);
template.render({ name: 'Frank' }, process.stdout);
```
Supported `options`:
- `buffer` (`boolean`) - If `true` (default) then rendered output will be buffered until `out.flush()` is called or until rendering is completed. Otherwise, the output will be written to the underlying stream as soon as it is produced.
- `buffer` (`Boolean`) - If `true` (default) then rendered output will be
buffered until `out.flush()` is called or until rendering is completed.
Otherwise, the output will be written to the underlying stream as soon as
it is produced.
- `writeToDisk` (`Boolean`) - This option is only applicable to server-side
template loading. If `true` then compiled template will be written to disk.
If `false`, template will be compiled and loaded but the compiled source
will not be written to disk.
### createWriter([stream]) : AsyncWriter

View File

@ -37,7 +37,6 @@ function loadSource(templatePath, compiledSrc) {
templateModule.paths = Module._nodeModulePaths(nodePath.dirname(templateModulePath));
templateModule.filename = templateModulePath;
templateModule._compile(
compiledSrc,
templateModulePath);
@ -69,13 +68,32 @@ function loadFile(templatePath) {
return require(targetFile);
}
module.exports = function load(templatePath) {
if (markoCompiler.defaultOptions.writeToDisk === false) {
module.exports = function load(templatePath, templateSrc, options) {
var writeToDisk;
if (options && (options.writeToDisk != null)) {
// options is provided and options.writeToDisk is non-null
writeToDisk = options.writeToDisk;
} else {
// writeToDisk should be inferred from defaultOptions
writeToDisk = markoCompiler.defaultOptions.writeToDisk;
}
// If the template source is provided then we can compile the string
// in memory and there is no need to read template file from disk or
// write compiled code to disk.
//
// If writeToDisk is false then there will be no up-to-date check
// since compiled source won't be written to disk.
if ((templateSrc != null) || (writeToDisk === false)) {
// Don't write the compiled template to disk. Instead, load it
// directly from the compiled source using the internals of the
// Node.js module loading system.
var compiler = markoCompiler.createCompiler(templatePath);
var templateSrc = fs.readFileSync(templatePath, fsReadOptions);
if (templateSrc === undefined) {
templateSrc = fs.readFileSync(templatePath, fsReadOptions);
}
var compiledSrc = compiler.compile(templateSrc);
return loadSource(templatePath, compiledSrc);
} else {

View File

@ -268,22 +268,38 @@ function initTemplate(rawTemplate, templatePath) {
return template;
}
function load(templatePath, options) {
function load(templatePath, templateSrc, options) {
if (!templatePath) {
throw new Error('"templatePath" is required');
}
if (arguments.length === 1) {
// templateSrc and options not provided
} else if (arguments.length === 2) {
// see if second argument is templateSrc (a String)
// or options (an Object)
var lastArg = arguments[arguments.length - 1];
if (typeof lastArg !== 'string') {
options = arguments[1];
templateSrc = undefined;
}
} else if (arguments.length === 3) {
// assume function called according to function signature
} else {
throw new Error('Illegal arguments');
}
var template;
if (typeof templatePath === 'string') {
template = initTemplate(loader(templatePath), templatePath);
template = initTemplate(loader(templatePath, templateSrc, options), templatePath);
} else if (templatePath.render) {
template = templatePath;
} else {
template = initTemplate(templatePath);
}
if (options) {
if (options && (options.buffer != null)) {
template = new Template(
template.path,
createRenderProxy(template),

View File

@ -394,4 +394,36 @@ describe('marko/api' , function() {
}
});
it('should allow a template to be loaded from source', function() {
var template;
var templatePath;
// Make sure calling load with templatePath:String, templateSrc:String arguments works
templatePath = nodePath.join(__dirname, 'dummy.marko');
template = marko.load(templatePath, 'Hello $!{data.name}!');
expect(template.renderSync({name: 'Frank'})).to.equal('Hello Frank!');
// Make sure calling load with templatePath:String, templateSrc:String, options:Object arguments works
templatePath = nodePath.join(__dirname, 'dummy.marko');
template = marko.load(templatePath, 'Hello $!{data.name}!', {});
expect(template.renderSync({name: 'Frank'})).to.equal('Hello Frank!');
// Make sure calling load with templatePath:String, options:Object arguments works
delete require('../compiler').defaultOptions.writeToDisk;
templatePath = nodePath.join(__dirname, 'fixtures/write-to-disk/template.marko');
var compiledPath = nodePath.join(__dirname, 'fixtures/write-to-disk/template.marko.js');
try {
fs.unlinkSync(compiledPath);
} catch(e) {
// ignore
}
template = marko.load(templatePath, {writeToDisk: false});
expect(fs.existsSync(compiledPath)).to.equal(false);
expect(template.render).to.be.a('function');
expect(template.renderSync({name: 'Frank'})).to.equal('Hello Frank!');
});
});