Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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
9 changes: 5 additions & 4 deletions .controlplane/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,8 @@ RUN SECRET_KEY_BASE=precompile_placeholder yarn res:build && \
# For Kubernetes and ControlPlane, this is the command on the workload.
ENTRYPOINT ["./.controlplane/entrypoint.sh"]

# Default args to pass to the entry point that can be overridden
# For Kubernetes and ControlPlane, these are the "workload args"
# Use Thruster HTTP/2 proxy for optimized performance
CMD ["bundle", "exec", "thrust", "bin/rails", "server"]
# Run the Pro Node renderer and Rails in a single container (Option 1 from
# docs/oss/building-features/node-renderer/container-deployment.md).
# `wait -n` exits on first child failure → container exits → Control Plane
# restarts the whole unit. Keeps the existing Thruster HTTP/2 proxy for Rails.
CMD ["bash", "-c", "node renderer/node-renderer.js & RENDERER_PID=$! ; bundle exec thrust bin/rails server & RAILS_PID=$! ; wait -n ; exit 1"]
Comment thread
ihabadham marked this conversation as resolved.
Comment thread
ihabadham marked this conversation as resolved.
Comment thread
ihabadham marked this conversation as resolved.
Comment thread
ihabadham marked this conversation as resolved.
Comment thread
ihabadham marked this conversation as resolved.
23 changes: 23 additions & 0 deletions .controlplane/templates/app.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,29 @@ spec:
# set to a secure random value using: openssl rand -hex 64
# Production apps should configure this manually after app creation via a secret.
value: 'placeholder_secret_key_base_for_test_apps_only'
# Pro Node renderer settings. The renderer process runs in the same
# container as Rails (see .controlplane/Dockerfile CMD).
- name: RENDERER_PORT
value: '3800'
- name: RENDERER_LOG_LEVEL
value: info
- name: RENDERER_WORKERS_COUNT
value: '2'
- name: RENDERER_URL
value: http://localhost:3800
# Enable the artificial Suspense demo delay so the streaming fallback is
# visible on the review-app. Off by default in production deployments.
- name: RSC_SUSPENSE_DEMO_DELAY
value: 'true'
Comment thread
ihabadham marked this conversation as resolved.
# RENDERER_PASSWORD and REACT_ON_RAILS_PRO_LICENSE must be created in the
# Control Plane Secret named by {{APP_SECRETS}} before deploy. cpflow
# resolves {{APP_SECRETS}} to `{APP_PREFIX}-secrets` — which means review
# apps all share one `qa-react-webpack-rails-tutorial-secrets` (thanks to
# match_if_app_name_starts_with: true on the qa template).
- name: RENDERER_PASSWORD
value: cpln://secret/{{APP_SECRETS}}.RENDERER_PASSWORD
- name: REACT_ON_RAILS_PRO_LICENSE
value: cpln://secret/{{APP_SECRETS}}.REACT_ON_RAILS_PRO_LICENSE
# Part of standard configuration
staticPlacement:
locationLinks:
Expand Down
17 changes: 14 additions & 3 deletions .controlplane/templates/org.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,25 @@
# other sensitive information that is shared across multiple apps
# in the same organization.

# This is how you apply this once (not during CI)
# cpl apply-template secrets -a qa-react-webpack-rails-tutorial --org shakacode-open-source-examples-staging
# The qa-* dictionary is bootstrapped via this template; prod and
# staging dictionaries are created manually with real values.

# Initial bootstrap (once, manually, not in CI):
# cpflow apply-template secrets -a qa-react-webpack-rails-tutorial --org shakacode-open-source-examples-staging
#
# Populate real values with `cpln apply -f <file>` or `cpln secret edit`.
# Do NOT re-apply this template after real values are set: it will
# overwrite them with the placeholders below.

kind: secret
name: {{APP_SECRETS}}
type: dictionary
data:
SOME_ENV: "123456"
# Both sides of the Rails/Node renderer handshake must match.
# Generate with `openssl rand -hex 32`.
RENDERER_PASSWORD: "replace-with-openssl-rand-hex-32"
# JWT from https://pro.reactonrails.com/; same token across envs.
REACT_ON_RAILS_PRO_LICENSE: "replace-with-pro-license-jwt"

---

Expand Down
11 changes: 8 additions & 3 deletions .controlplane/templates/rails.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,11 @@ spec:
# Inherit other ENV values from GVC
inheritEnv: true
image: {{APP_IMAGE_LINK}}
# 512 corresponds to a standard 1x dyno type
memory: 512Mi
# 1Gi (up from 512Mi) gives the single container enough headroom for
# Rails + the Pro Node renderer. Below the marketplace demo's 2Gi
# because this tutorial's Rails surface is smaller; capacityAI below
# adjusts upward if actual usage warrants it.
memory: 1Gi
ports:
- number: 3000
protocol: http
Expand All @@ -27,7 +30,9 @@ spec:
autoscaling:
# Max of 1 effectively disables autoscaling, so a like a Heroku dyno count of 1
maxScale: 1
capacityAI: false
# CapacityAI adjusts CPU/memory within the single replica based on observed
# usage, so the 1Gi/300m baseline can grow if Rails + renderer need more.
capacityAI: true
firewallConfig:
external:
# Default to allow public access to Rails server
Expand Down
22 changes: 22 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# React on Rails Pro license (JWT token from https://pro.reactonrails.com/).
# Required in production; optional in development/test.
REACT_ON_RAILS_PRO_LICENSE=

