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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
module.exports = {
|
||||
@ -116,8 +136,12 @@ module.exports = {
|
||||
r: function(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') {
|
||||
throw new Error('Invalid tag handler: ' + handler);
|
||||
return createLazyRenderer(handler);
|
||||
}
|
||||
|
||||
return renderFunc;
|
||||
|
||||
@ -53,8 +53,8 @@ if (streamPath) {
|
||||
stream = require(streamPath);
|
||||
}
|
||||
|
||||
function Template(renderFunc, options) {
|
||||
this._ = renderFunc;
|
||||
function Template( options) {
|
||||
this._ = null;
|
||||
this.buffer = !options || options.buffer !== false;
|
||||
}
|
||||
|
||||
@ -204,20 +204,35 @@ function load(templatePath, options) {
|
||||
if (typeof templatePath === 'string') {
|
||||
template = cache[templatePath];
|
||||
if (!template) {
|
||||
// The template has not been loaded, load the template to get
|
||||
// access to the factory function that is used to produce
|
||||
// The template has not been loaded
|
||||
|
||||
// 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
|
||||
// as the first argument to the factory function to produce
|
||||
// the compiled template function
|
||||
template = cache[templatePath] = new Template(
|
||||
loader(templatePath).create(helpers), // Load the template factory and invoke it
|
||||
options);
|
||||
// the template rendering function
|
||||
template._ = loader(templatePath).create(helpers); // Load the template factory and invoke it
|
||||
}
|
||||
} else {
|
||||
// Instead of a path, assume we got a compiled template module
|
||||
// We store the loaded template with the factory function that was
|
||||
// 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;
|
||||
|
||||
12
test/fixtures/marko-taglib.json
vendored
12
test/fixtures/marko-taglib.json
vendored
@ -102,6 +102,18 @@
|
||||
"attributes": {
|
||||
"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",
|
||||
|
||||
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