Including large JS library with :cache => true into a rails app - ruby-on-rails

I am thinking about the best way of including a JS library into rails app supporting :cache => true option for both JS and CSS.
Let me take an example to describe the question: jQueryUI (that's just an example). It usually has the following structure when downloaded:
+jq.ui
+css
+skin1
+images
all_the_images.png
jq-ui.css
+skin2
+images
all_the_images.png
jq-ui.css
+js
jquery.js
jq.ui.js
Now in order to use it I have to include this structure into rails app (2 js files + 1-2 css).
I need to be able to use :cache => true option (so that the jquery, jquery ui, application.js etc would be all in one file; also the jq.ui/skin2/jq-ui.css and application.css would be in a single file too).
The problem with :cache => true is that the single (combined) CSS file will not reference the correct images as it will be moved to the stylesheets path instead of stylesheets/jq.ui.css/skin2/jq-ui.css. Thus broken links to images from the CSS.
The question is:
Where the library like this should go in to the rails app? Should I reshuffle the structure to the default rails convention (and thus manually modify jquery ui css to fix image references) or use it as it is and combine all the files some other way?
Thanks,
Dmitriy.

If I really wanted to keep the directory structure of the jquery ui skins together, I would just exclude those css files from being cached into 1 file. Say you had 2 other css files outside of jquery ui:
stylesheet_link_tag "css-file1", "css-file2", :cache => "main"
I would just cache those and keep skins packaged with jquery ui, even if they don't get combined into a single file. I would probably do this because if a skin or a skin image got updated I would just want to be able to drop in and replace it to update it, rather than deal with restructuring directories or modifying css/js files that came with it. It's too error prone and not worth the benefit of saving 2 extra http requests.

Is there a specific reason why you need to combine them? I understand that it means more requests to your webserver, but the results will be cached. You might also want to consider using a version of jquery that's served off of the google CDN.
Alternatively if you must combine them into one file then I suggest flattening the directory structure and/or using absolute paths to your resources. The problem with this is that you'll need to be careful when updating to new version of your third party libraries as it will involve editing the libraries.
I personally use sprokets for managing my JS dependencies (instead of :cache => true), but it also won't help you with this use case. Even so, you might want to consider taking a look if you're going to have a lot of javascript.

Related

rails 4.2 assets loading

I'm playing with a rails 4.2 application and it seems like it loads all of my stylesheets for each and every page.
Is that true? How is it better than loading for each page only the relevant stylesheets?
On one hand, I know they'll all be minified when going to production, and it will reduce the total size and cache one CSS for the whole website.
On the other hand, page I might have some thin pages that will need no more than a few css lines to be rendered correctly that will get tones of files for no reason. It will also require me to be super strict and safe when choosing class names in order to have no collisions and unwanted overrides.
What about JS assets? It acts the same way?
(I guess the answer for image assets is "hell no!")
Yes, in development you'll see a lot of files (all of them) and in production they will be compiled and minified to a single file.
Once this file has been downloaded by the client it will be cached and wont need to make any further requests to load other stylesheet files on concurrent request (unless caching and turbolinks has been disabled). The downside is that the file size will be larger and make the initial load time slightly longer.
One problem as you point out is scoping. In my experience it's way better to always apply proper scopes when developing. And in rails using sass it's really easy to have nice and tidy css.
The same goes for javascript, but not for images as you pointed out.
That said. There are ways to work around this if desired, but more often than not I've realized that there are more pros than cons with a single file.
Edit:
Oh, and if you're new to rails, beware that turbolinks might cause you some headaches in the beginning messing with page ready in js-files before you get the hang of it. But it's worth it in the end.
The advantage and rationale for this is to reduce the amount of data that is sent to the client after the first page load. The first page load pulls down all the js/css (compiled into single files), but then this can be cached and reduces the amount on each subsequent page load.
The following is purely theoretical, if at all possible, try and work with the defaults of one css/jss file
If you absolutely do want to trim it down, then you can. Your application.css manifest file (or js) probably includes a line such as:
//= require_tree .
which says, require everything in this directory. you could then split this down so application.css only requires everything in the application folder (absolutely need to know):
//=require_tree ./application
Then add additional manifest files, for example for an admin section, so that the admin styles/JS can be loaded only when needed in admin.js
//=require_tree ./admin
Then in your layout file you can do
= stylesheet_link_tag "application", media: "all"
= yield :additional_stylesheets
And where you want those additional styles you can add them.
- content_for :additional_stylesheets do
= stylesheet_link_tag "admin", media: "all"
end
Note: this will cause issues if you're using turbolinks.
Note II: You may need to add these to the precompile list in application.rb:
config.assets.precompile += ['additional_manifests.css']
You could modify this workflow to not include any CSS at all to start with and only load what you need.

When I am given multiple CSS files, should I just dump all the styles in my main application.css?

I work with front-end designers that give me a bunch of HTML & CSS files. There are some things that are very straight forward - like CSS for Twitter Bootstrap or any other framework.
But when the designer has created a bunch of other stylesheets, should I just include them in the stylesheets directory or should I just copy all the styles to the main application.css file?
Is this just a matter of style or does my approach really (or not) matter with the asset pipeline?
Thanks.
The approach doesn't usually matter, but it can matter if you do not want to include everything in one stylesheet link on the final page. I'd strongly recommend keeping the stylesheets separated for the same reason you keep code separated. Easier maintenance, less conceptual overhead per file, and easier to find where to make the change you need to make.
Even though they get combined by the asset pipeline, I tend to do one stylesheet per controller, or component, with certain shared styles (navigation, forms, common UI forms) in their own file. I haven't found the perfect solution yet (I still struggle with wanting "DRYer" stylesheets), but this works pretty well.
application.css is ment to organize css file, i remember there are comments on the top of the application.css telling not to directly write css file inside it. You should create a new css file for those style-sheet content your front-end guy gave you. And as application.css will include all the files under the stylestheet folder automatically. It will work.

Ways to organise CSS in Rails project

I would like to know what are the best ways to organise CSS code in Rails project?
I'm interested in how you do it and why.
If you would like to break up your css into multiple files during development you can add cache => true to stylesheet_link_tag and rails will automatically concatenate them into a single file in production. This also works for javascript_include_tag.
http://guides.rubyonrails.org/layouts_and_rendering.html#linking-to-javascript-files-with-javascript_include_tag
Generally, you should not have the client download a massive amount of CSS snippets, but pack them into a single file on the server to avoid rendering latencies. So you have the tradeoff of having functionality divided up into multiple files put wanting to send only one file to the client.
You could use SASS to have each piece of code inside a single include file and just include all of them together. This gives you the added advantage of mixins (kind of like macros) and variables among other awesome things.
Another possibility would be to use plain CSS and use something like Jammit to pack the stuff up to send to the client.
Regarding actual setups, I tend to have one file resetting the styles to a known default, a file for the basic layout (columns, default spaces, ...), and one file each for each area of concern for your specific design (headers, buttons, ...)
James and Holger's answers are very good.
Besides organizing CSS in my projects, I also had to change colour schemes a couple of times..
Trying to do consistent changes throughout many CSS files can be pretty painful (results may vary).
I ended up extending the Rails start-up procedure a little, to include a custom module "site_settings.rb"
through which I can define variable for colors and other CSS attributes, which I can then use throughout my CSS input files.
Whenever Rails starts up, and one of the input files has changed, it auto-generates the CSS files.
http://unixgods.org/~tilo/Ruby/Using_Variables_in_CSS_Files_with_Ruby_on_Rails.html
Since Rails 3.1 is out and sprockets replaced Jammit, here an excerpt form the Rails guides concerning the asset organization:
Asset Organization
Assets can be placed inside an application in one of three locations: app/assets, lib/assets or vendor/assets.
app/assets is for assets that are owned by the application, such as custom images, JavaScript files or stylesheets.
lib/assets is for your own libraries’ code that doesn’t really fit into the scope of the application or those libraries which are shared across applications.
vendor/assets is for assets that are owned by outside entities, such as code for JavaScript plugins.

Can Rails' javascript_include_tag ignore previously-loaded scripts?

I'm using this line:
= javascript_include_tag :all, :recursive => true, :cache => true
in the footer of a Rails app to do the following:
Load all the scripts under public/javascripts recursively
In production, lump them all into one file (the :cache part)
However, I want to load one of these scripts in the head, because some inline JS depends on it.
Is there an option for javascript_include_tag to exclude files that have already been loaded?
I know it doesn't do this by default, because right now I see a script referenced twice in the source HTML.
javascript_include_tag is a simple html helper and doesn't track weather or not something has already been included on the page, so no, there isn't an option, sucks.
In place of this, you can solve your problem in a few ways:
Use something like Jammit, which I use right now and is an absolute joy. It packages all your javascripts up in production into one file, allows you to compress the shit out of them, and does the same for CSS. You configure it using a .yml file in your config directory, making it portable and easy to recursively include scripts from directories while still controlling the order in which they are included on the page or appended to the package. An alternative (less awesome IMHO) to Jammit is Asset Packager.
Use javascript_include_tag in the head. Not really the end of the world. Optimize later.
Not really Rails specific, but use head.js. head.js is pretty new but allows you to load many scripts quickly, in parallel, while preserving the execution order and taking callbacks to fire once your scripts are loaded but before the dom is ready. It includes a bunch of other goodies like HTML5 friendliness in older browsers. This option is interesting because you keep your scripts separate, or at least in different packages for maximum parallel download speed. I'm not sure weather or not downloading one huge compressed package serially in the <head> or even right at the footer, or loading things in parallel using head.js will be faster, but it sure makes managing these things easier.
I've used both head.js and Jammit recently and I must say, for heavy Javascript apps, they make things wonderfully easy.
In config/application.rb you can set the meaning of :defaults in the javascript_include_tag :
# JavaScript files you want as :defaults (application.js is always included).
config.action_view.javascript_expansions[:defaults] = %w(rails, jquery)
You can then use the :defaults parameter to use the tag in application.erb.html, or wherever you like:
<%= javascript_include_tag :defaults %>
Once you've done this at the bottom of your view template, you can of course include single scripts before it.
Now, I realise that you wanted to use the :all parameter, and load recursively, but this solution does give you more control, which I think you are going to need here.

In Ruby on Rails how can I combine multiple Javascript files at runtime?

I am building a Facebook App which is heavy on Javascript. For this I have multiple Javascript files. Since in Facebook development, the page is served over a tunnel, there is excessive latency added while requesting multiple javascript files. Is it possible to combine the contents of multiple javascript files at runtime? Having multiple files makes it easy to develop, and hence I am avoiding having to combine it while development itself.
You can pass a :cache option to the javascript_include_tag which will combine the files into one:
<%= javascript_include_tag :all, :cache => true %>
Note that this depends on ActionController::Base.perform_caching being set to true, which it is by default for the Rails production environment.
See http://api.rubyonrails.org/classes/ActionView/Helpers/AssetTagHelper.html#M001493
in your config file for the environment located at /config/environments, you have a file for each, like development.rb and so on.
In that file, you can set config.assets.debug = false
and that will reduce files down to 1 js file, and 1 css file.
Better than combining at runtime, have a look at Frizione. It's a framework that will allow you to combine your javascript files at deploy time, and compress them. So you get to save all around. It throws in doc generation and JSLint checking as well, but that's just an added bonus.
Jammit is a good catch too, to combile js and css files.
http://documentcloud.github.com/jammit/
I've used the asset_packager gem to do this in my applications.
It will combine and minimize your javascript (and CSS) files for production and adds some view helpers that make it very easy to use. There's a rake command that you run to generate the packaged files if the originals have changed.

Resources