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

render templates server side for rails #46

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

deepak
Copy link

@deepak deepak commented Jan 17, 2013

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 :-)

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
@deepak
Copy link
Author

deepak commented Jan 17, 2013

fixes #10

@deepak
Copy link
Author

deepak commented Jan 17, 2013

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
Copy link

@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
Copy link
Author

deepak commented Jan 17, 2013

thanks @zohararad

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

I am using active_model_serializer
like in rails-api/active_model_serializers#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
Copy link
Owner

leshill commented Jan 17, 2013

Hi @deepak,

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

@danielstocks
Copy link

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

:shipit:

This is a killer feature.

@stationkeeping
Copy link

This would be really nice to have.

@AlexRiedler
Copy link
Collaborator

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

My changes ( #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 👍 I was going to write this today... If this is dead I wouldn't mind taking it over as well 😄

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

@leshill
Copy link
Owner

leshill commented May 29, 2013

Hi @AlexRiedler,

That would be great!

@AlexRiedler
Copy link
Collaborator

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
Copy link
Contributor

turadg commented Jun 9, 2013

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
Copy link
Collaborator

@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
Copy link

👍 I hope this makes it in soon!

@variousauthors
Copy link

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
Copy link
Collaborator

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
Copy link

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

@turadg
Copy link
Contributor

turadg commented Jan 28, 2023

Ready to close? :)

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

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

Successfully merging this pull request may close these issues.

8 participants