Sprocket: Difference Between "Require" and "Require Tree"
As a Rails developer, you should have worked with Sprocket to deal with front-end resources. This article highlights a key difference between require
and require_tree
.
When require
is used, Sprocket searches the file from search paths. You can find out the search paths by inspecting Rails.application.config.assets.paths
in Rails console. The search starts from the first path in the list to the last one until the required file is found. In contrast, when require_tree
is used, Sprocket gets all the files from the relative directory specified in the argument, and these files are required in alphabetical order.
As a result, we can see that Sprocket loads file in different ways between require
and require_tree
. This can cause some chaotic behavior. I encountered such a case in my project. There is a JavaScript file called foo.js
in one of the gem, and this gem loads JavaScripts in the following maner:
//= require foo
//= require_tree .
The gem require foo.js
first because it defines a function bar
, and this function is called by the rest of the JavaScript files. However, the function bar
did not meet my requirements, so I decided to overwrite it. I wrote another foo.js
with a new implementation of function bar
, and put the new foo.js
under app/assets/javascripts
. Since //= require foo
loads foo.js
from search paths, and the path app/assets/javascripts
has a higher priority than the path inside the gem, I expected that the overwritten foo.js
would be loaded instead of the original one, and the new function bar
should take effect.
However, I noticed that the new function bar
did not take effect. Moreover, I found that both original and new foo.js
were loaded. I spent a lot of time to troubleshoot, and finally I realized that //= require foo
loaded the new foo.js
from app/assets/javascripts
, while //= require_tree .
loaded the original one from the specified directory. The new foo.js
was loaded before the original one, so the bar function in the original foo.js
took effect.
Finally, I solved it by renamed the new foo.js
to foo2.js
, and added a //= require foo2
at the bottom of application.js
in the application. It is working because the bar
function in foo2.js
is loaded later than the original bar
function, though this solution is not clean. Anyway, this is a good lesson to understand the difference between require
and require_tree
in Sprocket and be aware of it in future.