# Shared secret between Rails and the Node renderer. Must match on both sides.
# Dev/test default to `local-dev-renderer-password` if unset; production must
# set this explicitly (Pro raises at boot otherwise).
RENDERER_PASSWORD=

# Node renderer endpoint. Defaults to http://localhost:3800.
# RENDERER_URL=http://localhost:3800

# Port the Node renderer listens on. Defaults to 3800.
# RENDERER_PORT=3800

# Log verbosity for the Node renderer (debug, info, warn, error).
# Defaults to info.
# RENDERER_LOG_LEVEL=info

# Number of renderer worker processes. `0` is single-process mode, useful
# for local debugging. Defaults to 3; the app's CI workflow caps to 2.
# RENDERER_WORKERS_COUNT=3
22 changes: 22 additions & 0 deletions .github/workflows/rspec_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ jobs:
DRIVER: selenium_chrome
CHROME_BIN: /usr/bin/google-chrome
USE_COVERALLS: true
# Must match config.renderer_password in config/initializers/react_on_rails_pro.rb.
# Setting explicitly avoids silent drift if the two-sided defaults ever diverge.
RENDERER_PASSWORD: local-dev-renderer-password

steps:
- name: Install Chrome
Expand Down Expand Up @@ -82,6 +85,25 @@ jobs:
- name: Build shakapacker chunks
run: NODE_ENV=development bundle exec bin/shakapacker

- name: Start Node renderer for SSR
run: |
node renderer/node-renderer.js &
RENDERER_PID=$!
echo "Waiting for Node renderer (PID $RENDERER_PID) on port 3800..."
for i in $(seq 1 30); do
if ! kill -0 $RENDERER_PID 2>/dev/null; then
echo "Node renderer process exited unexpectedly (see output above)."
exit 1
fi
if nc -z localhost 3800 2>/dev/null; then
Comment thread
ihabadham marked this conversation as resolved.
echo "Node renderer is ready"
exit 0
fi
sleep 1
done
echo "Node renderer failed to start within 30 seconds (see output above)."
exit 1

- name: Run rspec with xvfb
uses: coactions/setup-xvfb@v1
Comment thread
ihabadham marked this conversation as resolved.
with:
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ client/app/bundles/comments/rescript/**/*.bs.js
# Using React on Rails default directory
/ssr-generated/

# Pro Node renderer bundle cache
/renderer/.node-renderer-bundles/

