Broadly: What are the best practices for organizing JS in the Rails pipeline?
Specifically: I have rapidly growing JS files that I'm fine with including in the overarching application.js manifest and letting Sprockets uglify. However, each individual JS file is starting to become unwieldy, and I'd love to organize them so that I don't have to dig through hundreds of lines of utility functions to get to the meat of the code. I recognize that the goal is some kind of namespacing/modularity, but I don't know what the best practices are for combining this with the asset pipeline, especially Sprockets manifests.
Things I've already considered, and read thoroughly:
Yes, I've read the entire Rails guide on its asset pipeline. I know how Sprockets directives like require and require_tree work; the issue is that I want to use those same directives like the equivalent of an ES6 import command so I can do something like
// in, say, controller.js
//= require 'utilities'
...
more code
...
// and in application.js, more confidently
//= require 'controller'
but I get the feeling that's not how manifests should be used, or at least that it'll needlessly recompile layers of assets every time I change a single line in utilities. I've also considered requiring every file individually from application.js but that doesn't really give the modularity that seems appropriate.
Gems like Paloma, CommonJS, or RequireJS. These seem like overkill, and seem meant to replace the pipeline rather than supplement it.
"Modern" JS like ES6, Babel, or Browserify. (I admit I don't really understand the overlap in these projects yet, but I think I get the gist of their purposes.) Maybe eventually, since JS seems to be moving in that direction, but also seems like overkill.
Gulp. In the same vein as previous, overkill and an unnecessary rewriting of the asset pipeline.
Rails 5 and Sprockets 4. We're on Rails 4 right now, and I'm aware that Sprockets 4 has some ES6 built in, but I don't plan on upgrading until at least a while after Rails 5 is publicly released.
So what should I do? I think I need to bite the bullet and go with one of these, but I just can't figure out which makes the most sense. The project isn't especially reliant on JS, but there's enough of it that I want to organize it now, rather than later.
I find when I have heavy amounts of page-specific js that it is best to leave the assets pipeline for only the js that is repeated more than once. Obviously all outside libraries should continue to go in your vendor/js folder. The most rails-esque way to add page-specific js to your app (thus avoiding loading js in every page when a library or script is only needed in one page) is to add to the very bottom of your layouts/application.html.erb file right before the closing body tag:
<%= yield :javascript %>
Then on the view that you're looking to run some snippets of javascript you should put this at the very bottom of it after all html tags have been closed. Make sure it's not within some divs or anything in that view but at the very bottom of it.
<%= content_for :javascript do %>
<script type="text/javascript">
$(document).on('page:load', function() {
all your page specific code here..
});
</script>
<% end %>
This code will now be yielded to the bottom of your layout view only loading on the specific views you need instead of being concatenated along with all other assets in your assets/js folder. I do this with all custom js that isn't application wide and it's very easy to maintain/debug.
Related
When running tests in a Rails (5) app, let's say controller rspecs for example, you need to have all external frontend dependencies available - anything that's included from application.js or application.css is needed to run these tests, otherwise you get a Sprockets::FileNotFound exception when the code gets to rendering the response.
That's not actually needed because we're not evaluating the resulting HTML or any such thing, and definitely not running the JS, but it makes those tests depend on npm/bower not failing, takes time downloading, etc. etc.
So, I'm hoping to find a way to not need js & css dependencies when running specs - essentially making application.js and application.css empty for the purpose of that spec run. (Except that doesn't work because other templates may require things too.)
Has anyone done such a thing? How? :)
You can work around this by just including the dependencies in the test environment, with Sprockets enabled it's just part of the Rails boot process, I don't believe there's an easy way around it.
Ended up solving this by doing.. in the test environment.
class << ActionController::Base.helpers
def image_path(path, options = {})
path
end
end
Turns out, not using image path (and possibly other related helpers, YMMV) doesn't trigger the lookups.
Pretty basic question here:
I on rails 3.2.17, need to include some coffeescript to my application, would rather not add it to my views.
my views folder is named episodes and would like to connect partial _show_info.html.erb to assets/javascript/episodes.js.coffee
just need the proper javascript include tag.
Thanks in advance.
I would recommend adding this to your app/assets/javascripts/application.js file:
//= require episodes
That way, you'll have access to it everywhere, and when you push to production, it'll be minified and concatenated with all the rest of your JavaScripts. You can read up on the asset pipeline here. Especially check out the section on JavaScript Compression.
I just finished Code School's intro course on JQuery, jQuery Air: First Flight. It was a great way to learn the basics of jQuery and when I was done I was all excited about adding some jQuery to my new little rails 3.2 app. How to make that happen isn't obvious, though.
By default, rails 3.2 comes with the jquery-rails and coffee-rails gems. New 3.2 apps are all set up accept javascript and jquery in the form of coffee-script. While I'll learn coffee-script soon, right now all I've got is jquery.
More specifically, should I add something like:
<script type="text/javasript" src= "https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
into the head of my app/views/layouts/application.html.erb file or is all that taken care of jquery-rails gem and the
<%= javascript_include_tag "application" %>
already there?
Where in my app do I put the jQuery code? With every new controller I generate, rails 3.2 creates a nice [new_controller].js.coffee file in the app/assets/javascripts/ directory. Javascript doesn't work if I put it in that .coffee file. Anyone have any thoughts?
Having experimented around and corresponded with the good folks at Code School, I've come up with the following answer with others may find useful:
Rails 3.2 apps are ready made to accept coffeescript. Indeed, every new controller automatically generates a [new_controller].js.coffee file ready to accept one's new coffeescript. While I'll get to coffeescript soon enough, having just finished JQuery Air: First Flight, all I know is jQuery.
Here's what one needs to do to add jQuery to one's Rails 3.2 app with
default, asset pipeline settings:
1) Place javascript_include_tag(:application) in the
app/views/layouts/application.html.erb file. Code School's Adam Fortuna notes that it is typical to put that line in the footer which sounds like good advice. That probably allows the rest of the page to load before the javascript.
2) In the 'app/assets/javascripts/' directory create a new file with the
suffix .js which in my case was user.js. Note: Do not name your jQuery
file the same as the automatically created .js.coffee file or it will not
be read, probably because the coffeescript file alone will be.
3) Add your jQuery javascript to that file to your heart's content! It's already part of your 3.2 app, included with the jquery-rails gem.
If others have insight into using jquery and javascript instead of coffee-script in a rails 3.2 app, please add. That said, my next step is to learn coffee-script!
You don't need to do anything. Rails will get you jquery by default. if the extension of your file is not coffee then you won't need to use coffeescript.
You can read this to better understand the magic.
If you must add your own, you can write something like this:
<%= javascript_include_tag "http://example.com/main.js" %>
Read this to understand how javascript_include_tag works.
Make sure that //= require jquery is that the top of the application.js or application.js.coffee and you should be good if you have the jquery-rails gem installed.
I recently started working with Rails 3.1. It's a very nice framework
and I like the 'asset pipeline' philosophy. Adding libraries that exist
of one file is quite easy and works out of the box. However, adding a library
which exists of a folder like EXTJS 4 is somewhat more difficult.
I'd like to just add the whole EXTJS4 folder to the '/app/assets' folder
And do a //= require_tree in my 'application.js' file but that does not
include the css files. Also images and scss files are not included this way.
All the images/css files are referenced 'relatively' from the js file so
I think the folder structure should be maintained as it is.
What is the best and easiest way to add this library to my rails projects?
I dont want to specify the whole list of EXTJS resources to my view each time
I create a new view.
Thanks
Simply leaving the Ext library (linked) inside of "public" works just fine.
One caveat here: keep in mind, that if you want sprockets to not interfere, then, while using Rails view helpers, you need the paths to your extjs JS and CSS files to be absolute, e.g. starting with "/". Let's say we have the Ext library in "public/extjs". Then these 2 calls will be needed in your Rails view/layout:
javascript_include_tag "/extjs/ext-all-debug"
stylesheet_link_tag "/extjs/resources/css/ext-all"
When writing javascript for a specific page in a site, when do you want to turn the javascript into a function and include it in application.js?
I've seen suggestions about doing this (and minifying or gzip-ing) to minimize HTTP requests. That makes sense, but what about maintainability? If I have js code specific to one view, it seems like more work to look into a potentially massive application.js. That code could be embedded into that view or put in its own .js (or .js.erb or .rjs) file in that view folder.
I've seen another suggestion that Rails automatically merges all javascript into one file. Is this true?
TLDR: how much or how little should a developer worry about optimization when writing javascript?
As I haven't seen an answer in about a month, I'll answer this question to the best of my current knowledge.
Rails 3.1 (currently at release candidate 4) introduces sprockets, which will compile all javascript in a rails project into one file. It even comes with tools to minify and compress javascript so that it's all delivered to the client at once.
Related to sprockets is the Rails 3.1 asset pipeline. As I understand, it's a folder hierarchy/abstraction. Javascripts can go into 3 folders:
/apps/assets/javscripts/
Javascript files specific to the application, including application.js. This should only contain the manifest of javascript files you want to include in your project. The rails new tool will generate this file and include jquery in the manifest.
/lib/assets/javascripts/
Javascript files written by the developer that are more general purpose. (My impression is that this would be for javascript libraries you develop to drop into multiple applications)
/vendor/assets/javascripts/
Third party javascript files (i.e. JQuery, Modernizr)
All files in these folders will appear to the client inside /assets/, abstracting out the server side file paths. I assume this is meant to help the developer organize javascript files.
To answer my own question
Put javascript functions into separate files, group them logically. My test app indicated that subfolders within .../assets/javascripts/ are ok if and only if the subfolder path is included in the manifest.
I.E. putting //= subfolder/js_file in the manifest will work. Putting //= js_file will not if js_file is inside .../javascripts/subfolder/
DHH mentions a "rule of 13" in his talk (linked below). If the number of javascripts in a folder exceeds 13, it starts to look messy and unmanageable. This would be a good time to group javascript files into subfolders.
Use the built in Rails 3.1 minifier and compressor (or install a preferred gem)
Refactor javascript code from time to time. Move functions to /lib/assets/javascripts/ over time. (The goal is to eventually recognize when you want to write general purpose javascript functions as opposed to application-specific ones and eliminate this refactor step)
More Resources
a blog post covering all changes in Rails 3.1
DHH's talk on Rails 3.1 changes, May 16 2011 (~1 hr)