Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compile mixins for client #1950

Open
mikeyhew opened this issue May 15, 2015 · 9 comments
Open

Compile mixins for client #1950

mikeyhew opened this issue May 15, 2015 · 9 comments

Comments

@mikeyhew
Copy link

It would be nice if you could write mixins for use on the server, and compile them for use on the client:

//- tweets.jade

mixin tweet(tweet)
  li
    h3= tweet.handle
      small= tweet.time
    p= tweet.text

h1 Tweets
ul#tweets
each tweet in tweets
  +tweet(tweet)

And then on the client, when a new tweet comes in, you do:

new_tweets.forEach(function(tweet) {
  $('ul#tweets').prepend(tweet_mixin(tweet));
})

You can do this by moving the tweet template to _tweet.jade, and writing include _tweet.jade instead of +tweet(tweet), but there are some issues with this approach:

  1. Each mixin that you want to be able to access on the client has to be put in a separate file. It would be nice if you could have multiple mixins in a mixins.jade file, and be able to send those mixins to the client.
  2. If the mixin has more than one argument, then it gets tricky - this example worked nicely because the tweet mixin takes a single object as its only argument; but what about a mixin that takes a single number, or if the tweet mixin looked like +tweet(tweet_data, time)?
  3. Usually you design the site with HTML (or jade) and CSS first, and then implement functionality second. When you're writing the template, you'll naturally want to use the mixin syntax. But then you'll have to go and refactor the code later on, moving the mixins you want on the client to a separate file and including them.

I propose something along the lines of compileMixinsClient(mixin_names, templateString) and compileMixinsFileClient(mixin_names, templateFileName), that return a string of javascript declaring a function for each mixin in mixin_names:

function mixinName1 (locals, arg1, arg2) {...}
function mixinName2 (locals, arg1) {...}

// or what would be even better - a curried function that you can use like this:
function mixinName1 (locals) {
  return function (arg1, arg2) {...}
}
var mixinName1WithLocals = mixinName1(locals);
$('#my-el').html(mixinName1WithLocals(arg1, arg2));
@mikeyhew mikeyhew changed the title compile mixins for client Compile mixins for client May 15, 2015
@jonnyscholes
Copy link

This would be really useful for us - we have a component library of jade mixins we use across multiple backends. Would be great if we could do the same on the front end using something like jadeify. Is there in principle support for this? If so I could take a stab?

@TimothyGu
Copy link
Member

This issue can be considered in conjunction with pugjs/pug-code-gen#3, which make the mixins pure functions instead of properties in an object, and returns strings. However, the PR also further complicates things, since it adds a hash to the function name, although that can probably be circumvented with a function variable. In the end you can always depend on the good ol' include.

@mikeyhew said:

Each mixin that you want to be able to access on the client has to be put in a separate file. It would be nice if you could have multiple mixins in a mixins.jade file, and be able to send those mixins to the client.

True, that is a problem that cannot be avoided.

If the mixin has more than one argument, then it gets tricky - this example worked nicely because the tweet mixin takes a single object as its only argument; but what about a mixin that takes a single number, or if the tweet mixin looked like +tweet(tweet_data, time)?

You can always put the information in the locals object.

@jonnyscholes, I don't think much can be done at this moment when we haven't decided whether pugjs/pug-code-gen#3 should go in or not.

@TimothyGu TimothyGu reopened this Jul 28, 2015
@mikeyhew
Copy link
Author

Here is github repository of what I am doing right now in order to use mixins on the client. It requires that create a file for every mixin that you want to have on the client, but this could conceivably be automated if you don't want to create the files yourself.

@jonnyscholes
Copy link

@mikeyhew Ah nice. We went down a similar road - but I wanted a more drop in solution without having to create a new file for each mixin so I can use it (the component library in question already has ~80 components). I've put together jademixinify which exposes mixins as functions that return rendered strings. It works - but is rather (read: super) hacky. (It lacks test at the moment as I only just put it together - but they are coming).

@TimothyGu no worries. I'll watch that PR and see how it goes. Thanks for chiming in :)

@cheshrkat
Copy link

cheshrkat commented Apr 1, 2017

Giving this a bump, as the referenced issue has been closed.

Also I've had a look at using include as described, but that doesn't seem to be viable if your templates have mixins in them (which we do - we have subcomponent mixins called from component mixins). Or possibly I just can't see how to pass values down to them.

So really for me I need some Pug option for getting mixins into functions (I use them for testing the template API with Jasmine). There were some Jade projects for doing this but so far it seems they've not been migrated to Pug.

So... Is it possible to compile Pug mixins for client-side use; or is it going to be possible? ie. is there support for the idea in principle even if it's not done yet?

@megatolya
Copy link

megatolya commented Jun 22, 2017

I think it can be done in current version of API with new compile flag:

Now

const mixinCode = `
mixin myMixin(variable)
    h1=variable
`;
const template = pug.compile(mixinCode);
template("hello") // === "" :(

With new compile flag:

const mixinCode = `
mixin myMixin(variable)
    h1=variable
`;
const template = pug.compile(mixinCode, {exportMixins: true}); // <----- some new flag
template("hello") // === "" ok, nothing new here
template.myMixin("hello") // === "<h1>hello</h1>"  <----- OH, HELLO THERE!

What do you think?

There will be some complexity with mixins api (e.g. mixin's rest args, vars outside of mixin and mixin's attributes). But still it is possible to implement.

@ForbesLindesay
Copy link
Member

@megatolya I think that would work fine, but we'll probably want to refactor the code-gen stage quite a bit first. I think we should make mixins functions that return a string, currently they just push directly into the buffer. There are lots of optimisations that get easier if they return a string I think.

@henricazottes
Copy link

Any update? This feature is a must have! :)
What is the actual way to properly do what the op want?

@ForbesLindesay
Copy link
Member

This is currently blocked on #3019 but even after that, it will need someone to own it and push it forwards.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

7 participants