The lack of documentation and blog posts on this topic is painful. I would have imagined it to be a more popular request.
For anyone else struggling, I was able to do some hair pulling and get the below setup to work!
Disclaimer: I have no idea how "correct" this solution is and whether it's recommended or not. I'd love for someone who knows more about rails engines and the asset pipeline to edit as needed.
I tested this in all 4 combinations of development
/production
and prerender: true
/ prerender: false
. (I tested production
on my local machine by setting RAILS_ENV
)
Definitions
The below examples use the following definitions
blorgh
- Name of your engine (lifted from the official Rails docs)
SomeComponent
/ some_component.jsx
- Name of a React component we want to include
RAILS_ROOT
- The root path of the dummy host application inside your engine test or spec folder
ENGINE_ROOT
- The root path of your Rails Engine
Setup
As per the react-rails
docs, run the generator from your ENGINE_ROOT
which will create several files for you.
rails generate react:install
Engine Configuration - Assets Folder
Folder structure should be -
- app/
- assets/
- config/
- blorgh_manifest.js
- javascripts/
- blorgh/
- components/
- some_component.jsx
- application.js
- components.js
- server_rendering.js
Both components.js
and server_rendering.js
essentially include React for you and then require your components under the components/
folder. But components.js
is included through application.js
whereas server_rendering.js
is invoked when you are pre-rendering server side
The manifest itself I don't understand very well, but like it's name suggests it seems to be a manifest of all your engine's CSS and JS assets
Manifest (this should already exist, just including for clarity)
# app/assets/config/blorg_manifest.js
//= link_directory ../javascripts/blorgh .js
//= link_directory ../stylesheets/blorgh .css
Application
# app/assets/javascripts/blorgh/application.js
//= require react
//= require react_ujs
//= require ./components
//= require_tree .
Components
# app/assets/javascripts/blorgh/components.js
//= require_tree ./components
Server Rendering
# app/assets/javascripts/blorgh/server_rendering.js
//= require react-server
//= require react_ujs
//= require ./components
Some Component (just a sample to test with)
var SomeComponent = React.createClass({
propTypes:{
},
getInitialState: function() {
return {};
},
render: function() {
return (
<div>
THIS IS IN REACT WOOHOO
</div>
);
}
});
Engine Configuration - Application
Engine Initializer - need to namespace the file for asset prcompilation
# config/initializers/react_server_rendering.rb
Rails.application.config.assets.precompile += ["blorgh/server_rendering.js"]
Engine - require react and configure it
require "react-rails"
module Blorgh
class Engine < ::Rails::Engine
isolate_namespace Blorgh
# ....
initializer("blorgh.react-rails") do |app|
app.config.react.variant = Rails.env.to_s
# Make sure the file is explicitly referenced for server side rendering
app.config.react.server_renderer_options = {
files: ["blorgh/server_rendering.js"]
}
end
end
end
HTML View - render the component
<%= react_component("SomeComponent", {}, { prerender: false }) %>
# or
<%= react_component("SomeComponent", {}, { prerender: true }) %>
Host application configuration
Your host application should include your engine's assets. To do that, you need to instruct the users of your engines to add this to their application files
#{RAILS_ROOT}/app/assets/javascripts/application.js
// Make sure it appears above `require_tree .`
//= require blorgh_manifest.js
Run it in development
Now when you run rails server
the above should load your component
Testing "Production" locally
If you want to ensure everything runs ok on production, you'll want to run your app in production mode locally
cd RAILS_ROOT
rake assets:precompile
cd ENGINE_ROOT
RAILS_SERVE_STATIC_FILES=true SECRET_KEY_BASE=(...) rails s -e production