Rails Assets Best Practices [closed] - ruby-on-rails

It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 10 years ago.
I'm new to Rails, and having trouble figuring out the best way to organize my assets. The purpose of this question is to collect my thoughts, solicit input, and evolve the document over time - perhaps it can be a Rails Guide someday. (The Rails Wiki appears to be dead.) This will be meant as an aid to conceptualization for novices, not a reference, so it will be limited to the most common scenarios.
Asset Pipeline - Overview
For details on the purpose, benefits, and inner workings of the pipeline, start with this guide: http://guides.rubyonrails.org/asset_pipeline.html I will only summarize the bits relevant to my purposes here.
The reasons the pipeline is necessary are:
Compilation: To compile high-level languages (ERb, Haml, Sass, LESS, CoffeeScript...) into plain CSS/JS.
The additional benefits of the pipeline are:
Concatenation: Combining multiple files into one to improve client performance.
Minification: Removing whitespace and other clever optimizations to reduce file size.
Fingerprinting: Added an MD5 hash of the file contents to the filename to force caches to **fetch the file again when it changes.
Asset Pipeline - Default Filesystem Layout
app|lib|vender/assets/ - Intended for files which will be processed by the pipeline.
app/assets/ - Intended specifically for files you created for your application.
lib/assets/ - Intended specifically for files you created for sharing across multiple applications.
vendor/assets/ - Intended specifically for files created by others, such as jQuery and Twitter Bootstrap (though they are frequently provided by gems instead of being imported directly into /vender).
public/ - Files in here are left as is, and fetchable directly from the root path ('/') of your web app.
Asset Pipeline - Default Files and Behavior
app/assets/javascripts/application.js
//= require jquery
//= require jquery_ujs
//= require_tree .
app/assets/stylesheets/application.css
/*
*= require_self
*= require_tree .
*/
public/404.html
public/robots.txt
...
Gemfile
...
gem 'jquery-rails'
...
Here's what the asset pipeline compiler does using the default setup of a new Rails app:
The compiler, by default, will process application.js, application.css, and all non-JS/CSS files (images, mostly).
The two application files contain sprockets directives (the comment lines that start with =). Sprockets is the library that powers the Rails asset pipeline compilation. These directives are also called manifests, since they list files for inclusion.
application.js contains a manifest that pulls in two jquery files (which exist in the jquery-rails gem, not in your app), then pulls in all files in the app/assets/javascripts/ tree via require_tree .. All files included via this manifest will get compiled into a single file called application-[the MD5 hash].js, and placed in public/assets/.
application.css contains a manifest that pulls in all files in the app/assets/stylesheets/ tree via require_tree .. The required_self directive tells the compiler to include any CSS content in the application.css file itself, and in the order of the directives. So, in this case, the CSS in application.css will appear above the rest. All files included via this manifest will get compiled into a single file called application-[the MD5 hash].css, and placed in public/assets/.
All non-JS/CSS files (images, mostly) in the app/assets tree will also get fingerprinted and placed in public/assets/, with the directory structure intact. For example, app/assets/images/categories/computers.png will end up as public/assets/categories/computers-[the MD5 hash].png.
Conceptualizing Intra-Asset Dependency Scenarios
Images
Images have no dependencies between them, they always stand alone.
Stylesheets
CSS: CSS files can import each other, which will work as long as paths are correct, though it's probably not the best technique.
Sass: Sass files can import each other, as well as share variables and mixins, but only when they are still Sass (not after compiling to CSS), and only via Sass imports. If you have sprockets directives in application.css.scss that requires 'a' and 'b', they will be compiled in separate contexts before merging. To share variables and mixins, you must import 'a' from 'b' or vice versa using Sass import directives. (See Key Concept 1 below.)
LESS: [Don't know enough about this.]
JavaScript
JS: JavaScript components have inter-dependencies (example: Twitter Bootstrap uses jQuery). However, they all get resolves at runtime in the browser, so it doesn't matter how your organize/combine the files in your project, as long as all the contents eventually get loaded by the browser.
CoffeeScript: [Don't know enough about this.]
Helper Behavior - Rails Views
TODO
Helper Behavior - Sass
TODO
Best Practices - Key Concepts
The pipeline is for preparing assets for production. Think of it as part of the deployment system, not the application itself. Establish the logical structure of your app yourself, then configure sprockets to operate correctly on that structure.
Best Practices - The Common Asset Scenarios
TODO
Best Practices - Summary of Generally Useful Defaults
TODO
** Questions **

Related

Difference between // and //= in application.js?

In every language I can think of, placing the comment decorator at the start of a line will comment out that line of code (without any exceptions).
In rails, in application.js I see some lines starting with // and others starting with //=. I presume lines starting with // are comments and those lines are not executed.
Question
What's the difference between
lines starting with //
lines starting with //= and
lines starting with neither of those decorators?
From here:
Sprockets is a Ruby library for compiling and serving web assets. Sprockets allows to organize an application’s JavaScript files into smaller more manageable chunks that can be distributed over a number of directories and files.
Also:
When it comes to asset bundling, the "Rails way" is webpack for JavaScript and Sprockets for everything else. The default setup in a fresh Rail 6 install, similar to what Basecamp uses, still compiles CSS, images, and fonts with Sprockets.
So basically
lines starting with //= is a sprocket processor directive (and it will get executed)
lines starting with // are simply comments (they won't get executed), and
lines starting with neither are javascript

What is the proper way to link big template assets into rails erb files?

I am developing a rails application starting from webarch template. I know that adding the whole assets folder in the public/ folder will link the assets with my views, but it would not be taking advantage of the assets pipeline functions. The template has a lot of plugins and different options and one generally does not use all of it. The assets folder's size is 30MB.
I though about putting it inside vendor/assets and using it with the asset pipeline but this generates two problems:
I would be serving 30MB of minified code and using a small percentage of it in my app.
I would have to manually rewrite the whole assets folder to use links the way asset pipeline wants it (javascript_include_tag "file" to serve file.js). Of course, I would do this via a script but it still seems like a problem someone should have encountered first.
Since neither vendor/assets and public/ folders seem to be a proper location for these files I would like a better option (or a way to make the later options work better).
A solution to keep your files under asset pipeline when they are too big to reasonably be left in one single minimified asset file is to split your assets by categories, compile those categories in different minimified files, and include them in your views when needed.
I do it for an app that contains several "heavy" javascripts components that are located in different area of my app and are not often used.
1- Organize your file structure
In app/assets/javascrips and app/assets/stylesheets create one directory per category we are going to create. Examples:
app/assets/javascrips/common
app/assets/javascrips/admin
app/assets/javascrips/user_account
2- Create your manifests
In app/assets/javascrips and app/assets/stylesheets create one manifest file per category and have them included the related directory
File app/assets/javascrips/common.js
//= require jquery
//= require_tree ./common
File app/assets/javascrips/admin.js
//= require_tree ./admin
File app/assets/javascrips/user_account.js
//= require_tree ./user_account
3- Add your manifests to rails precompile list
You can do it in config/application.rb file, but when it gets big it is preferable to create an initializer file config/initializers/assets.rb
Rails.application.configure do
config.assets.precompile += %w[common.js admin.js user_account.js]
end
4- Include them in your views and layouts, and set-up your javascript libraries.
Import the assets files into layouts and views. It can be a good idea to create several layouts for different area of your application that would be using common assets files. The methods to use are
stylesheet_link_tag 'manifest_file' and javascript_include_tag 'manifest_file'
And keep in mind you may have to tell your javascript plug-ins they need to use the miniminied file when dynamically loading files. For them you can use a configuration .js.erb file. Example:
File app/assets/javascrips/admin/plug-in_config.js.erb
PLUGIN.config('dynamicFileName', '<%= javascript_path('manifest_file') %>');

Sprockets::CircularDependencyError in manifest file using asset pipeline

i am trying to use asset pipeline and want to have more then one manifest file. At present i have application.css manifest file and admin_area.css manifest file. One of the stack answer suggested to remove application.css manifest, however it will not solve my intent.
Current Error msg:
Sprockets::CircularDependencyError in Authenticate#dashboard
projectfolder/app/assets/stylesheets/admin_area.css has already been required
My current rails version is : 4.1.5
And also please suggest solution to have more then one javascript manifest file.
thanks in advance.
If you have require_tree . directive in both your manifests - one of them tries to require another manifests, and another will try to require first, and it leads to circular error.
Instead you should explicitly require assets in your manifests.
Manifest file: If you look at docs, it says
Sprockets uses manifest files to determine which assets to include and serve. These manifest files contain directives - instructions that tell Sprockets which files to require in order to build a single CSS or JavaScript file
so in short rails asset pipeline precompile your all of your assets like css,js in single file(one file for all of your css files and one js file for all of your js). By doing this load time of your pages is significantly reduced because your browser makes fewer requests to get these files individually.
Having More than one manifest files:
In some cases like in your case or if you are making your app compatible with <= IE8 then you might want to have more than one manifest files as IE only allows a some fixed size of your styles and ignore your other styles
To achieve this you follow these steps:
a. Remove require_tree . from your application.css file because it will require all of your styles present in app/assets/stylesheets and hence you should require each file individually.
b. In case of Production you need to precompile your assets and for that you'll have to add your individual files by
#config/application.rb or config/environments/production.rb
Rails.application.config.assets.precompile += ['admin_area.css', 'other.css', 'some_file.js']
Your error:
Sprockets::CircularDependencyError in Authenticate#dashboard projectfolder/app/assets/stylesheets/admin_area.css has already been required
Your error clearly says you have a circular dependency meaning one of your files is trying to load resources of other and other one is trying to load resources of first one making a circular dependency. As #MikDiet already mentioned in his answer that you have require_tree . in both of your css files.

RoR asset pipeline best practices for one-off JS plugins

I have a best practices question regarding one-off javascript plugins and their role in the Rails asset pipeline.
I'm new to Rails, and am working on a new project. The site template I'm using uses a large collection of js plugins for added functionality. (eq chartjs.org, ckeditor, and about 40 others) Since these are needed on a page-by-page basis, I'm not sure if I should really load them all in the application.js manifest.
Currently, I have the template's assets under the /vendor directory and only the core assets are being loaded from my application.js manifest.
Thoughts on how/where to include the plugins?
As i know that rails default added all js file include in application.js by //= require_tree . so, you can remove it and add only those file which you want to added. and if you want to run only specific function then you can use location.pathname with condition and it will work for only that specific page.

Rails 3.1 asset pipeline - missing files from public/assets - why isn't this the default?

After I deployed my upgraded Rails 2.3.x -> 3.1 (rc4) app to our test environment this afternoon, all of our stylesheets and JavaScript files were returning 404 errors. We had added the rake assets:precompile task to our post-deploy script and it took a while to determine why the assets folder didn't have the pre-compiled files we expected.
In the end, the files weren't being compiled because apparently only application.css and application.js (+ non JS/CSS files) are processed by default.
We needed to change the following configuration value as follows:
config.assets.precompile += %w( *.js *.css )
Question: why isn't this the default?
I would have expected that anything that wasn't necessary to process as a manifest file would just get copied into public/assets. Much of what I've read on the asset pipeline is essentially "stick your assets in app/assets, configure the manifest files, and it should just work". Since the assets:precompile task didn't spit out any information about what it was doing, it took a while to determine that it just wasn't looking at the files we thought it would.
Is there any reason why this would not be a good value for the precompile configuration?
Thanks!
The idea is to have all your JavaScript and CSS always loaded in one shot, rather than loading bits and pieces as you move along. That way you always have the 'world' loaded and ready to work with, rather than having to include a whole bunch of individual files here and there.
It's a bit of a larger 'up front' load, but then the browser should keep loading all the javascript from cache. So the perceived speed of the site should speed up due to having everything cached and ready to go after the first request.
This was a controversial decision to include for Rails, but so is including CoffeeScript by default. Rails has always been an opinionated framework that way.
the new sprockets-based pipeline compiles all the files in /asssets/stylesheets and /assets/javascripts get compiled into application.css and application.js, respectively, by default.
In your views, you only need to link the application files, sprockets handles the rest.
Update:
Well, you don't have to make it all into just one file... You could have an shared.js, secure.js and public.js and have them each include the parts they need...
Think of them not as javascript files, but manifest files that establish groups of javascript files which you can then include as a group with a single javascript_include_tag. While the default is to include everything in the folder into a single file, you can be always pick and choose what to include, and what not.
The 'precompile' task simply runs those manifest files and compiles the multiple files into one, while pre-processing and sass or coffee script it runs across.

Resources