I'm using browserify-rails and I'm trying to get sprockets to preprocess a file that contains a sprockets directive, so that when I require()
it using browserify, it will contain the generated JavaScript.
The sprockets directive tries to include the output of the gem js-routes, in order to allow me to access the Rails routes from the clientside.
This is my setup (within app/assets/javascripts
):
system/
rails_routes.js
application.js
application.js
is the main file, and it runs the rest of the application. I would like to be able to do something like
var rr = require("./system/rails_routes.js");
in it, and get access to the routes object.
Within system/react_routes.js
, I have the following:
//= require js-routes
console.log("Does this work?");
(as an aside, I configured js-routes
to place the output in an object called module.exports
, so to comply with the CommonJS model, as described in railsware/js-routes#121)
The only issue is that when I look at the generated bundle, the sprockets directive is still there and has not been expanded.
The console.log
call is also there and gets executed when I require()
the module.
Is there a way to get this to work? What is the correct way to have sprockets preprocess a file before bundling it with browserify-rails?
I’ve spent endless hours on integrating browserify-rails in my project and making JS Routes work within this setup…
The solution I came to and described below is the result of me not being able to have Sprockets pre-process my routes file before Browserify would come in. I have spent quite some time in both the source code of browserify-rails and sprockets but couldn't find a way to turn things around and have each component act in the correct order for this to work.
So my solution was to use a Rails hook to generate the complete JS file « by hand » in the development environment, so that routes are always up to date with the latest Rails routes files. I then assume the routes JS file will be up to date when pushing to production.
Doing so in the environment loading makes sure the JS file is ready before Sprockets/browserify chime in: for them it’s just another plain JS file.
Here's the code to include in development.rb
:
ActionDispatch::Reloader.to_prepare do
Rails.application.reload_routes!
if JsRoutes.assert_usable_configuration!
JsRoutes.generate!(Rails.root.join('app/assets/javascripts/routes.js'))
end
end
You'll want to always reload routes, otherwise the generated file will always represent the second to last state of the Rails routes file. I never figured out why...
In my application.js
, I then just removed all //=
directives but the jQuery ones (to keep a global jQuery available), and used the require
method for all other modules so that browserify would pick the files I want to include.
So this is a bit hacky, but it does work.
I'd be interested to see whether someone with better knowledge of the Sprockets pipeline could come with a better solution?