Skip to content

Commit

Permalink
Update the install generator to add Webpacker configuration (#1404)
Browse files Browse the repository at this point in the history
* Default install includes sample configuration including SSR with HMR
* Supports Rails 7
  • Loading branch information
gscarv13 authored Dec 24, 2021
1 parent 3fe52bf commit 64f722f
Show file tree
Hide file tree
Showing 52 changed files with 3,167 additions and 4,012 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ Changes since last non-beta release.

*Please add entries here for your pull requests that are not yet released.*

#### Added
- Added webpack configuration files as part of the generator and updated webpacker to version 6 [PR 1404](https://github.com/shakacode/react_on_rails/pull/1404) by [gscarv13](https://github.com/gscarv13).

### [12.4.0] - 2021-09-22
#### Added
- ScoutAPM tracing support for server rendering [PR 1379](https://github.com/shakacode/react_on_rails/pull/1379) by [justin808](https://github.com/justin808).
Expand Down
3 changes: 2 additions & 1 deletion Gemfile.development_dependencies
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# frozen_string_literal: true

gem "webpacker"
gem "webpacker", "6.0.0.rc.6"
gem "bootsnap", require: false
gem "rails"
gem "sqlite3"
Expand All @@ -20,6 +20,7 @@ gem "sdoc", group: :doc
gem "sprockets"

gem "amazing_print"

gem "mini_racer"

group :development, :test do
Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ See [Rails/Webpacker React Integration Options](https://www.shakacode.com/react-

See the [react-webpack-rails-tutorial](https://github.com/shakacode/react-webpack-rails-tutorial) for an example of a live implementation and code.

## Online demo

A deployed version of the project `spec/dummy` which demonstrates several uses of `react_on_rails` is available on heroku [through this link](https://ror-spec-dummy.herokuapp.com/)

## ShakaCode Forum Premium Content
_Requires creating a free account._

Expand Down
32 changes: 18 additions & 14 deletions docs/guides/tutorial.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

-----

*Updated for Ruby 2.7.1, Rails 6.0.3.1, and React on Rails v12.0.0*
*Updated for Ruby 2.7.1, Rails 6.0.3.1, React on Rails v12.5.0, and Webpacker v6*

This tutorial guides you through setting up a new or existing Rails app with **React on Rails**, demonstrating Rails + React + Redux + Server Rendering.

Expand Down Expand Up @@ -42,7 +42,7 @@ gem install foreman # download and install Foreman
```

## Create a new Ruby on Rails App
Then we need to create a fresh Rails application with webpacker react support as following.
Then we need to create a fresh Rails application as following.

First be sure to run `rails -v` and check you are using Rails 5.1.3 or above. If you are using an older version of Rails, you'll need to install webpacker with react per the instructions [here](https://github.com/rails/webpacker).

Expand All @@ -51,10 +51,9 @@ cd <directory where you want to create your new Rails app>
# Any name you like for the rails app
# Skip javascript so will add that next and get the current version
rails new --skip-sprockets -J --skip-turbolinks test-react-on-rails-v12-no-sprockets
rails new --skip-sprockets --skip-turbolinks -J test-react-on-rails
cd test-react-on-rails
bundle
```

## Add the webpacker and react_on_rails gems
Expand All @@ -63,22 +62,21 @@ of both the gem and npm package. In other words, don't use the `^` or `~` in the
_Use the latest version for react_on_rails._

```
gem 'react_on_rails', '12.0.4' # prefer exact gem version to match npm version
gem 'react_on_rails', '12.5.0' # prefer exact gem version to match npm version
```

Note: The latest released React On Rails version is considered stable. Please use the latest
version to ensure you get all the security patches and the best support.

```bash
bundle add webpacker
bundle add react_on_rails --version=12.0.4 --strict
bundle add webpacker --git=https://github.com/rails/webpacker.git
bundle add react_on_rails --version=12.5.0 --strict
```

## Run the webpacker generator

```
```terminal
bundle exec rails webpacker:install
bundle exec rails webpacker:install:react
```

Let's commit everything before installing React on Rails.
Expand All @@ -97,20 +95,24 @@ Install React on Rails: `rails generate react_on_rails:install`. You need to fir
Note, using `redux` is no longer recommended as the basic installer uses React Hooks.
If you want the redux install: `rails generate react_on_rails:install --redux`

The generator will add `mini_racer`'s latest version. If you're using linux & encounter issues installing `libv8`, here's [a common solution](https://github.com/rubyjs/mini_racer/issues/218).

```
rails generate react_on_rails:install
```

Then run server with a static client bundle. Static means that the bundle is saved in your
public/webpack/packs directory.
Enter `a` to replace all configuration files required by the project.

Then run the server with one of the following options:

## Running with HMR
```
foreman start -f Procfile.dev
```

## To run with the webpack-dev-server:
## Running without HMR, statically creating the bundles
```
foreman start -f Procfile.dev-hmr
foreman start -f Procfile.dev-static
```

Visit [http://localhost:3000/hello_world](http://localhost:3000/hello_world) and see your **React On Rails** app running!
Expand Down Expand Up @@ -250,6 +252,8 @@ heroku open

and you will see your live app and you can share this URL with your friends. Congrats!

A deployed version of the project `spec/dummy` which demonstrates several uses of `react_on_rails` is available on heroku [through this link](https://ror-spec-dummy.herokuapp.com/)

## Turning on Server Rendering

You can turn on server rendering by simply changing the `prerender` option to `true`:
Expand Down Expand Up @@ -312,7 +316,7 @@ mv app/javascript client
## Using HMR with the rails/webpacker setup
Start the app using `foreman start -f Procfile.dev-hmr`.
Start the app using `foreman start -f Procfile.dev`.

When you change a JSX file and save, the browser will automatically refresh!

Expand Down
49 changes: 46 additions & 3 deletions lib/generators/react_on_rails/base_generator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,40 @@ def copy_base_files
app/views/layouts/hello_world.html.erb
config/initializers/react_on_rails.rb
Procfile.dev
Procfile.dev-hmr]
Procfile.dev-static]
base_files.each { |file| copy_file("#{base_path}#{file}", file) }
end

def copy_js_bundle_files
base_path = "base/base/"
base_files = %w[app/javascript/packs/server-bundle.js
app/javascript/bundles/HelloWorld/components/HelloWorldServer.js
app/javascript/bundles/HelloWorld/components/HelloWorld.module.css]
base_files.each { |file| copy_file("#{base_path}#{file}", file) }
end

def copy_webpack_config
puts "Adding Webpack config"
base_path = "base/base"
base_files = %w[babel.config.js
config/webpack/clientWebpackConfig.js
config/webpack/commonWebpackConfig.js
config/webpack/development.js
config/webpack/production.js
config/webpack/serverWebpackConfig.js
config/webpack/webpackConfig.js]
config = {
message: "// The source code including full typescript support is available at:"
}
base_files.each do |file|
template("#{base_path}/#{file}.tt", file, config)
end
end

def copy_webpacker_config
puts "Adding Webpacker v6 config"
base_path = "base/base/"
base_files = %w[config/webpacker.yml]
base_files.each { |file| copy_file("#{base_path}#{file}", file) }
end

Expand All @@ -51,6 +84,16 @@ def add_yarn_dependencies
puts "Adding the lastest react-on-rails NPM module. Double check this is correct in package.json"
run "yarn add react-on-rails --exact"
end

puts "Adding React dependencies"
run "yarn add react react-dom @babel/preset-react prop-types babel-plugin-transform-react-remove-prop-types \
babel-plugin-macros"

puts "Adding CSS handlers"
run "yarn add css-loader css-minimizer-webpack-plugin mini-css-extract-plugin style-loader"

puts "Adding dev dependencies"
run "yarn add -D @pmmmwh/react-refresh-webpack-plugin react-refresh"
end

def append_to_spec_rails_helper
Expand Down Expand Up @@ -111,10 +154,10 @@ def self.helpful_message
- Alternately, you may turn off compile in config/webpacker.yml and run the foreman
command to start the rails server and run webpack in watch mode.
foreman start -f Procfile.dev
foreman start -f Procfile.dev-static
- To turn on HMR, edit config/webpacker.yml and set HMR to true. Restart the rails server
and bin/webpack-dev-server. Or use Procfile.dev-hmr.
and bin/webpack-dev-server. Or use Procfile.dev.
- To server render, change this line app/views/hello_world/index.html.erb to
`prerender: true` to see server rendering (right click on page and select "view source").
Expand Down
4 changes: 4 additions & 0 deletions lib/generators/react_on_rails/generator_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,8 @@ def copy_file_and_missing_parent_directories(source_file, destination_file = nil
empty_directory(parent_directories) unless dest_dir_exists?(parent_directories)
copy_file source_file, destination_file
end

def add_documentation_reference(message, source)
"#{message} \n#{source}"
end
end
4 changes: 3 additions & 1 deletion lib/generators/react_on_rails/templates/.eslintrc
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
---
extends: eslint-config-shakacode
extends:
- eslint-config-shakacode
- prettier

plugins:
- react
Expand Down
12 changes: 4 additions & 8 deletions lib/generators/react_on_rails/templates/base/base/Procfile.dev
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
# Procfile for development using HMR
# You can run these commands in separate shells
web: rails s -p 3000

# Next line runs a watch process with webpack to compile the changed files.
# When making frequent changes to client side assets, you will prefer building webpack assets
# upon saving rather than when you refresh your browser page.
# Note, if using React on Rails localization you will need to run
# `bundle exec rake react_on_rails:locale` before you run bin/webpack
client: sh -c 'rm -rf public/packs/* || true && bin/webpack -w'
rails: bundle exec rails s -p 3000
wp-client: HMR=true bin/webpack-dev-server
wp-server: HMR=true SERVER_BUNDLE_ONLY=yes bin/webpack --watch
26 changes: 0 additions & 26 deletions lib/generators/react_on_rails/templates/base/base/Procfile.dev-hmr

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# You can run these commands in separate shells
web: rails s -p 3000

# Next line runs a watch process with webpack to compile the changed files.
# When making frequent changes to client side assets, you will prefer building webpack assets
# upon saving rather than when you refresh your browser page.
# Note, if using React on Rails localization you will need to run
# `bundle exec rake react_on_rails:locale` before you run bin/webpack
webpack: sh -c 'rm -rf public/packs/* || true && bin/webpack -w'
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import PropTypes from 'prop-types';
import React, { useState } from 'react';
import style from './HelloWorld.module.css';

const HelloWorld = (props) => {
const [name, setName] = useState(props.name);
Expand All @@ -9,7 +10,7 @@ const HelloWorld = (props) => {
<h3>Hello, {name}!</h3>
<hr />
<form>
<label htmlFor="name">
<label className={style.bright} htmlFor="name">
Say hello to:
<input id="name" type="text" value={name} onChange={(e) => setName(e.target.value)} />
</label>
Expand Down
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';
// This could be specialized for server rendering
// For example, if using React-Router, we'd have the SSR setup here.

export default HelloWorld;
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import ReactOnRails from 'react-on-rails';

import HelloWorld from '../bundles/HelloWorld/components/HelloWorldServer';

// This is how react_on_rails can see the HelloWorld in the browser.
ReactOnRails.register({
HelloWorld,
});
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<title>ReactOnRailsWithWebpacker</title>
<%= csrf_meta_tags %>
<%= javascript_pack_tag 'hello-world-bundle' %>
<%= stylesheet_pack_tag 'hello-world-bundle' %>
</head>

<body>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<%= add_documentation_reference(config[:message], "// https://github.com/shakacode/react_on_rails_tutorial_with_ssr_and_hmr_fast_refresh/blob/master/babel.config.js") %>

const defaultConfigFunc = require('@rails/webpacker/package/babel/preset.js');

module.exports = function (api) {
const resultConfig = defaultConfigFunc(api);

const changesOnDefault = {
plugins: [process.env.WEBPACK_SERVE && 'react-refresh/babel'].filter(Boolean),
};

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

return resultConfig;
};
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,5 @@
# different. You should have ONE server bundle which can create all of your server rendered
# React components.
#
config.server_bundle_js_file = "hello-world-bundle.js"
config.server_bundle_js_file = "server-bundle.js"
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<%= add_documentation_reference(config[:message], "// https://github.com/shakacode/react_on_rails_tutorial_with_ssr_and_hmr_fast_refresh/blob/master/config/webpack/clientWebpackConfig.js") %>

const commonWebpackConfig = require('./commonWebpackConfig');

const configureClient = () => {
const clientConfig = commonWebpackConfig();

// server-bundle is special and should ONLY be built by the serverConfig
// In case this entry is not deleted, a very strange "window" not found
// error shows referring to window["webpackJsonp"]. That is because the
// client config is going to try to load chunks.
delete clientConfig.entry['server-bundle'];

return clientConfig;
};

module.exports = configureClient;
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<%= add_documentation_reference(config[:message], "// https://github.com/shakacode/react_on_rails_tutorial_with_ssr_and_hmr_fast_refresh/blob/master/config/webpack/commonWebpackConfig.js") %>

// Common configuration applying to client and server configuration
const { webpackConfig: baseClientWebpackConfig, merge } = require('@rails/webpacker');

const commonOptions = {
resolve: {
extensions: ['.css', '.ts', '.tsx'],
},
};

// Copy the object using merge b/c the baseClientWebpackConfig and commonOptions are mutable globals
const commonWebpackConfig = () => merge({}, baseClientWebpackConfig, commonOptions);

module.exports = commonWebpackConfig;
Loading

0 comments on commit 64f722f

Please sign in to comment.