EDIT: Answered my own question in detail below, so editing this retro-actively to simplify the question
How do I include ReactJS into my Rails Engine?
If I add the react-rails gem directly, I get the error
React::ServerRendering::PrerenderError in Blorgh::Dashboards#show
Encountered error "#<ExecJS::ProgramError: TypeError: undefined is not an object (evaluating 'this.ReactRailsUJS.serverRender')>" when prerendering SomeComponent
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)
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 includeRAILS_ROOT - The root path of the dummy host application inside your engine test or spec folderENGINE_ROOT - The root path of your Rails EngineAs per the react-rails docs, run the generator from your ENGINE_ROOT which will create several files for you.
rails generate react:install
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 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 }) %>
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
Now when you run rails server the above should load your component
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With