Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,14 @@

# Ignore master key for decrypting credentials and more.
/config/master.key

/public/packs
/public/packs-test
/node_modules
/yarn-error.log
yarn-debug.log*
.yarn-integrity

# Generated React on Rails packs
**/generated/**
ssr-generated
5 changes: 5 additions & 0 deletions Procfile.dev
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Procfile for development using HMR
# You can run these commands in separate shells
rails: bundle exec rails s -p 3000
wp-client: WEBPACK_SERVE=true bin/shakapacker-dev-server
wp-server: SERVER_BUNDLE_ONLY=yes bin/shakapacker --watch
8 changes: 8 additions & 0 deletions Procfile.dev-prod-assets
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Procfile for development with production assets
# Uses production-optimized, precompiled assets with development environment
# Uncomment additional processes as needed for your app

rails: bundle exec rails s -p 3001
# sidekiq: bundle exec sidekiq -C config/sidekiq.yml
# redis: redis-server
# mailcatcher: mailcatcher --foreground
2 changes: 2 additions & 0 deletions Procfile.dev-static-assets
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
web: bin/rails server -p 3000
js: bin/shakapacker --watch
9 changes: 9 additions & 0 deletions app/controllers/hello_world_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# frozen_string_literal: true

class HelloWorldController < ApplicationController
layout "hello_world"

def index
@hello_world_props = { name: "Stranger" }
end
end
15 changes: 15 additions & 0 deletions app/javascript/packs/application.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/* eslint no-console:0 */
// This file is automatically compiled by Webpack, along with any other files
// present in this directory. You're encouraged to place your actual application logic in
// a relevant structure within app/javascript and only use these pack files to reference
// that code so it'll be compiled.
//
// To reference this file, add <%= javascript_pack_tag 'application' %> to the appropriate
// layout file, like app/views/layouts/application.html.erb

// Uncomment to copy all static images under ./images to the output folder and reference
// them with the image_pack_tag helper in views (e.g <%= image_pack_tag 'rails.png' %>)
// or the `imagePath` JavaScript helper below.
//
// const images = require.context('./images', true)
// const imagePath = (name) => images(name, true)
1 change: 1 addition & 0 deletions app/javascript/packs/server-bundle.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
// Placeholder comment - auto-generated imports will be prepended here by react_on_rails:generate_packs
21 changes: 21 additions & 0 deletions app/javascript/src/HelloWorld/ror_components/HelloWorld.client.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import React, { useState } from 'react';
import * as style from './HelloWorld.module.css';

const HelloWorld = (props) => {
const [name, setName] = useState(props.name);

return (
<div>
<h3>Hello, {name}!</h3>
<hr />
<form>
<label className={style.bright} htmlFor="name">
Say hello to:
<input id="name" type="text" value={name} onChange={(e) => setName(e.target.value)} />
</label>
</form>
</div>
);
};

