mirror of
https://github.com/marko-js/marko.git
synced 2025-12-08 19:26:05 +00:00
Merge pull request #67 from patrick-steele-idem/circular
Fixes #66 - Allow circular dependencies when loading templates
This commit is contained in:
commit
9fa2e6b7ba
@ -22,6 +22,26 @@ function notEmpty(o) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createLazyRenderer(handler) {
|
||||||
|
var lazyRenderer = function(input, out) {
|
||||||
|
lazyRenderer.renderer(input, out);
|
||||||
|
};
|
||||||
|
|
||||||
|
// This is the initial function that will do the rendering. We replace
|
||||||
|
// the renderer with the actual renderer func on the first render
|
||||||
|
lazyRenderer.renderer = function(input, out) {
|
||||||
|
var rendererFunc = handler.renderer || handler.render;
|
||||||
|
if (typeof renderFunc !== 'function') {
|
||||||
|
throw new Error('Invalid tag handler: ' + handler);
|
||||||
|
}
|
||||||
|
// Use the actual renderer from now on
|
||||||
|
lazyRenderer.renderer = rendererFunc;
|
||||||
|
rendererFunc(input, out);
|
||||||
|
};
|
||||||
|
|
||||||
|
return lazyRenderer;
|
||||||
|
}
|
||||||
|
|
||||||
var WARNED_INVOKE_BODY = 0;
|
var WARNED_INVOKE_BODY = 0;
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
@ -116,8 +136,12 @@ module.exports = {
|
|||||||
r: function(handler) {
|
r: function(handler) {
|
||||||
var renderFunc = handler.renderer || handler.render || handler;
|
var renderFunc = handler.renderer || handler.render || handler;
|
||||||
|
|
||||||
|
// If the user code has a circular function then the renderer function
|
||||||
|
// may not be available on the module. Since we can't get a reference
|
||||||
|
// to the actual renderer(input, out) function right now we lazily
|
||||||
|
// try to get access to it later.
|
||||||
if (typeof renderFunc !== 'function') {
|
if (typeof renderFunc !== 'function') {
|
||||||
throw new Error('Invalid tag handler: ' + handler);
|
return createLazyRenderer(handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
return renderFunc;
|
return renderFunc;
|
||||||
|
|||||||
@ -53,8 +53,8 @@ if (streamPath) {
|
|||||||
stream = require(streamPath);
|
stream = require(streamPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
function Template(renderFunc, options) {
|
function Template( options) {
|
||||||
this._ = renderFunc;
|
this._ = null;
|
||||||
this.buffer = !options || options.buffer !== false;
|
this.buffer = !options || options.buffer !== false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -204,20 +204,35 @@ function load(templatePath, options) {
|
|||||||
if (typeof templatePath === 'string') {
|
if (typeof templatePath === 'string') {
|
||||||
template = cache[templatePath];
|
template = cache[templatePath];
|
||||||
if (!template) {
|
if (!template) {
|
||||||
// The template has not been loaded, load the template to get
|
// The template has not been loaded
|
||||||
// access to the factory function that is used to produce
|
|
||||||
|
// Cache the Template instance before actually loading and initializing
|
||||||
|
// the compiled template. This allows circular dependencies since the
|
||||||
|
// partially loaded Template instance will be found in the cache.
|
||||||
|
template = cache[templatePath] = new Template(options);
|
||||||
|
|
||||||
|
// Now load the template to get access to the factory function that is used to produce
|
||||||
// the actual compiled template function. We pass the helpers
|
// the actual compiled template function. We pass the helpers
|
||||||
// as the first argument to the factory function to produce
|
// as the first argument to the factory function to produce
|
||||||
// the compiled template function
|
// the template rendering function
|
||||||
template = cache[templatePath] = new Template(
|
template._ = loader(templatePath).create(helpers); // Load the template factory and invoke it
|
||||||
loader(templatePath).create(helpers), // Load the template factory and invoke it
|
|
||||||
options);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Instead of a path, assume we got a compiled template module
|
// Instead of a path, assume we got a compiled template module
|
||||||
// We store the loaded template with the factory function that was
|
// We store the loaded template with the factory function that was
|
||||||
// used to get access to the compiled template function
|
// used to get access to the compiled template function
|
||||||
template = templatePath._ || (templatePath._ = new Template(templatePath.create(helpers), options));
|
template = templatePath._;
|
||||||
|
if (!template) {
|
||||||
|
// First put the partially loaded Template instance on the
|
||||||
|
// the compiled template module before actually loading and
|
||||||
|
// initializing the compiled template. This allows for circular
|
||||||
|
// dependencies during template loading.
|
||||||
|
template = templatePath._ = new Template(options);
|
||||||
|
|
||||||
|
// Now fully initialize the template by adding the needed render
|
||||||
|
// function.
|
||||||
|
template._ = templatePath.create(helpers);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return template;
|
return template;
|
||||||
|
|||||||
12
test/fixtures/marko-taglib.json
vendored
12
test/fixtures/marko-taglib.json
vendored
@ -102,6 +102,18 @@
|
|||||||
"attributes": {
|
"attributes": {
|
||||||
"name": "string"
|
"name": "string"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"test-circular-renderer-a": {
|
||||||
|
"renderer": "./taglib/test-circular-renderer-a/renderer"
|
||||||
|
},
|
||||||
|
"test-circular-renderer-b": {
|
||||||
|
"renderer": "./taglib/test-circular-renderer-b/renderer"
|
||||||
|
},
|
||||||
|
"test-circular-template-a": {
|
||||||
|
"template": "./taglib/test-circular-template-a/template.marko"
|
||||||
|
},
|
||||||
|
"test-circular-template-b": {
|
||||||
|
"template": "./taglib/test-circular-template-b/template.marko"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"tags-dir": "./taglib/scanned-tags",
|
"tags-dir": "./taglib/scanned-tags",
|
||||||
|
|||||||
6
test/fixtures/taglib/test-circular-renderer-a/renderer.js
vendored
Normal file
6
test/fixtures/taglib/test-circular-renderer-a/renderer.js
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
var marko = require('../../../../');
|
||||||
|
var template = marko.load(require.resolve('./template.marko'));
|
||||||
|
|
||||||
|
exports.renderer = function(input, out) {
|
||||||
|
template.render({}, out);
|
||||||
|
};
|
||||||
2
test/fixtures/taglib/test-circular-renderer-a/template.marko
vendored
Normal file
2
test/fixtures/taglib/test-circular-renderer-a/template.marko
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
test-circular-renderer-a
|
||||||
|
<test-circular-renderer-b/>
|
||||||
6
test/fixtures/taglib/test-circular-renderer-b/renderer.js
vendored
Normal file
6
test/fixtures/taglib/test-circular-renderer-b/renderer.js
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
var marko = require('../../../../');
|
||||||
|
marko.load(require.resolve('./template.marko'));
|
||||||
|
|
||||||
|
exports.renderer = function(input, out) {
|
||||||
|
out.write('test-circular-renderer-b');
|
||||||
|
};
|
||||||
1
test/fixtures/taglib/test-circular-renderer-b/template.marko
vendored
Normal file
1
test/fixtures/taglib/test-circular-renderer-b/template.marko
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
<test-circular-renderer-a/>
|
||||||
2
test/fixtures/taglib/test-circular-template-a/template.marko
vendored
Normal file
2
test/fixtures/taglib/test-circular-template-a/template.marko
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
test-circular-template-a
|
||||||
|
<test-circular-template-b/>
|
||||||
1
test/fixtures/taglib/test-circular-template-b/template.marko
vendored
Normal file
1
test/fixtures/taglib/test-circular-template-b/template.marko
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
test-circular-template-b<test-circular-template-a if="false"/>
|
||||||
1
test/fixtures/templates/circular-renderer/expected.html
vendored
Normal file
1
test/fixtures/templates/circular-renderer/expected.html
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
test-circular-renderer-a test-circular-renderer-b
|
||||||
1
test/fixtures/templates/circular-renderer/template.marko
vendored
Normal file
1
test/fixtures/templates/circular-renderer/template.marko
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
<test-circular-renderer-a/>
|
||||||
1
test/fixtures/templates/circular-renderer/test.js
vendored
Normal file
1
test/fixtures/templates/circular-renderer/test.js
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
exports.templateData = {};
|
||||||
1
test/fixtures/templates/circular-template/expected.html
vendored
Normal file
1
test/fixtures/templates/circular-template/expected.html
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
test-circular-template-a test-circular-template-b
|
||||||
1
test/fixtures/templates/circular-template/template.marko
vendored
Normal file
1
test/fixtures/templates/circular-template/template.marko
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
<test-circular-template-a/>
|
||||||
1
test/fixtures/templates/circular-template/test.js
vendored
Normal file
1
test/fixtures/templates/circular-template/test.js
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
exports.templateData = {};
|
||||||
Loading…
x
Reference in New Issue
Block a user