execjs-rails

JavaScript-based rendering in Rails

Why render via JavaScript in Rails?

There are some great JavaScript UI frameworks out there now. Writing most of your view layer in a JavaScript-based framework cuts down on a lot of repetition (and potential points of divergence) as opposed to having Rails output HTML one way and JavaScript output HTML another. Rendering JavaScript-based view code on the server preserves SEO and, if you care and you're diligent, backward compatibility with older browsers.

Why ExecJS Rails?

ExecJS Rails has very few opinions. It's designed to get its opinions from your JavaScript code.

It was originally written out of some frustration with react-rails, which bakes in a lot of opinions we don't share. Should a server-side JavaScript context have a global window object? We thought "no", and react-rails at some point decided "yes" and broke some of our conditional checks. It also didn't have any hooks to override what it injects into the server-side JavaScript context. So we thought what would really be nice is to have an underpinning rendering library that doesn't care if you use React or something else and is largely opinion-free.

This view engine has one philosophy: Let JavaScript do it. Out of the box, it's configured to look for two JavaScript functions in your asset bundle: One to ask your JavaScript if it has a view for a given path, and another to actually return a rendered string. It's up to you to write JS code that will look up and render JS-based views. It's up to you how you want to build your JS bundle to accomplish that task. Or better yet, it's up to you to build a more opinionated framework on top of ExecJS Rails. Which is really what it's here for.

Quickstart Guide:

Include execjs-rails in your Gemfile, and create a file named app/assets/javascripts/server.js which contains the following:

// This function will tell Rails whether or not ExecJS Rails has a view for this path.
function execjs_rails_has_view(path) {
  // `path` looks like "users/show"
  return false; // Do something smarter that will return `true` once in a while.
}

// This function will render a view for the given path.
function execjs_rails_handler(path, opts) {
  // `path` looks like "users/show"
  // `opts` is a data object passed in from Rails view assigns
  return "Hello, World!"; // Do something smarter that returns HTML or something.
}

Then you have:

  • A Rails view helper, execjs_render, that will render output from your execjs_rails_handler JavaScript function.
  • A Rails template handler that will do the same. You can write your controller code the exact same way as if you were using ERB. It will use execjs_rails_has_view to determine whether or not ExecJS Rails can handle the view. If so, it will render via execjs_rails_handler. If not, it will fall back to looking for ERB.

That's pretty much it.

Advanced Usage:

For now, just read the source for configuration options and more info. You can override a lot of the default behavior.