Traditionally, in order to use any javascript library (js lib), Rails users will do either of these two things:
- Directly copy paste js lib source into
vendor/assets/javascript
folder - Create a gem, add js lib source to gem, and reuse that gem.
First option is problematic because users have to keep track of changes to js lib, and update them whenever required. Second option delegates this responsibility to gem author, and users will just bump up gem version and most of the times assume that latest gem will have latest js lib. Both these approaches have problems because everytime js lib author improves lib either users have to copy sources or gem authors have to make a new release.
Of late, creating js libs and distributing them through bower has gained lot of traction. There are different ways to use bower with Rails. A popular way is to use bower rails gem. This blog will not use this gem, but explores sprockets inbuilt support for bower.
Sprockets - Bower support
Sprockets has support for bower. It doesn't do package management on its own, but it can understand bower package structure, and pick up js, and css files from bower package. Lets go through this simple example:
- Create a simple rails app. Just use
rails new
, nothing new here. - Install Faker js lib and use it in rails app.
Setting up bower json file
Packages installed from bower need to be specified in a bower.json
file.
Run bower init command at the root of rails app to generate this file.
This file will be checked into version control, so that other devs can
also know about dependencies.
One of the important things to note here is to mark this package as private so that its not published by mistake. The generated bower.json file can be further edited, and un-necessary fields like homepage, author can be removed.
Note: This is a one time process.
Setting up .bowerrc
file
Since rails automatically picks up assets from fixed locations, bower can be
instructed to install packages to one of the pre defined locations. Create a
.bowerrc
file like this:
Since bower brings in third party js libs, its recommended to put them under
vendor
folder. Note: This is a one time process
Installing Faker js lib and using it
Use bower install to install above said lib. Since .bowerrc
defaults the
directory to vendor/assets/javascript
, Faker will be installed under this
directory. Use --save
option with bower to update bower.json
.
Thats it! Faker lib is installed. Add an entry in application.js
and use
the lib.
Note: Make sure that its just Faker
and not Faker.js
. More details on
why no extension will be explained later in the blog post.
What just happened? How did it work?
The vendor/assets/javascript
folder has a folder called Faker
, and
that folder does not have any file called Faker.js
. Inspecting any page
from the rails app, script tab looks like this:
Looking at source code of Faker, there is a file called
faker.js
, and is under build/build
folder. How did rails app know
the location of this file, even though application.js doesnot have explicit
path? This is where sprockets support for bower kicks in:
- Sprockets will search for
Faker
in asset paths. - If found, it checks whether its a file or a directory. In the rails app,
bower installed this lib under directory
Faker
. - If directory, it checks if the directory contains
bower.json
file. In the rails app, Faker folder does havebower.json
file. - It decodes json file, and parses
main
field containing files and returns the desired assets.
Now, bower.json
for Faker has explicit path for faker.js
, which will
be returned by sprockets
Bonus: Digging into sprockets source code
First, sprockets will populate asset search paths. When sprockets sees
require Faker
in application.js
, it checks for extension, and since
there is no extension, ie .js
, asset search paths will be populated
with 3 paths:
Faker/.bower.json
Faker/bower.json
Faker/components.json
Gist of the source:
Source code is here: populating asset paths
Second, while resolving require Faker
, if bower.json
file is found,
sprockets will parse the json file, and fetches main
entry. Gist of
the source:
Source code is here: resolving bower json