export default HelloWorld;
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.bright {
color: green;
font-weight: bold;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import HelloWorld from './HelloWorld.client';
// This could be specialized for server rendering
// For example, if using React Router, we'd have the SSR setup here.

export default HelloWorld;
2 changes: 2 additions & 0 deletions app/views/hello_world/index.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<h1>Hello World</h1>
<%= react_component("HelloWorld", props: @hello_world_props, prerender: true) %>
1 change: 1 addition & 0 deletions app/views/layouts/application.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

<%# Includes all stylesheet files in app/assets/stylesheets %>
<%= stylesheet_link_tag :app %>
<%= javascript_pack_tag "application" %>
</head>

<body>
Expand Down
15 changes: 15 additions & 0 deletions app/views/layouts/hello_world.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<!DOCTYPE html>
<html>
<head>
<title>ReactOnRailsWithShakapacker</title>
<%= csrf_meta_tags %>

<!-- Empty pack tags - React on Rails injects component CSS/JS here -->
<%= stylesheet_pack_tag %>
<%= javascript_pack_tag %>
</head>

<body>
<%= yield %>
</body>
</html>
36 changes: 36 additions & 0 deletions babel.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// The source code including full typescript support is available at:
// https://github.com/shakacode/react_on_rails_demo_ssr_hmr/blob/master/babel.config.js

module.exports = function (api) {
const defaultConfigFunc = require('shakapacker/package/babel/preset.js')
const resultConfig = defaultConfigFunc(api)
const isProductionEnv = api.env('production')

const changesOnDefault = {
presets: [
[
'@babel/preset-react',
{
development: !isProductionEnv,
useBuiltIns: true,
runtime: 'automatic'
}
]
].filter(Boolean),
plugins: [
// Enable React Refresh (Fast Refresh) only when webpack-dev-server is running (HMR mode)
// This prevents React Refresh from trying to connect when using static compilation
!isProductionEnv && process.env.WEBPACK_SERVE && 'react-refresh/babel',
isProductionEnv && ['babel-plugin-transform-react-remove-prop-types',
{
removeImport: true
}
]
].filter(Boolean),
}

resultConfig.presets = [...resultConfig.presets, ...changesOnDefault.presets]
resultConfig.plugins = [...resultConfig.plugins, ...changesOnDefault.plugins ]

return resultConfig
}
34 changes: 33 additions & 1 deletion bin/dev
Original file line number Diff line number Diff line change
@@ -1,2 +1,34 @@
#!/usr/bin/env ruby
exec "./bin/rails", "server", *ARGV
# frozen_string_literal: true

# ReactOnRails Development Server
#
# This script provides a simple interface to the ReactOnRails development
# server management. The core logic is implemented in ReactOnRails::Dev
# classes for better maintainability and testing.
#
# Each command uses a specific Procfile for process management:
# - bin/dev (default/hmr): Uses Procfile.dev
# - bin/dev static: Uses Procfile.dev-static-assets
# - bin/dev prod: Uses Procfile.dev-prod-assets
#
# To customize development environment:
# 1. Edit the appropriate Procfile to modify which processes run
# 2. Modify this script for project-specific command-line behavior
# 3. Extend ReactOnRails::Dev classes in your Rails app for advanced customization
# 4. Use classes directly: ReactOnRails::Dev::ServerManager.start(:development, "Custom.procfile")

require "bundler/setup"
require "react_on_rails/dev"

# Default route configuration
# This is set by the ReactOnRails installer to point to your generated component.
# Change this to your preferred default route, or pass --route=<route> to override.
DEFAULT_ROUTE = "hello_world"

# Main execution
# Add the default route to ARGV if no --route option is provided
argv_with_defaults = ARGV.dup
argv_with_defaults.push("--route", DEFAULT_ROUTE) unless argv_with_defaults.any? { |arg| arg.start_with?("--route") }

ReactOnRails::Dev::ServerManager.run_from_command_line(argv_with_defaults)
3 changes: 3 additions & 0 deletions bin/setup
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ FileUtils.chdir APP_ROOT do
puts "== Installing dependencies =="
system("bundle check") || system!("bundle install")

# Install JavaScript dependencies
system!("npm install")

puts "\n== Removing old logs and tempfiles =="
system! "bin/rails log:clear tmp:clear"

Expand Down
11 changes: 11 additions & 0 deletions bin/shakapacker
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#!/usr/bin/env ruby

ENV["RAILS_ENV"] ||= "development"
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", __FILE__)
ENV["APP_ROOT"] ||= File.expand_path("..", __dir__)

require "bundler/setup"
require "shakapacker"
require "shakapacker/runner"

Shakapacker::Runner.run(ARGV)
13 changes: 13 additions & 0 deletions bin/shakapacker-dev-server
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/usr/bin/env ruby

ENV["RAILS_ENV"] ||= "development"
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", __FILE__)

require "bundler/setup"
require "shakapacker"
require "shakapacker/dev_server_runner"

APP_ROOT = File.expand_path("..", __dir__)
Dir.chdir(APP_ROOT) do
Shakapacker::DevServerRunner.run(ARGV)
end
67 changes: 67 additions & 0 deletions config/initializers/react_on_rails.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# frozen_string_literal: true

# See https://github.com/shakacode/react_on_rails/blob/master/docs/guides/configuration.md
# for many more options.

ReactOnRails.configure do |config|
# This configures the script to run to build the production assets by webpack. Set this to nil
# if you don't want react_on_rails building this file for you.
# If nil, then the standard shakacode/shakapacker assets:precompile will run
# config.build_production_command = nil

################################################################################
################################################################################
# TEST CONFIGURATION OPTIONS
# Below options are used with the use of this test helper:
# ReactOnRails::TestHelper.configure_rspec_to_compile_assets(config)
################################################################################

# If you are using this in your spec_helper.rb (or rails_helper.rb):
#
# ReactOnRails::TestHelper.configure_rspec_to_compile_assets(config)
#
# with rspec then this controls what npm command is run
# to automatically refresh your webpack assets on every test run.
#
# Alternately, you can remove the `ReactOnRails::TestHelper.configure_rspec_to_compile_assets`
# and set the config/shakapacker.yml option for test to true.
config.build_test_command = "RAILS_ENV=test bin/shakapacker"

################################################################################
################################################################################
# SERVER RENDERING OPTIONS
################################################################################
# This is the file used for server rendering of React when using `(prerender: true)`
# If you are never using server rendering, you should set this to "".
# Note, there is only one server bundle, unlike JavaScript where you want to minimize the size
# of the JS sent to the client. For the server rendering, React on Rails creates a pool of
# JavaScript execution instances which should handle any component requested.
#
# While you may configure this to be the same as your client bundle file, this file is typically
# different. You should have ONE server bundle which can create all of your server rendered
# React components.
#
config.server_bundle_js_file = "server-bundle.js"

# Configure where server bundles are output. Defaults to "ssr-generated".
# This should match your webpack configuration for server bundles.
config.server_bundle_output_path = "ssr-generated"

# Enforce that server bundles are only loaded from private (non-public) directories.
# When true, server bundles will only be loaded from the configured server_bundle_output_path.
# This is recommended for production to prevent server-side code from being exposed.
config.enforce_private_server_bundles = true

################################################################################
################################################################################
# FILE SYSTEM BASED COMPONENT REGISTRY
################################################################################
# `components_subdirectory` is the name of the matching directories that contain automatically registered components
# for use in the Rails views. The default is nil, you can enable the feature by updating it in the next line.
config.components_subdirectory = "ror_components"
#
# For automated component registry, `render_component` view helper method tries to load bundle for component from
# generated directory. default is false, you can pass option at the time of individual usage or update the default
# in the following line
config.auto_load_bundle = true
end
1 change: 1 addition & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
Rails.application.routes.draw do
get "hello_world", to: "hello_world#index"
# Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html

# Reveal health status on /up that returns 200 if the app boots with no exceptions, otherwise 500.
Expand Down
Loading
Loading