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

Intercepting Template Before Compile #39

Closed
KidA78 opened this issue Oct 2, 2013 · 12 comments
Closed

Intercepting Template Before Compile #39

KidA78 opened this issue Oct 2, 2013 · 12 comments
Assignees
Milestone

Comments

@KidA78
Copy link

KidA78 commented Oct 2, 2013

Eric, big fan of this module. Powerful stuff.

This is a question, not an issue:
I would like to intercept my templates and partials before they get compiled and cached, and process them with another module.

For example, just say I wanted to use juice to inline all my css, is there a mechanism for applying such transformations? If it were in the module it would probably happen somewhere in express-handlebars.js line 132.

What would you recommend, given the underlying structure, if there was a way to preload the files, transform them. Is it possible would you say, without extending the module itself?

Our other option is to just juice the templates in a grunt script, but it would be good to have this in memory since we don't have a lot of templates....

@ericf
Copy link
Owner

ericf commented Oct 12, 2013

Could you just use a Handlebars block helper for this? I've done similar stuff like this before:

@KidA78
Copy link
Author

KidA78 commented Oct 12, 2013

Thanks for getting back to this, Eric! So, that's an interest approach you suggest. I ran some tests, but my hunch what may have happened is right.

you see juice takes an HTML string + Css file, and inlines all the stylesheets in the HTML elements. Putting this functionality within a block helper, the juice still happens with every request to render the template, even if the template has already been cached. It seems that the Helper functions are applied at runtime.

I guess what I am thinking of, is:

File.hbs (from file system) ---> Compiled JS in ExpHbs Cache
To somehow intercept the HBS from all the templates along the way to the cache, and get them juiced, so they have the inline CSS already in them within the cache.

@ericf
Copy link
Owner

ericf commented Oct 13, 2013

This sounds like something you'd want to do at the Express View level by overriding the way Express calls into the rendering process so you can pass along your cached HTML or post process the HTML before sending it as the response. Handlebars compiles strings into functions, and Express-Handlebars caches those compiled functions, not HTML strings.

The reason this packages also has a cache for files is to support both compiling and precompiling templates while only needing to go to disk once. This is an implementation detail where I made a trade off of consuming more RAM instead of going to disk more than once per template when the cache option is set.

@KidA78
Copy link
Author

KidA78 commented Oct 16, 2013

I think in our case especially, consuming more RAM vs going to disk, is fine. We have a few nested templates, that are repeatedly called for different items rendered (can be hundreds in some cases), going to memory for a small template beats 100s of reads, per event. That said, I would like to process the template before it gets compiled. En route to compilation. Currently we are post processing the HTML on its way out from express, which is resource intensive.

What i'm probably gonna have to end up doing, is writing a custom grunt task, whereby I can create a mirror directory of processed .hbs files, that way they're already in the file system, created at build time, after deploy. The goal really is to only process each template once before compilation. So if it's not possible to do it in between read from disk and compile, then it will have to be at build time... I was trying to see if there was a hook, essentially at line 134 of expess-handlebars. Digging through the handlebars API itself, doesn't seem to be a way to do it there either.

Could you think of any other needs for some sort of pre-process function that sits in between read and compile? I guess most folks resort to build tasks for this sort of thing.

@ericf
Copy link
Owner

ericf commented Oct 17, 2013

Could you think of any other needs for some sort of pre-process function that sits in between read and compile? I guess most folks resort to build tasks for this sort of thing.

I think your use-case is valid without needing others to solidify it. I would be willing to add a hook by simply adding a compileTemplate() method on the prototype which you'd be able to easily override. The other option would be to subclass Express' View class and override the rendering process to add another level of caching at the Express View level.

Note: There's a app.set('view' CustomViewClass) option that we got implemented. You can see an example of this approach done here: https://github.com/yahoo/express-view

@ericf
Copy link
Owner

ericf commented Oct 17, 2013

@KidA78 I will replace this chunk of code with something that first loads the template, then delegates to a public compileTemplate() method passing it the args which loadTemplate() was called with. And I'll make it all async.

This will allow you to hook in and override compileTemplate(), and wrap the call the original method. This will give you the chance to do whatever you want before/after the Handlebars compiler runs and before the template is cached. Sound good?

ericf added a commit that referenced this issue Oct 17, 2013
This provides a hook for customizing how templates are compiled,
allowing for pre- and post- processing of templates compiled by the
Handlebars compiler.

Fixes #39
@ghost ghost assigned ericf Oct 17, 2013
@ericf
Copy link
Owner

ericf commented Oct 21, 2013

@KidA78 does #41 work for you?

@KidA78
Copy link
Author

KidA78 commented Oct 21, 2013

Eric, I just took a look at the changeset and it looks good. Could you provide as well an update to your examples section? Will clarify how this could be used.

On a side note, I'm working on creating adapters for some of these html processors, for handlebars templates. Will be a great coupling with this feature you just put in!

@ericf
Copy link
Owner

ericf commented Oct 21, 2013

Yeah I'll look into getting the docs updated. I want to get to a v1.0 on this package, and the Issues Milestones capture what's left.

Usage should be straight-forward:

var hbs             = require('express3-handlebars').create(),
    compileTemplate = hbs.compileTemplate.bind(hbs);

hbs.compileTemplate = function (template, options, callback) {
    // Pre-process template here.

    compileTemplate(template, options, function (err, compiled) {
        // Post-process template here.

        callback(err, compiled);
    });
};

@KidA78
Copy link
Author

KidA78 commented Oct 21, 2013

Perfect, thanks!

@ericf
Copy link
Owner

ericf commented Oct 21, 2013

Updated code sample to bind correct context.

@ericf
Copy link
Owner

ericf commented Aug 5, 2014

This feature is now implemented in #68

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

Successfully merging a pull request may close this issue.

2 participants