Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
justin808 committed May 6, 2020
1 parent 85c9cb4 commit abf6856
Show file tree
Hide file tree
Showing 6 changed files with 138 additions and 36 deletions.
17 changes: 17 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,23 @@ for details.
* Removal of config.symlink_non_digested_assets_regex as it's no longer needed with rails/webpacker.
If any business needs this, we can move the code to a separate gem.

#### Changed
- Added configuration option `same_bundle_for_client_and_server` with default `false` because

1. Production applications would typically have a server bundle that differs from the client bundle
2. This change only affects trying to use HMR with react_on_rails with rails/webpacker.

The previous behavior was to always go to the webpack-dev-server for the server bundle if the
webpack-dev-server was running _and_ the server bundle was found in the `manifest.json`. Because
the `assets:clean` enhancement of rails/webpacker deletes any files that are not in the `manifest.json`,
we recommend fingerprinting the server bundle and adding it to the manifest.

If you are using the **same bundle for client and server rendering**, then set this configuration option
to `true`. By [justin808](https://github.com/justin808/1240).

#### Improved
- Removed unnecessary restriction to keep the server bundle in the same directory with the client bundles. Rails/webpacker 4 has an advanced cleanup that will remove any files in the directory of other webpack files. Removing this restriction allows the server bundle to be created in a sibling directory. Note, the rails/webpacker cleanup will remove any files in child directories. By [justin808](https://github.com/justin808/1240).

### [11.3.0] - 2019-05-24
#### Added
- Added method for retrieving any option from `render_options` [PR 1213](https://github.com/shakacode/react_on_rails/pull/1213)
Expand Down
13 changes: 10 additions & 3 deletions docs/basics/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,9 +105,11 @@ ReactOnRails.configure do |config|
# The default is `%w( manifest.json )` as will be sufficient for most webpacker builds.
# However, if you are generated a server bundle that is NOT hashed (present in manifest.json),
# then include the file in this list like this:
#
config.webpack_generated_files = %w( server-bundle.js manifest.json )

# Note, be sure NOT to include your server-bundle.js if it is hashed, or else React on Rails will
# think the server-bundle.js is missing every time for test runs.
# In the future, we'll require the server-bundle.js to be hashed

# You can optionally add values to your rails_context. See example below for RenderingExtension
# config.rendering_extension = RenderingExtension

Expand All @@ -126,7 +128,12 @@ ReactOnRails.configure do |config|
# If you are hashing this file (supposing you are using the same file for client rendering), then
# you should include a name that matches your bundle name in your webpack config.
config.server_bundle_js_file = "server-bundle.js"


# This value only affects using the webpack-dev-server
# If you wanted to use the same bundle for client and server, you'd set this to `true`.
# Normally, you have different bundles for client and server, thus, the default is false.
config.same_bundle_for_client_and_server = false

# If set to true, this forces Rails to reload the server bundle if it is modified
# Default value is Rails.env.development?
#
Expand Down
71 changes: 47 additions & 24 deletions docs/tutorial.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@


Start work here and work through the tutorial and maybe add a simple configuration for having a different server
rendering file.



# React on Rails Basic Tutorial

This tutorial guides you through setting up a new or existing Rails app with **React on Rails**, demonstrating Rails + React + Redux + Server Rendering. It is updated to 11.2.1.
Expand All @@ -17,9 +24,9 @@ By the time you read this, the latest may have changed. Be sure to check the ver

_Note: some of the screen images below show the "npm" command. react_on_rails 6.6.0 and greater uses `yarn`._

## Setting up the environment
## Setting up your environment

Trying out **React on Rails** is super easy, so long as you have the basic prerequisites. This includes the basics for Rails 5.x and node version 6+. I recommend `rvm` and `nvm` to install Ruby and Node, and [brew](https://brew.sh/) to install [yarn](https://yarnpkg.com/en/docs/install#mac-tab). Rails can be installed as an ordinary gem.
Trying out **React on Rails** is super easy, so long as you have the basic prerequisites. This includes the basics for Rails 6.x and node version 13+. I recommend `rvm` and `nvm` to install Ruby and Node, and [brew](https://brew.sh/) to install [yarn](https://yarnpkg.com/en/docs/install#mac-tab). Rails can be installed as an ordinary gem.

```
nvm install node # download and install latest stable Node
Expand All @@ -28,8 +35,8 @@ nvm list # check
brew install yarn # you can use other installer if desired
11\.\d+\.\d+
rvm install 2.5.0 # download and install latest stable Ruby (update to exact version)
rvm use 2.5.0 --default # use it and make it default
rvm install 2.6 # download and install latest stable Ruby (update to exact version)
rvm use 2.6 --default # use it and make it default
rvm list # check
gem install rails # download and install latest stable Rails
Expand All @@ -44,13 +51,13 @@ First be sure to run `rails -v` and check you are using Rails 5.1.3 or above. If
cd <directory where you want to create your new Rails app>
# any name you like for the rails app
rails new test-react-on-rails --webpack=react
rails new test-react-on-rails --webpack=react --skip-sprockets
cd test-react-on-rails
bundle
```

Note: if you are installing React On Rails in an existing app or an app that uses **Rails pre 5.1.3** (*not for Rails > 5.2*), you will need to run these two commands as well:
Note: if you are adding React On Rails to an existing app you will instead to run these two commands as well:

```
bundle exec rails webpacker:install
Expand All @@ -60,7 +67,7 @@ bundle exec rails webpacker:install:react
Add the **React On Rails** gem to your `Gemfile`:

```
gem 'react_on_rails', '11.2.2' # prefer exact gem version to match npm version
gem 'react_on_rails', '12.0.0' # prefer exact gem version to match npm version
```

Note: 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.
Expand All @@ -81,7 +88,6 @@ Install React on Rails: `rails generate react_on_rails:install` or `rails genera

```
rails generate react_on_rails:install
bundle && yarn
```

Then run server with static client side files:
Expand All @@ -96,27 +102,34 @@ foreman start -f Procfile.dev-server
```

Visit [http://localhost:3000/hello_world](http://localhost:3000/hello_world) and see your **React On Rails** app running!
Note, foreman defaults to PORT 5000 unless you set the value of PORT in your environment or in the Procfile.

## Using a pre-release of rails/webpacker
Until `rails/webpacker` v4 ships, or if you ever want to try out the master branch, you can modify the React on Rails tutorial instructions slightly. You can see the sequence of commits here. To summarize:
*Note, foreman may default to PORT 5000 unless you set the value of PORT in your environment or in the Procfile.*

# HMR vs. React Hot Reloading

First, check that the `hmr` option is `true` in your `config/webpacker.yml` file.

The basic setup will have HMR working with the default webpacker setup. However, the basic will cause a full page refresh each time you save a file.

















**Don't run `rails new` with the `--webpack=react` option**. Instead, add the webpacker gem to the Gemfile such that it points to master, like this if `11.2.1` is the version you want.

```ruby
gem 'webpacker', github: "rails/webpacker"
gem 'react_on_rails', '11.2.1' # always use exact version
```

Then run these commands:

```sh
bundle exec rails webpacker:install
yarn add "rails/webpacker" # because the installer has a bug that puts in an invalid version in your package.json.
bundle exec rails webpacker:install:react
yarn add --dev webpack-dev-server
run rails generate react_on_rails:install && bundle && yarn
```

### Custom IP & PORT setup (Cloud9 example)

Expand Down Expand Up @@ -265,6 +278,16 @@ You can turn on server rendering by simply changing the `prerender` option to `t
<%= react_component("HelloWorld", props: @hello_world_props, prerender: true) %>
```

If you want to test this out with HMR, then you also need to add this line to your
`config/intializers/react_on_rails.rb`

```ruby
config.same_bundle_for_client_and_server = true
```

More likely, you will create a different build file for server rendering. However, if you want to
use the same file from the webpack-dev-server, you'll need to add that line.

Then push to Heroku:

```
Expand Down
13 changes: 9 additions & 4 deletions lib/react_on_rails/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ def self.configuration
server_render_method: nil,
build_test_command: "",
build_production_command: "",
random_dom_id: DEFAULT_RANDOM_DOM_ID
random_dom_id: DEFAULT_RANDOM_DOM_ID,
same_bundle_for_client_and_server: false
)
end

Expand All @@ -46,7 +47,9 @@ class Configuration
:webpack_generated_files, :rendering_extension, :build_test_command,
:build_production_command,
:i18n_dir, :i18n_yml_dir,
:server_render_method, :random_dom_id
:server_render_method,
:random_dom_id,
:same_bundle_for_client_and_server

def initialize(node_modules_location: nil, server_bundle_js_file: nil, prerender: nil,
replay_console: nil,
Expand All @@ -58,9 +61,9 @@ def initialize(node_modules_location: nil, server_bundle_js_file: nil, prerender
rendering_extension: nil, build_test_command: nil,
build_production_command: nil,
i18n_dir: nil, i18n_yml_dir: nil, random_dom_id: nil,
same_bundle_for_client_and_server: nil,
server_render_method: nil)
self.node_modules_location = node_modules_location.present? ? node_modules_location : Rails.root
self.server_bundle_js_file = server_bundle_js_file
self.generated_assets_dirs = generated_assets_dirs
self.generated_assets_dir = generated_assets_dir
self.build_test_command = build_test_command
Expand All @@ -82,6 +85,8 @@ def initialize(node_modules_location: nil, server_bundle_js_file: nil, prerender
self.skip_display_none = skip_display_none

# Server rendering:
self.server_bundle_js_file = server_bundle_js_file
self.same_bundle_for_client_and_server = same_bundle_for_client_and_server
self.server_renderer_pool_size = self.development_mode ? 1 : server_renderer_pool_size
self.server_renderer_timeout = server_renderer_timeout # seconds

Expand Down Expand Up @@ -195,7 +200,7 @@ def configure_generated_assets_dirs_deprecation
def ensure_webpack_generated_files_exists
return unless webpack_generated_files.empty?

files = ["hello-world-bundle.js"]
files = ["manifest.json"]
files << server_bundle_js_file if server_bundle_js_file.present?

self.webpack_generated_files = files
Expand Down
10 changes: 7 additions & 3 deletions lib/react_on_rails/webpacker_utils.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,19 @@ def self.dev_server_running?
Webpacker.dev_server.running?
end

# This returns either a URL for the webpack-dev-server or a file path
def self.bundle_js_uri_from_webpacker(bundle_name)
# This returns either a URL for the webpack-dev-server, non-server bundle or server bundle
# if using the same bundle for the client, and otherwise returns a file path.
def self.bundle_js_uri_from_webpacker(bundle_name, server_bundle: false)
# Note Webpacker 3.4.3 manifest lookup is inside of the public_output_path
# [2] (pry) ReactOnRails::WebpackerUtils: 0> Webpacker.manifest.lookup("app-bundle.js")
# "/webpack/development/app-bundle-c1d2b6ab73dffa7d9c0e.js"
# Next line will throw if the file or manifest does not exist
hashed_bundle_name = Webpacker.manifest.lookup!(bundle_name)

if Webpacker.dev_server.running?
is_server_bundle = bundle_name == ReactOnRails.configuration.server_bundle_js_file

if Webpacker.dev_server.running? && (!is_server_bundle ||
ReactOnRails.configuration.same_bundle_for_client_and_server)
"#{Webpacker.dev_server.protocol}://#{Webpacker.dev_server.host_with_port}#{hashed_bundle_name}"
else
File.expand_path(File.join("public", hashed_bundle_name)).to_s
Expand Down
50 changes: 48 additions & 2 deletions spec/react_on_rails/utils_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ module ReactOnRails
allow(Webpacker).to receive_message_chain("manifest.lookup!")
.with("webpack-bundle.js")
.and_return("/webpack/dev/webpack-bundle-0123456789abcdef.js")
allow(ReactOnRails).to receive_message_chain("configuration.server_bundle_js_file")
.and_return("server-bundle.js")
end

it { expect(subject).to eq("#{webpacker_public_output_path}/webpack-bundle-0123456789abcdef.js") }
Expand Down Expand Up @@ -125,17 +127,61 @@ module ReactOnRails
end
end

context "With Webpacker enabled and server file in the manifest", :webpacker do
context "With Webpacker enabled and server file in the manifest, used for client", :webpacker do
it "returns the correct path hashed server path" do
allow(ReactOnRails).to receive_message_chain("configuration.server_bundle_js_file")
.and_return("webpack-bundle.js")
allow(ReactOnRails).to receive_message_chain("configuration.same_bundle_for_client_and_server")
.and_return(true)
allow(Webpacker).to receive_message_chain("manifest.lookup!")
.with("webpack-bundle.js")
.and_return("webpack/development/webpack-bundle-123456.js")

path = Utils.server_bundle_js_file_path

expect(path).to end_with("public/webpack/development/webpack-bundle-123456.js")
expect(path).to start_with("/")
end
end

context "With Webpacker enabled and server file in the manifest, used for client, "\
" and webpack-dev-server running, and same file used for server and client", :webpacker do
it "returns the correct path hashed server path" do
allow(ReactOnRails).to receive_message_chain("configuration.server_bundle_js_file")
.and_return("webpack-bundle.js")
allow(ReactOnRails).to receive_message_chain("configuration.same_bundle_for_client_and_server")
.and_return(true)
allow(Webpacker).to receive_message_chain("dev_server.running?")
.and_return(true)
allow(Webpacker).to receive_message_chain("dev_server.protocol")
.and_return("http")
allow(Webpacker).to receive_message_chain("dev_server.host_with_port")
.and_return("localhost:3035")
allow(Webpacker).to receive_message_chain("manifest.lookup!")
.with("webpack-bundle.js")
.and_return("/webpack/development/webpack-bundle-123456.js")

path = Utils.server_bundle_js_file_path

expect(path).to eq("http://localhost:3035/webpack/development/webpack-bundle-123456.js")
end
end

context "With Webpacker enabled, dev-server running, and server file in the manifest, and "\
" separate client/server files", :webpacker do
it "returns the correct path hashed server path" do
allow(ReactOnRails).to receive_message_chain("configuration.server_bundle_js_file")
.and_return("server-bundle.js")
allow(ReactOnRails).to receive_message_chain("configuration.same_bundle_for_client_and_server")
.and_return(false)
allow(Webpacker).to receive_message_chain("manifest.lookup!")
.with("server-bundle.js")
.and_return("webpack/development/server-bundle-123456.js")
allow(Webpacker).to receive_message_chain("dev_server.running?")
.and_return(true)

path = Utils.server_bundle_js_file_path

expect(path).to end_with("/public/webpack/development/server-bundle-123456.js")
end
end
end
Expand Down

0 comments on commit abf6856

Please sign in to comment.