Open Artazor opened 10 years ago
Rethinking all mentioned above, I decided to remove this
related stuff in favour of self
. It will make all the solution more lightweight and current-jade-flavoured. Working on pull request.
Still waiting comments and suggestions.
Mmmm think it's very similar to what I propose, in fact it can be complemented with #1566
I have a pull request now #1654. It is simpler in implementation an does not involve any currying or other usage of this
.
+1 for this. Specifically in the context of being able to do the following;
var express = require('express');
var app = express();
var jade = require('jade');
app.mixins['foo'] = jade.compileMixinFile('mixins/foo.jade');
app.get('/', function(req, res, next) {
res.render('bar'); // mixin 'foo' is available in the `bar` template
});
:+1: this would be fantastic, and it solves a problem that currently (to my knowledge) doesn't have a good solution (reusing mixins across templates that aren't necessarily hierarchical)
@Artazor have you made progress on this? Even if it's a fork of Jade, this is immensely useful in a number of cases and I'd like to start using it.
Hi @ForbesLindesay and jade-community! I would like to propose or discuss the impact (features vs. performance) of the following refactoring (and new features). Proposed refactoring is conservative in terms of public api - all existing unit tests are passed.
TL;DR
Let's make templates and mixins first-class values in Jade in a clean sound and backward-compatible way:
And let's make templates and mixins more OOP friendly by allowing them to be late-bound on the same prototypal resolution principles as method calls:
TL;DR-2 (longer)
Since subclassing is effectively constructed by prototype chaining, we can actually speak about classes, inheritance and overriding.
Imagine that you can somehow attach templates to your classes and use
this
reference to access current instance for accessing properties, calling methods and rendering other member mixins.Example:
class Person
where src1 and src2 are:
class Agent
where src3 is:
Mixin late binding demo
For given array of objects
the following code
will produce
Detailed proposal & implementation
1. Composable and decoupled from
buf
and runtimejade
In proposed implementation mixins are compiled into triple-curried functions. Their internal calling principle is changed from
to
where
expression_that_evaluates_to_mixin
could either be the samejade_mixins[name]
, or can be obtained from first-class mixin calling syntax (described below in p.4).This will decouple mixins from template-wide globals:
buf
jade
and make them streaming-friendly since
buf
should provide onlypush
method, that can perform arbitrary action on the chunk being emitted.Also it eliminates usage of
this
for passing arguments and blocks (it was very clever and elegant trick but I believe it can be sacrificed for the sake of features discussed below).2.
this
respectfulThe implementation keeps
this
reference between currying steps and across all the template. Keepingthis
reference is important for proposed features. Also it involves minor change inwith
module that was recently merged into master: https://github.com/ForbesLindesay/with/commit/b752d06f84c28e30938819e53a8621dff3bb9cf3Also it means that blocks should be internally compiled as
and called as
3. Templates as mixins
Implementation introduces new exported method
compileMixin
that will compile source in the form of mixin proposed above. The form is context-independent since buffer and runtime are provided as parameters. Possible call of the compiled mixin could look like the following snippet:
4. Mixins as first-class objects
We extend syntax of calling mixins allowing them to be first-class citizens of Jade
In the following snippet
the mixin stored in
obj.renderView
is called in the context ofobj
like normal OOP method. But here we see undesirable fusion of two aspects inobj
— it provides data context for rendering as well as rendering methods themselves. To separate these aspects we introduce notion ofrendering_prototype
described in the next section.5. Rendering-prototype
We introduce notion of
rendering_prototype
that is a property of object's constructor like normalprototype
, but contains jade's mixins as members, thus original prototype is not polluted. Also rendering prototype covariates with ordinary prototype. This achieved by two tiny helper functionsTo support
render_prototypes
syntactically we make further extension to mixin calling syntaxor even
that is compiled into
Let's consider example:
that will produce
Note that template compiled with
jade.compile
still produces function that returns a string, but isthis
respectful.Status of the implementation & discussion
Implementation is almost ready at my fork of jade https://github.com/Artazor/jade - this is only proof-of-concept. But i want to discuss proposed features before working on production-ready pull request.
I'd like to discuss the following items:
rendering-prototype
this
in templates (the most controversial point)For Nr.3 alternative implementation could use
self
quasi-variable that is already present in jade (instead ofthis
). It will allow to:this
for passing{attributes, block, self}
into mixins,buf
andjade
runtime).bind
in favour of.call
The cost of this alternative is that
will be called in the context of the current
self
instead ofobject
. Butwill be called in context of
object
as it should. Here by the word "context" I mean the local value ofself
quasi-variable. May be this is reasonable difference since given cases come from different prototypes: the former comes formObject.prototype
and the later — fromObject.jade_mixins
.Would be glad to hear any opinions, Regards, Anatoly