leshill / handlebars_assets

Use handlebars.js templates with the Rails asset pipeline.
MIT License
648 stars 159 forks source link

render templates server side for rails #46

Open deepak opened 11 years ago

deepak commented 11 years ago

using ExecJS and the handlebars javascript source the handlebars templates is rendered on the server

objective is to keep templates DRY. same template on the client and server

stole code from https://github.com/zohararad/handlebarer/blob/master/lib/handlebarer/renderer.rb#L24-L34 to introspect locals and controller variables no need to pass in a special handlebars local like https://github.com/railsware/sht_rails

copied the api for https://github.com/pixeltrix/steering as well

thanks @zohararad and @pixeltrix :-)

deepak commented 11 years ago

fixes https://github.com/leshill/handlebars_assets/issues/10

deepak commented 11 years ago

have not written any tests sorry. also cannot figure out the whole flow.

TODO

  1. rails templetes gets rendered under app/view but then asset pipeline does not pick up the javascript template

tried

    initializer 'handlebars.prepend_views_path', :after => :add_view_paths do |app|
      ActionController::Base.class_eval do
        before_filter do |controller|
          prepend_view_path 'app/assets/javascripts/templates'
        end
      end
    end

and

    initializer 'handlebars.append_assets_path', :after => :append_assets_path, :group => :all do |app|
      Dir[Rails.root.join("app", "views", "*")].each do |path|
        app.assets.paths << path
      end
    end 
  1. rails collection rendering does not work. http://guides.rubyonrails.org/layouts_and_rendering.html#rendering-collections
  2. templates of the form _foo.html.erb.hbs do not work. ie. run the template first under a erb parser

How to you peeps share templates on the client and the server ? also is there any pure-ruby handlebars implementation ?

zohararad commented 11 years ago

@deepak glad my code was of some help to you. A few notes though:

  1. Handlebarer will not be able to support Ember.js server-side rendering, because Ember.js manipulates the DOM which of course cannot work under V8.
  2. Serializing needs an extra push - You can see Handlebarer::Serializer or or active_model_serializer gem for some insight on how to render collections (I'm assuming the problem here is how to properly expose models to V8 context when rendering templates on the server).
  3. Template paths definitions - you basically need to prepend the client-side template directory to the ActionView lookup path, so when looking for a server-side view to render it will first look under app/assets/javascripts/templates and then use the default app/views.
deepak commented 11 years ago

thanks @zohararad

I liked the convention for to_hbs :+1: but did not use it as i was already using active_model_serializer

I am using active_model_serializer like in https://github.com/rails-api/active_model_serializers/issues/192 and rendering with <%= render 'loan', Loan.active_model_serializer._root => loan.as_json(root: false) %> not the cleanest of solutions :-)

I tried using prepend_view_path for template path definations. But was getting errors I think it was because i had a index.html.erb and index (hbs file) both

leshill commented 11 years ago

Hi @deepak,

Looks good, but needs at least a minimal rendering test :)

danielstocks commented 11 years ago

A note from someone who was a duplicate set of erb/hbs templates:

:shipit:

This is a killer feature.

stationkeeping commented 11 years ago

This would be really nice to have.

AlexRiedler commented 11 years ago

You could actually make the ActionView Handler less concrete; but that is a matter of opinion.

My changes ( https://github.com/leshill/handlebars_assets/pull/67 ) should help with this as well as asset-url and other rails helpers are able to be passed in during precompile which helps a fair bit.

You should also do a conditional check to save resources + not need another required gem; otherwise :+1: I was going to write this today... If this is dead I wouldn't mind taking it over as well :smile:

^ another note I should probably add is we should be running against the precompiled templates instead of recompiling in the ActionView handling.

leshill commented 11 years ago

Hi @AlexRiedler,

That would be great!

AlexRiedler commented 11 years ago

This is done @ http://github.com/AlexRiedler/handlebars_assets I just need to make sure everything is working ... it is quite a big change and may only make it into the release of JSAssets in the end (I need to clean it up).

turadg commented 11 years ago

I'd love to see this feature. What's the current status? Is this PR from @deepak good, just waiting for tests? Or is the fork from @AlexRiedler furthest along?

What are the missing pieces that someone could help with to see this feature in the main project?

AlexRiedler commented 11 years ago

@turadg I have been working on it the past week or so; there is still some kinks in it that I am trying to workout.

Short List (of hacks I don't like):

  1. Auto Updating for Local Development, I currently implemented by using a short hack for my current project; plugging straight into the Rails Sprockets pipeline to auto-reload a bundle-asset "templates.js" whenever it has changed. This builds the Javascript Context with the correct partials etc. However, this does not auto reload your other potential dependencies (e.g. additional handlebars helpers)

I believe the correct way to do this is probably give a folder e.g. "javascripts/templates"; or say everything that registered with HandlebarAssets in Sprockets should be loaded into the context. Downsides to this are on boot-up the application must precompile all the templates (which means not so great compilation errors, especially coming out of the ExecJS context).

  1. Concurrency; I have not determined the optimal way to make this performant. Probably using thread local JS contexts is enough; but cause of the previous thing building them properly on bootup is higher priority. (Also other related concerns such as is there potential for infinite loops at runtime? should I have a max render time just for sanity? ... either way they should be implemented).
  2. I had to do some hacks in my local copy in order for Rails Helpers + other helpers to work; it was not pretty but I believe this is cause of Sprockets in Rails 3.1 being quite out of date.

I also am quite busy in my personal life (shit happens); I will see what I can do this week to my branch to make it a little more sane.

variousauthors commented 10 years ago

:+1: I hope this makes it in soon!

variousauthors commented 10 years ago

Little update! I tried to use @AlexRiedler's fork as-is in my project (by directing the gem statement to that repo). It didn't work: I was getting undefined method 'fresh?' for nil:NilClass, which is a lovely error and gave me a good laugh.

Failing that, I tried adding @deepak's changes into my local copy of handlebars_assets, and this worked. Now I can have the following file,

app/assets/javascripts/templates/_widget.jst.hbs

and do this in a view,

render '../assets/javascripts/templates/widget', name: "bob"

The handlebars template will be rendered. However, I haven't been able to figure out how to pass an object rather than key value pairs like name: "bob" above. Also, and more importantly, the widget file has to be _widget to be recognized by rails as a partial... but sprockets won't compile files with a leading _ into functions.

This is a really cool feature, I'd love to be able to have just one .jst.hbs file called widget that would server as both the first-class view template on my client side (compiled into he JST), and as a partial to be pre-rendered on the server-side. Alas, today is not the day.

EDIT: today is the day!

render template: '../assets/javascripts/templates/widget', locals: widget.to_hbs

where to_hbs is basically JSON.parse(widget.to_json). This lets me have all my cake!

AlexRiedler commented 10 years ago

I might be able to get around to this relatively soon (by end of the month); I have been battling some personal issues over the last couple months and hence why the lack of movement in the project. I still would like to get this actively working though as well. I had it working with my personal branch but it did require some additional modifications to the rails setup environment (to which I can no longer remember quite perfectly); and I also ran into some issues with development environment not refreshing properly in various cases which was bothersome.

variousauthors commented 10 years ago

My fork from master and has @deepak's changes, if that helps. I'm currently able to do the stuff.

turadg commented 1 year ago

Ready to close? :)

(it's showing up in my list of open issues in which I've been mentioned)