# Generated React on Rails packs
**/generated/**

Expand Down
4 changes: 2 additions & 2 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ git_source(:github) { |repo| "https://github.com/#{repo}.git" }

ruby "3.4.6"

gem "react_on_rails", "16.6.0.rc.0"
gem "shakapacker", "10.0.0.rc.0"
gem "react_on_rails_pro", "16.6.0"
gem "shakapacker", "10.0.0"

# Bundle edge Rails instead: gem "rails", github: "rails/rails"
gem "rails", "~> 8.1.2"
Expand Down
40 changes: 36 additions & 4 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,12 @@ GEM
addressable (2.8.7)
public_suffix (>= 2.0.2, < 7.0)
ast (2.4.3)
async (2.39.0)
console (~> 1.29)
fiber-annotation
io-event (~> 1.11)
metrics (~> 0.12)
traces (~> 0.18)
autoprefixer-rails (10.4.16.0)
execjs (~> 2)
awesome_print (1.9.2)
Expand Down Expand Up @@ -115,6 +121,10 @@ GEM
coffee-script-source (1.12.2)
concurrent-ruby (1.3.6)
connection_pool (3.0.2)
console (1.34.3)
fiber-annotation
fiber-local (~> 1.1)
json
coveralls_reborn (0.25.0)
simplecov (>= 0.18.1, < 0.22.0)
term-ansicolor (~> 1.6)
Expand Down Expand Up @@ -146,16 +156,24 @@ GEM
railties (>= 5.0.0)
ffi (1.17.2-arm64-darwin)
ffi (1.17.2-x86_64-linux-gnu)
fiber-annotation (0.2.0)
fiber-local (1.1.0)
fiber-storage
fiber-storage (1.0.1)
foreman (0.88.1)
generator_spec (0.10.0)
activesupport (>= 3.0.0)
railties (>= 3.0.0)
globalid (1.3.0)
activesupport (>= 6.1)
http-2 (1.1.3)
httpx (1.7.6)
http-2 (>= 1.1.3)
i18n (1.14.8)
concurrent-ruby (~> 1.0)
interception (0.5)
io-console (0.8.2)
io-event (1.15.1)
irb (1.17.0)
pp (>= 0.6.0)
prism (>= 1.3.0)
Expand All @@ -165,6 +183,8 @@ GEM
actionview (>= 5.0.0)
activesupport (>= 5.0.0)
json (2.19.1)
jwt (2.10.2)
Comment thread
ihabadham marked this conversation as resolved.
base64
language_server-protocol (3.17.0.5)
launchy (3.0.1)
addressable (~> 2.8)
Expand All @@ -182,6 +202,7 @@ GEM
marcel (1.1.0)
matrix (0.4.2)
method_source (1.1.0)
metrics (0.15.0)
mini_mime (1.1.5)
minitest (6.0.2)
drb (~> 2.0)
Expand Down Expand Up @@ -296,13 +317,23 @@ GEM
erb
psych (>= 4.0.0)
tsort
react_on_rails (16.6.0.rc.0)
react_on_rails (16.6.0)
addressable
connection_pool
execjs (~> 2.5)
rails (>= 5.2)
rainbow (~> 3.0)
shakapacker (>= 6.0)
react_on_rails_pro (16.6.0)
Comment thread
ihabadham marked this conversation as resolved.
addressable
async (>= 2.29)
connection_pool
execjs (~> 2.9)
http-2 (>= 1.1.1)
httpx (~> 1.5)
jwt (~> 2.7)
rainbow
react_on_rails (= 16.6.0)
redcarpet (3.6.0)
redis (5.3.0)
redis-client (>= 0.22.0)
Expand Down Expand Up @@ -387,7 +418,7 @@ GEM
websocket (~> 1.0)
semantic_range (3.1.1)
sexp_processor (4.17.1)
shakapacker (10.0.0.rc.0)
shakapacker (10.0.0)
activesupport (>= 5.2)
package_json
rack-proxy (>= 0.6.1)
Expand Down Expand Up @@ -425,6 +456,7 @@ GEM
tins (1.33.0)
bigdecimal
sync
traces (0.18.2)
tsort (0.2.0)
turbo-rails (2.0.11)
actionpack (>= 6.0.0)
Expand Down Expand Up @@ -486,7 +518,7 @@ DEPENDENCIES
rails-html-sanitizer
rails_best_practices
rainbow
react_on_rails (= 16.6.0.rc.0)
react_on_rails_pro (= 16.6.0)
redcarpet
redis (~> 5.0)
rspec-rails (~> 6.0.0)
Expand All @@ -498,7 +530,7 @@ DEPENDENCIES
scss_lint
sdoc
selenium-webdriver (~> 4)
shakapacker (= 10.0.0.rc.0)
shakapacker (= 10.0.0)
spring
spring-commands-rspec
stimulus-rails (~> 1.3)
Expand Down
9 changes: 6 additions & 3 deletions Procfile.dev
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@
# You can run these commands in separate shells
#
# Note: bin/dev runs precompile tasks (rescript + locale) BEFORE starting these processes.
# This ensures all generated files exist before Rspack starts watching.
# This ensures all generated files exist before webpack starts watching.
#
# ReScript watch mode (no clean - bin/dev already did the clean build)
rescript: yarn res:watch
# redis: redis-server # Run Redis as a system service instead (brew services start redis)
rails: bundle exec thrust bin/rails server -p 3000
# Client Rspack dev server with HMR
# Client webpack dev server with HMR
wp-client: RAILS_ENV=development NODE_ENV=development bin/shakapacker-dev-server
# Server Rspack watcher for SSR bundle
# Server webpack watcher for SSR bundle
wp-server: SERVER_BUNDLE_ONLY=yes bin/shakapacker --watch
# RSC webpack watcher for React Server Components bundle
wp-rsc: RSC_BUNDLE_ONLY=yes bin/shakapacker --watch
node-renderer: NODE_ENV=development node renderer/node-renderer.js
9 changes: 8 additions & 1 deletion app/controllers/pages_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

class PagesController < ApplicationController
include ReactOnRails::Controller
before_action :set_comments
include ReactOnRailsPro::Stream
before_action :set_comments, only: %i[index no_router]

Comment thread
ihabadham marked this conversation as resolved.
def index
# NOTE: The below notes apply if you want to set the value of the props in the controller, as
Expand Down Expand Up @@ -38,6 +39,12 @@ def simple; end

def rescript; end

def server_components
@server_components_comments = Comment.order(id: :desc).limit(10)
.as_json(only: %i[id author text created_at updated_at])
stream_view_containing_react_components(template: "/pages/server_components")
end

private

def set_comments
Expand Down
5 changes: 5 additions & 0 deletions app/views/pages/server_components.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<%= stream_react_component("ServerComponentsPage",
props: { comments: @server_components_comments },
prerender: true,
auto_load_bundle: true,
trace: Rails.env.development?) %>
Loading
Loading