react_on_rails 12.0.0 → 12.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.eslintrc +0 -1
- data/.github/workflows/lint-js-and-ruby.yml +53 -0
- data/.github/workflows/main.yml +178 -0
- data/.github/workflows/package-js-tests.yml +35 -0
- data/.github/workflows/rspec-package-specs.yml +45 -0
- data/.rubocop.yml +18 -40
- data/.travis.yml +8 -4
- data/CHANGELOG.md +41 -20
- data/CONTRIBUTING.md +1 -1
- data/Gemfile +1 -33
- data/Gemfile.development_dependencies +54 -0
- data/NEWS.md +5 -0
- data/README.md +73 -65
- data/SUMMARY.md +1 -1
- data/docs/additional-reading/converting-from-custom-webpack-config-to-rails-webpacker-config.md +10 -0
- data/docs/additional-reading/react-router.md +1 -1
- data/docs/additional-reading/recommended-project-structure.md +69 -0
- data/docs/additional-reading/server-rendering-tips.md +4 -1
- data/docs/api/javascript-api.md +3 -3
- data/docs/api/redux-store-api.md +2 -2
- data/docs/api/view-helpers-api.md +4 -4
- data/docs/basics/client-vs-server-rendering.md +2 -0
- data/docs/basics/configuration.md +1 -1
- data/docs/basics/hmr-and-hot-reloading-with-the-webpack-dev-server.md +64 -9
- data/docs/basics/react-server-rendering.md +8 -5
- data/docs/basics/render-functions-and-railscontext.md +1 -1
- data/docs/basics/upgrading-react-on-rails.md +51 -14
- data/docs/basics/webpack-configuration.md +12 -18
- data/docs/misc/doctrine.md +0 -1
- data/docs/outdated/code-splitting.md +5 -5
- data/docs/tutorial.md +6 -0
- data/lib/generators/react_on_rails/base_generator.rb +8 -1
- data/lib/generators/react_on_rails/templates/dev_tests/spec/rails_helper.rb +4 -1
- data/lib/generators/react_on_rails/templates/dev_tests/spec/simplecov_helper.rb +1 -1
- data/lib/react_on_rails/configuration.rb +2 -0
- data/lib/react_on_rails/git_utils.rb +3 -3
- data/lib/react_on_rails/helper.rb +15 -14
- data/lib/react_on_rails/locales/to_js.rb +0 -4
- data/lib/react_on_rails/locales/to_json.rb +0 -4
- data/lib/react_on_rails/server_rendering_pool/ruby_embedded_java_script.rb +6 -6
- data/lib/react_on_rails/test_helper.rb +2 -0
- data/lib/react_on_rails/test_helper/webpack_assets_compiler.rb +1 -1
- data/lib/react_on_rails/utils.rb +8 -2
- data/lib/react_on_rails/version.rb +1 -1
- data/lib/react_on_rails/webpacker_utils.rb +4 -4
- data/lib/tasks/assets.rake +21 -9
- data/package.json +1 -1
- data/rakelib/docker.rake +0 -5
- data/rakelib/examples.rake +1 -1
- data/rakelib/lint.rake +4 -10
- data/rakelib/release.rake +9 -13
- data/rakelib/run_rspec.rake +9 -10
- data/rakelib/task_helpers.rb +2 -3
- data/react_on_rails.gemspec +3 -17
- metadata +15 -192
- data/docs/additional-reading/webpack-dev-server.md +0 -15
- data/docs/basics/recommended-project-structure.md +0 -77
- data/ruby-lint.yml +0 -25
@@ -13,7 +13,7 @@ Be sure to use mini_racer. See [issues/428](https://github.com/shakacode/react_o
|
|
13
13
|
- You can conditionally avoid running code that references document by either checking if `window`
|
14
14
|
is defined or using the "railsContext"
|
15
15
|
your top level react component. Since the passed in props Hash from the view helper applies to
|
16
|
-
client and server side code, the best way to do this is to use a
|
16
|
+
client and server side code, the best way to do this is to use a Render-Function.
|
17
17
|
- If you're serious about server rendering, it's worth the effort to have different entry points for client and server rendering. It's worth the extra complexity. The point is that you have separate files for top level client or server side, and you pass some extra option indicating that rendering is happening server side.
|
18
18
|
- You can enable Node.js server rendering via [React on Rails Pro](https://github.com/shakacode/react_on_rails/wiki).
|
19
19
|
|
@@ -22,6 +22,9 @@ Be sure to use mini_racer. See [issues/428](https://github.com/shakacode/react_o
|
|
22
22
|
1. First be sure your code works with server rendering disabled (`prerender: false`)
|
23
23
|
2. Be sure that `config.trace` is true. You will get the server invocation code that renders your component. If you're not using Webpacker, you will also get the whole file used to setup the JavaScript context.
|
24
24
|
|
25
|
+
## CSS
|
26
|
+
Server bundles must always have CSS Extracted
|
27
|
+
|
25
28
|
## setTimeout, setInterval, and clearTimeout
|
26
29
|
|
27
30
|
These methods are polyfilled for server rendering to be no-ops. We log calls to these when in `trace` mode. In the past, some libraries, namely babel-polyfill, did call setTimout.
|
data/docs/api/javascript-api.md
CHANGED
@@ -25,10 +25,10 @@ The best source of docs is the main [ReactOnRails.js](https://github.com/shakaco
|
|
25
25
|
/**
|
26
26
|
* Main entry point to using the react-on-rails npm package. This is how Rails will be able to
|
27
27
|
* find you components for rendering. Components get called with props, or you may use a
|
28
|
-
* "
|
28
|
+
* "Render-Function" to return a React component or an object with the following shape:
|
29
29
|
* { renderedHtml, redirectLocation, error }.
|
30
|
-
* For server rendering, if you wish to return multiple HTML strings from a
|
31
|
-
* you may return an Object from your
|
30
|
+
* For server rendering, if you wish to return multiple HTML strings from a Render-Function,
|
31
|
+
* you may return an Object from your Render-Function with a single top level property of
|
32
32
|
* renderedHtml. Inside this Object, place a key called componentHtml, along with any other
|
33
33
|
* needed keys. This is useful when you using side effects libraries like react helmet.
|
34
34
|
* Your Ruby code with get this Object as a Hash containing keys componentHtml and any other
|
data/docs/api/redux-store-api.md
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
# Redux Store
|
2
2
|
|
3
|
-
_This redux API is no longer recommended as it prevents dynamic code splitting for performance. Instead, you should use the standard react_component view helper passing in a "
|
3
|
+
_This redux API is no longer recommended as it prevents dynamic code splitting for performance. Instead, you should use the standard react_component view helper passing in a "Render-Function."_
|
4
4
|
|
5
5
|
You don't need to use the `redux_store` api to use redux. This api was setup to support multiple calls to `react_component` on one page that all talk to the same redux store.
|
6
6
|
|
7
|
-
If you are only rendering one react component on a page, as is typical to do a "Single Page App" in React, then you should _probably_ pass the props to your React component in a "
|
7
|
+
If you are only rendering one react component on a page, as is typical to do a "Single Page App" in React, then you should _probably_ pass the props to your React component in a "Render-Function."
|
8
8
|
|
9
9
|
Consider using the `redux_store` helper for the two following use cases:
|
10
10
|
|
@@ -22,7 +22,7 @@ Uncommonly used options:
|
|
22
22
|
id: nil,
|
23
23
|
```
|
24
24
|
|
25
|
-
- **component_name:** Can be a React component, created using an ES6 class or a
|
25
|
+
- **component_name:** Can be a React component, created using a React Function Component, an ES6 class or a Render-Function that returns a React component (or, only on the server side, an object with shape { redirectLocation, error, renderedHtml }), or a "renderer function" that manually renders a React component to the dom (client side only). Note, a "renderer function" is a special type of "Render-Function." A "renderer function" takes a 3rd param of a DOM ID.
|
26
26
|
All options except `props, id, html_options` will inherit from your `react_on_rails.rb` initializer, as described [here](../basics/configuration.md).
|
27
27
|
- **general options:**
|
28
28
|
- **props:** Ruby Hash which contains the properties to pass to the react object, or a JSON string. If you pass a string, we'll escape it for you.
|
@@ -45,7 +45,7 @@ adding meta-tags to a page. It is exactly like react_component except for the fo
|
|
45
45
|
|
46
46
|
1. `prerender: true` is automatically added to options, as this method doesn't make sense for
|
47
47
|
client only rendering.
|
48
|
-
2. Your JavaScript
|
48
|
+
2. Your JavaScript Render-Function for server rendering must return an Object rather than a React Component.
|
49
49
|
3. Your view code must expect an object and not a string.
|
50
50
|
|
51
51
|
Here is an example of ERB view code:
|
@@ -98,11 +98,11 @@ You can call `rails_context` or `rails_context(server_side: true|false)` from yo
|
|
98
98
|
|
99
99
|
### Renderer Functions (function that will call ReactDOM.render or ReactDOM.hydrate)
|
100
100
|
|
101
|
-
A "renderer function" is a
|
101
|
+
A "renderer function" is a Render-Function that accepts three arguments (rather than 2): `(props, railsContext, domNodeId) => { ... }`. Instead of returning a React component, a renderer is responsible for installing a callback that will call `ReactDOM.render` (in React 16+, `ReactDOM.hydrate`) to render a React component into the DOM. The "renderer function" is called at the same time the document ready event would instantate the React components into the DOM.
|
102
102
|
|
103
103
|
Why would you want to call `ReactDOM.hydrate` yourself? One possible use case is [code splitting](docs/outdated/code-splitting.md). In a nutshell, you don't want to load the React component on the DOM node yet. So you want to install some handler that will call `ReactDOM.hydrate` at a later time. In the case of code splitting with server rendering, the server rendered code has any async code loaded and used to server render. Thus, the client code must also fully load any asynch code before server rendering. Otherwise, the client code would first render partially, not matching the server rendering, and then a second later, the full code would render, resulting in an unpleasant flashing on the screen.
|
104
104
|
|
105
|
-
Renderer functions are not meant to be used on the server since there's no DOM on the server. Instead, use a
|
105
|
+
Renderer functions are not meant to be used on the server since there's no DOM on the server. Instead, use a Render-Function. Attempting to server render with a renderer function will throw an error.
|
106
106
|
|
107
107
|
------------
|
108
108
|
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# Client-Side Rendering vs. Server-Side Rendering
|
2
2
|
|
3
|
+
*See also [react-server-rendering.md](./react-server-rendering.md).*
|
4
|
+
|
3
5
|
In most cases, you should use the `prerender: false` (default behavior) with the provided helper method to render the React component from your Rails views. In some cases, such as when SEO is vital, or many users will not have JavaScript enabled, you can enable server-rendering by passing `prerender: true` to your helper, or you can simply change the default in `config/initializers/react_on_rails`.
|
4
6
|
|
5
7
|
Now the server will interpret your JavaScript. The default is to use [ExecJS](https://github.com/rails/execjs) and pass the resulting HTML to the client. We recommend using [mini_racer](https://github.com/discourse/mini_racer) as ExecJS's runtime.
|
@@ -215,7 +215,7 @@ Example of a RenderingExtension for custom values in the `rails_context`:
|
|
215
215
|
module RenderingExtension
|
216
216
|
|
217
217
|
# Return a Hash that contains custom values from the view context that will get merged with
|
218
|
-
# the standard rails_context values and passed to all calls to
|
218
|
+
# the standard rails_context values and passed to all calls to Render-Functions used by the
|
219
219
|
# react_component and redux_store view helpers
|
220
220
|
def self.custom_context(view_context)
|
221
221
|
{
|
@@ -8,22 +8,18 @@ The webpack-dev-server provides:
|
|
8
8
|
abruptly lose any tweaks within the Chrome development tools.
|
9
9
|
3. Optional hot-reloading. The older react-hot-loader has been deprecated in
|
10
10
|
favor of [fast-refresh](https://reactnative.dev/docs/fast-refresh).
|
11
|
-
For use with webpack, see [react-refresh-webpack-plugin](https://github.com/pmmmwh/react-refresh-webpack-plugin).
|
11
|
+
For use with webpack, see **Client Side rendering and HMR using react-refresh-webpack-plugin** section bellow or visit [react-refresh-webpack-plugin](https://github.com/pmmmwh/react-refresh-webpack-plugin) for additional details.
|
12
12
|
|
13
13
|
If you are ***not*** using server-side rendering (***not*** using `prerender: true`),
|
14
14
|
then you can follow all the regular docs for using the `bin/webpack-dev-server`
|
15
15
|
during development.
|
16
16
|
|
17
|
-
|
18
17
|
# Server Side Rendering with the Default rails/webpacker bin/webpack-dev-server
|
19
18
|
|
20
19
|
If you are using server-side rendering, then you have a couple options. The
|
21
20
|
recommended technique is to have a different webpack configuration for server
|
22
21
|
rendering.
|
23
22
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
23
|
## If you use the same Webpack setup for your server and client bundles
|
28
24
|
If you do use the webpack-dev-server for prerendering, be sure to set the
|
29
25
|
`config/initializers/react_on_rails.rb` setting of
|
@@ -43,7 +39,66 @@ If you don't configure these two to false, you'll see errors like:
|
|
43
39
|
* "ReferenceError: window is not defined" (if hmr is true)
|
44
40
|
* "TypeError: Cannot read property 'prototype' of undefined" (if inline is true)
|
45
41
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
42
|
+
# Client Side rendering with HMR using react-refresh-webpack-plugin
|
43
|
+
## Basic installation
|
44
|
+
To enable HMR functionality you have to use `./bin/webpack-dev-server`
|
45
|
+
1. In `config/webpacker.yml` set **hmr** and **inline** `dev_server` properties to true.
|
46
|
+
```
|
47
|
+
dev_server:
|
48
|
+
https: false
|
49
|
+
host: localhost
|
50
|
+
port: 3035
|
51
|
+
public: localhost:3035
|
52
|
+
hmr: true
|
53
|
+
# Inline should be set to true if using HMR
|
54
|
+
inline: true
|
55
|
+
```
|
56
|
+
|
57
|
+
2. Add react refresh packages:
|
58
|
+
` yarn add @pmmmwh/react-refresh-webpack-plugin react-refresh -D`
|
59
|
+
|
60
|
+
3. HMR is for use with the webpack-dev-server, so we only add this for the webpack-dev-server.
|
61
|
+
```
|
62
|
+
const { devServer } = require('@rails/webpacker')
|
63
|
+
|
64
|
+
const isWebpackDevServer = process.env.WEBPACK_DEV_SERVER
|
65
|
+
|
66
|
+
//plugins
|
67
|
+
if (isWebpackDevServer) {
|
68
|
+
environment.plugins.append(
|
69
|
+
'ReactRefreshWebpackPlugin',
|
70
|
+
new ReactRefreshWebpackPlugin({
|
71
|
+
overlay: {
|
72
|
+
sockPort: devServer.port
|
73
|
+
}
|
74
|
+
})
|
75
|
+
)
|
76
|
+
}
|
77
|
+
```
|
78
|
+
We added overlay.sockedPort option in `ReactRefreshWebpackPlugin` to match the webpack dev-server port specified in config/webpacker.yml. Thats way we make sockjs works properly and suppress error in browser console `GET http://localhost:[port]/sockjs-node/info?t=[xxxxxxxxxx] 404 (Not Found)`.
|
79
|
+
|
80
|
+
4. Add react-refresh plugin in `babel.config.js`
|
81
|
+
```
|
82
|
+
module.export = function(api) {
|
83
|
+
return {
|
84
|
+
plugins: [process.env.WEBPACK_DEV_SERVER && 'react-refresh/babel'].filter(Boolean)
|
85
|
+
}
|
86
|
+
}
|
87
|
+
```
|
88
|
+
That's it :).
|
89
|
+
Now Browser should reflect .js along with .css changes without reloading.
|
90
|
+
|
91
|
+
If by some reason plugin doesn't work you could revert changes and left only devServer hmr/inline to true affecting only css files.
|
92
|
+
|
93
|
+
These plugins are working and tested with
|
94
|
+
- babel 7
|
95
|
+
- webpacker 5
|
96
|
+
- bootstrap 4
|
97
|
+
- jest 26
|
98
|
+
- core-js 3
|
99
|
+
- node 12.10.0
|
100
|
+
- react-refresh-webpack-plugin@0.4.1
|
101
|
+
- react-refresh 0.8.3
|
102
|
+
- react_on_rails 11.1.4
|
103
|
+
|
104
|
+
configuration.
|
@@ -1,6 +1,9 @@
|
|
1
1
|
# React Server Rendering
|
2
2
|
|
3
|
-
See also [Client vs. Server Rendering](./client-vs-server-rendering.md)
|
3
|
+
See also [Client vs. Server Rendering](./client-vs-server-rendering.md).
|
4
|
+
|
5
|
+
## What is the easiest way to setup a webpack configuration for server-side-rendering?
|
6
|
+
See the example webpack setup here: [github.com/shakacode/react_on_rails_tutorial_with_ssr_and_hmr_fast_refresh](https://github.com/shakacode/react_on_rails_tutorial_with_ssr_and_hmr_fast_refresh).
|
4
7
|
|
5
8
|
## What is Server Rendering?
|
6
9
|
|
@@ -10,13 +13,13 @@ During the Rails rendering of HTML per a browser request, the Rails server will
|
|
10
13
|
|
11
14
|
The default JavaScript interpretter is [ExecJS](https://github.com/rails/execjs). If you want to maximize the perfomance of your server rendering, then you want to use React on Rails Pro which uses NodeJS to do the server rendering. See the [docs for React on Rails Pro](https://github.com/shakacode/react_on_rails/wiki).
|
12
15
|
|
13
|
-
See [this note](docs/outdated/how-react-on-rails-works.md#client-side-rendering-vs-server-side-rendering)
|
14
|
-
|
16
|
+
See [this note](docs/outdated/how-react-on-rails-works.md#client-side-rendering-vs-server-side-rendering).
|
15
17
|
|
16
18
|
## How do you do Server Rendering with React on Rails?
|
17
19
|
1. The `react_component` view helper method provides the `prerender:` option to switch on or off server rendering.
|
18
20
|
1. Configure your Webpack setup to create a different server bundle per your needs. While you may reuse the same bundle as for client rendering, this is not common in larger apps for many reasons, such as as code splitting, handling CSS and images, different code paths for React Router on the server vs. client, etc.
|
19
|
-
1. You need to configure `config.server_bundle_js_file = "
|
21
|
+
1. You need to configure `config.server_bundle_js_file = "server-bundle.js"` in your `config/initializers/react_on_rails.rb`
|
22
|
+
1. You should ***not*** put a hash on the server-bundle so that you can easily use the webpack-dev-server for client bundles and have the server bundle generated by a watch process.
|
20
23
|
|
21
24
|
## Do you need server rendering?
|
22
25
|
|
@@ -26,4 +29,4 @@ Server rendering is used for either SEO or performance reasons.
|
|
26
29
|
|
27
30
|
1. Never access `window`. Animations, globals on window, etc. just don't make sense when you're trying to run some JavaScript code to output a string of HTML.
|
28
31
|
2. JavaScript calls to `setTimeout`, `setInterval`, and `clearInterval` similarly don't make sense when server rendering.
|
29
|
-
3. Promises don't work when server rendering
|
32
|
+
3. Promises and file system access don't work when server rendering with ExecJS. Instead, you can use the Node renderer or [React on Rails Pro](https://www.shakacode.com/react-on-rails-pro/).
|
@@ -15,7 +15,7 @@ side rendering, except for the key `serverSide` based on whether or not you are
|
|
15
15
|
|
16
16
|
While you could manually configure your Rails code to pass the "`railsContext` information" with
|
17
17
|
the rest of your "props", the `railsContext` is a convenience because it's passed consistently to
|
18
|
-
all invocations of
|
18
|
+
all invocations of Render-Functions.
|
19
19
|
|
20
20
|
For example, suppose you create a "render-function" called MyAppComponent.
|
21
21
|
|
@@ -1,16 +1,20 @@
|
|
1
1
|
# Upgrading React on Rails
|
2
2
|
|
3
3
|
## Need Help Migrating?
|
4
|
-
If you would like help in migrating between React on Rails versions or help with implementing server rendering, please contact [justin@shakacode.com](mailto:justin@shakacode.com) for information about our [
|
4
|
+
If you would like help in migrating between React on Rails versions or help with implementing server rendering, please contact [justin@shakacode.com](mailto:justin@shakacode.com) for more information about our [React on Rails Pro Support](https://www.shakacode.com/react-on-rails-pro).
|
5
5
|
|
6
|
-
We specialize in helping companies to quickly and efficiently
|
6
|
+
We specialize in helping companies to quickly and efficiently upgrade. The older versions use the Rails asset pipeline to package client assets. The current and recommended way is to use Webpack 4+ for asset preparation. You may also need help migrating from the `rails/webpacker`'s Webpack configuration to a better setup ready for Server Side Rendering.
|
7
7
|
|
8
8
|
## Upgrading to v12
|
9
9
|
### Recent versions
|
10
|
-
Make sure that you are on a relatively more recent version of rails and webpacker.
|
11
|
-
v12 is tested on Rails 6. It should work on Rails v5. If you're on
|
10
|
+
Make sure that you are on a relatively more recent version of rails and webpacker. Yes, the [rails/webpacker](https://github.com/rails/webpacker) gem is required!
|
11
|
+
v12 is tested on Rails 6. It should work on Rails v5. If you're on any older version,
|
12
12
|
and v12 doesn't work, please file an issue.
|
13
13
|
|
14
|
+
### Removed Configuration config.symlink_non_digested_assets_regex
|
15
|
+
Remove `config.symlink_non_digested_assets_regex` from your `config/initializers/react_on_rails.rb`.
|
16
|
+
If you still need that feature, please file an issue.
|
17
|
+
|
14
18
|
### i18n default format changed to JSON
|
15
19
|
* If you're using the internalization helper, then set `config.i18n_output_format = 'js'`. You can
|
16
20
|
later update to the default JSON format as you will need to update your usage of that file. A JSON
|
@@ -19,25 +23,58 @@ and v12 doesn't work, please file an issue.
|
|
19
23
|
### Updated API for `ReactOnRails.register()`
|
20
24
|
|
21
25
|
In order to solve the issues regarding React Hooks compatibility, the number of parameters
|
22
|
-
for functions is used to determine if you have a
|
26
|
+
for functions is used to determine if you have a Render-Function that will get invoked to
|
23
27
|
return a React component, or you are registering a React component defined by a function.
|
28
|
+
Please see [Render-Functions and the Rails Context](./render-functions-and-railscontext.md) for
|
29
|
+
more information on what a Render-Function is.
|
24
30
|
|
25
|
-
#####
|
31
|
+
##### Update required for registered functions taking exactly 2 params.
|
26
32
|
|
27
|
-
Registered Objects are of the following
|
28
|
-
1.
|
29
|
-
that takes zero or one params and returns a React Element, like JSX.
|
33
|
+
Registered Objects are of the following type:
|
34
|
+
1. **Function that takes only zero or one params and you return a React Element**, often JSX. If the function takes zero or one params, there is **no migration needed** for that function.
|
30
35
|
```js
|
31
|
-
export default (props
|
36
|
+
export default (props) => <Component {...props} />;
|
32
37
|
```
|
38
|
+
|
39
|
+
2. **Function that takes only zero or one params and you return an Object (_not a React Element_)**. If the function takes zero or one params, **you need to add one or two unused params so you have exactly 2 params** and then that function will be treated as a render function and it can return an Object rather than a React element. If you don't do this, you'll see this obscure error message:
|
33
40
|
|
34
|
-
|
41
|
+
```
|
42
|
+
[SERVER] message: Objects are not valid as a React child (found: object with keys {renderedHtml}). If you meant to render a collection of children, use an array instead.
|
43
|
+
in YourComponentRenderFunction
|
44
|
+
```
|
45
|
+
|
46
|
+
So look in YourComponentRenderFunction and do this change
|
47
|
+
|
48
|
+
```js
|
49
|
+
export default (props) => { renderedHTML: getRenderedHTML };
|
50
|
+
```
|
51
|
+
|
52
|
+
To have exactly 2 arguments:
|
53
|
+
|
54
|
+
```js
|
55
|
+
export default (props, _railsContext) => { renderedHTML: getRenderedHTML };
|
56
|
+
```
|
57
|
+
|
58
|
+
3. Function that takes **2 params** and returns **a React function or class component**. _Migration is needed as the older syntax returned a React Element._
|
59
|
+
A function component is a function that takes zero or one params and returns a React Element, like JSX. The correct syntax
|
60
|
+
looks like:
|
35
61
|
```js
|
36
|
-
export default (props) => <Component {...props} />;
|
62
|
+
export default (props, railsContext) => () => <Component {{...props, railsContext}} />;
|
37
63
|
```
|
64
|
+
Note, you cannot return a React Element (JSX). See below for the migration steps. If your function that took **two params returned
|
65
|
+
an Object**, then no migration is required.
|
66
|
+
4. Function that takes **3 params** and uses the 3rd param, `domNodeId`, to call `ReactDOM.hydrate`. If the function takes 3 params, there is **no migration needed** for that function.
|
67
|
+
5. ES6 or ES5 class. There is **no migration needed**.
|
68
|
+
|
69
|
+
Previously, with case number 2, you could return a React Element.
|
70
|
+
|
71
|
+
The fix is simple. Here is an example of the change you'll do:
|
72
|
+
|
73
|
+
![2020-07-07_09-43-51 (1)](https://user-images.githubusercontent.com/1118459/86927351-eff79e80-c0ce-11ea-9172-d6855c45e2bb.png)
|
74
|
+
|
38
75
|
##### Broken, as this function takes two params and it returns a React Element from a JSX Literal
|
39
76
|
```js
|
40
|
-
export default (props,
|
77
|
+
export default (props, railsContext) => <Component {{...props, railsContext} />;
|
41
78
|
```
|
42
79
|
|
43
80
|
If you make this mistake, you'll get this warning
|
@@ -63,7 +100,7 @@ wrapper such that you're returning a function rather than a React Element, then:
|
|
63
100
|
|
64
101
|
## Upgrading rails/webpacker from v3 to v4
|
65
102
|
### Custom Webpack build file
|
66
|
-
The default value for `extract_css` is **false** in `config/webpack.yml`. Custom webpack builds should set this value to true or else no CSS link tags are generated. You have a custom webpack build if you are not using [rails/webpacker](https://github.com/rails/webpacker to setup your Webpack configuration.
|
103
|
+
The default value for `extract_css` is **false** in `config/webpack.yml`. Custom webpack builds should set this value to true or else no CSS link tags are generated. You have a custom webpack build if you are not using [rails/webpacker](https://github.com/rails/webpacker) to setup your Webpack configuration.
|
67
104
|
|
68
105
|
```yml
|
69
106
|
default: &default
|
@@ -6,8 +6,13 @@
|
|
6
6
|
|
7
7
|
[rails/webpacker](https://github.com/rails/webpacker) is the Ruby gem that mainly gives us 2 things:
|
8
8
|
|
9
|
-
1. View helpers for placing the
|
10
|
-
2. A layer of abstraction on top of Webpack customization.
|
9
|
+
1. View helpers for placing the webpack bundles on your Rails views. React on Rails depends on these view helpers.
|
10
|
+
2. A layer of abstraction on top of Webpack customization. The base setup works great for the client side webpack configuration.
|
11
|
+
|
12
|
+
To get a deeper understanding of `rails/webpacker`, watch [RailsConf 2020 CE - Webpacker, It-Just-Works, But How? by Justin Gordon](https://youtu.be/sJLoOpc5LD8)
|
13
|
+
|
14
|
+
Per the example repo [shakacode/react_on_rails_tutorial_with_ssr_and_hmr_fast_refresh](https://github.com/shakacode/react_on_rails_tutorial_with_ssr_and_hmr_fast_refresh),
|
15
|
+
you should consider keeping your codebase mostly consistent with the defaults for [rails/webpacker](https://github.com/rails/webpacker).
|
11
16
|
|
12
17
|
# React on Rails
|
13
18
|
|
@@ -15,15 +20,15 @@ Version 9 of React on Rails added support for the rails/webpacker view helpers s
|
|
15
20
|
|
16
21
|
A key decision in your use React on Rails is whether you go with the rails/webpacker default setup or the traditional React on Rails setup of putting all your client side files under the `/client` directory. While there are technically 2 independent choices involved, the directory structure and the mechanism of Webpack configuration, for simplicity sake we'll assume that these choices go together.
|
17
22
|
|
18
|
-
## Option 1:
|
23
|
+
## Option 1: Default Generator Setup: rails/webpacker app/javascript
|
19
24
|
|
20
|
-
|
25
|
+
Typical rails/webpacker apps have a standard directory structure as documented [here](https://github.com/rails/webpacker/blob/master/docs/folder-structure.md). If you follow the steps in the the [basic tutorial](../../docs/tutorial.md), you will see this pattern in action. In order to customize the Webpack configuration, you need to consult with the [rails/webpacker Webpack configuration](https://github.com/rails/webpacker/blob/master/docs/webpack.md).
|
21
26
|
|
22
|
-
The
|
27
|
+
The *advantage* of using rails/webpacker to configure Webpack is that there is very little code needed to get started and you don't need to understand really anything about Webpack customization.
|
23
28
|
|
24
|
-
|
29
|
+
## Option 2: Traditional React on Rails using the /client directory
|
25
30
|
|
26
|
-
|
31
|
+
Until version 9, all React on Rails apps used the `/client` directory for configuring React on Rails in terms of the configuration of Webpack and location of your JavaScript and Webpack files, including the node_modules directory. Version 9 changed the default to `/` for the `node_modules` location using this value in `config/initializers/react_on_rails.rb`: `config.node_modules_location`.
|
27
32
|
|
28
33
|
You can access values in the `config/webpacker.yml`
|
29
34
|
|
@@ -36,15 +41,4 @@ You will want consider using some of the same values set in these files:
|
|
36
41
|
* https://github.com/rails/webpacker/blob/master/package/environments/base.js
|
37
42
|
* https://github.com/rails/webpacker/blob/master/package/environments/development.js
|
38
43
|
|
39
|
-
**Note**, if your node_modules directory is not at the top level of the Rails project, then you will need to set the
|
40
|
-
ENV value of WEBPACKER_CONFIG to the location of the `config/webpacker.yml` file per [rails/webpacker PR 2561](https://github.com/rails/webpacker/pull/2561).
|
41
|
-
|
42
|
-
## Option 2: Default Generator Setup: rails/webpacker app/javascript
|
43
|
-
|
44
|
-
Typical rails/webpacker apps have a standard directory structure as documented [here](https://github.com/rails/webpacker/blob/master/docs/folder-structure.md). If you follow the steps in the the [basic tutorial](../../docs/tutorial.md), you will see this pattern in action. In order to customize the Webpack configuration, you need to consult with the [rails/webpacker Webpack configuration](https://github.com/rails/webpacker/blob/master/docs/webpack.md).
|
45
|
-
|
46
|
-
The *advantage* of using rails/webpacker to configure Webpack is that there is very little code needed to get started and you don't need to understand really anything about Webpack customization. The *big disadvantage* to this is that you will need to learn the ins and outs of the [rails/webpacker way to customize Webpack](https://github.com/rails/webpacker/blob/master/docs/webpack.md) which differs from the plain [Webpack way](https://webpack.js.org/).
|
47
44
|
|
48
|
-
You can find more details on this topic in [Recommended Project Structure](./recommended-project-structure.md).
|
49
|
-
|
50
|
-
See [Issue 982: Tutorial Generating Correct Project Structure?](https://github.com/shakacode/react_on_rails/issues/982) to discuss this issue.
|
data/docs/misc/doctrine.md
CHANGED
@@ -25,7 +25,6 @@ The React on Rails setup provides several key components related to front-end de
|
|
25
25
|
* React on Rails has taken the hard work out of figuring out the JavaScript tooling that works best with Rails. Not only could you spend lots of time researching different tooling, but then you'd have to figure out how to splice it all together. This is where a lot of "JavaScript fatigue" comes from. The following keep the code clean and consistent:
|
26
26
|
* [Style Guide](../coding-style/style.md)
|
27
27
|
* [linters](../contributor-info/linters.md)
|
28
|
-
* [Recommended Project Structure](../basics/recommended-project-structure.md)
|
29
28
|
|
30
29
|
We're big believers in this quote from the Rails Doctrine:
|
31
30
|
|
@@ -21,11 +21,11 @@ Let's say you're requesting a page that needs to fetch a code chunk from the ser
|
|
21
21
|
> (server) <div data-reactroot="
|
22
22
|
<!--This comment is here because the comment beginning on line 13 messes up Sublime's markdown parsing-->
|
23
23
|
|
24
|
-
Different markup is generated on the client than on the server. Why does this happen? When you register a component or
|
24
|
+
Different markup is generated on the client than on the server. Why does this happen? When you register a component or Render-Function with `ReactOnRails.register`, react on rails will render the component as soon as the page loads. However, react-router renders a comment while waiting for the code chunk to be fetched from the server. This means that react will tear all of the server rendered code out of the DOM, and then rerender it a moment later once the code chunk arrives from the server, defeating most of the purpose of server rendering.
|
25
25
|
|
26
26
|
### The solution
|
27
27
|
|
28
|
-
To prevent this, you have to wait until the code chunk is fetched before doing the initial render on the client side. To accomplish this, react on rails allows you to register a renderer. This works just like registering a
|
28
|
+
To prevent this, you have to wait until the code chunk is fetched before doing the initial render on the client side. To accomplish this, react on rails allows you to register a renderer. This works just like registering a Render-Function, except that the function you pass takes three arguments: `renderer(props, railsContext, domNodeId)`, and is responsible for calling `ReactDOM.render` or `ReactDOM.hydrate` to render the component to the DOM. React on rails will automatically detect when a Render-Function takes three arguments, and will **not** call `ReactDOM.render` or `ReactDOM.hydrate`, instead allowing you to control the initial render yourself. Note, you have to be careful to call `ReactDOM.hydrate` rather than `ReactDOM.render` if you are are server rendering.
|
29
29
|
|
30
30
|
Here's an example of how you might use this in practice:
|
31
31
|
|
@@ -117,8 +117,8 @@ There's an implemented example of code splitting in the `spec/dummy` folder of t
|
|
117
117
|
|
118
118
|
See:
|
119
119
|
|
120
|
-
- [spec/dummy/client/app/startup/
|
121
|
-
- [spec/dummy/client/app/
|
120
|
+
- [spec/dummy/client/app/startup/client-bundle.js](https://github.com/shakacode/react_on_rails/tree/master/spec/dummy/client/app/startup/client-bundle.js)
|
121
|
+
- [spec/dummy/client/app/packs/server-bundle.js](https://github.com/shakacode/react_on_rails/tree/master/spec/dummy/client/app/packs/server-bundle.js)
|
122
122
|
- [spec/dummy/client/app/startup/DeferredRenderAppClient](https://github.com/shakacode/react_on_rails/tree/master/spec/dummy/client/app/startup/DeferredRenderAppClient.jsx)<-- Code splitting implemented here
|
123
123
|
- [spec/dummy/client/app/startup/DeferredRenderAppServer.jsx](https://github.com/shakacode/react_on_rails/tree/master/spec/dummy/client/app/startup/DeferredRenderAppServer.jsx)
|
124
124
|
- [spec/dummy/client/app/components/DeferredRender.jsx](https://github.com/shakacode/react_on_rails/tree/master/spec/dummy/client/app/components/DeferredRender.jsx)
|
@@ -134,7 +134,7 @@ If you're going to try to do code splitting with server rendered routes, you'll
|
|
134
134
|
|
135
135
|
The reason is we do server rendering with ExecJS, which is not capable of doing anything asynchronous. It would be impossible to asyncronously fetch a code chunk while server rendering. See [this issue](https://github.com/shakacode/react_on_rails/issues/477) for a discussion.
|
136
136
|
|
137
|
-
Also, do not attempt to register a renderer on the server. Instead, register either a
|
137
|
+
Also, do not attempt to register a renderer function on the server. Instead, register either a Render-Function or a component. If you register a renderer in the server bundle, you'll get an error when react on rails tries to server render the component.
|
138
138
|
|
139
139
|
## How does Webpack know where to find my code chunks?
|
140
140
|
|
data/docs/tutorial.md
CHANGED
@@ -1,5 +1,11 @@
|
|
1
1
|
# React on Rails Basic Tutorial
|
2
2
|
|
3
|
+
-----
|
4
|
+
|
5
|
+
**November 11, 2020**: See the example repo of [React on Rails Tutorial With SSR, HMR fast refresh, and TypeScript](https://github.com/shakacode/react_on_rails_tutorial_with_ssr_and_hmr_fast_refresh) for a new way to setup the creation of your SSR bundle with `rails/webpacker`. This file will be update shortly. Most of it is still relevant.
|
6
|
+
|
7
|
+
-----
|
8
|
+
|
3
9
|
*Updated for Ruby 2.7.1, Rails 6.0.3.1, and React on Rails v12.0.0*
|
4
10
|
|
5
11
|
This tutorial guides you through setting up a new or existing Rails app with **React on Rails**, demonstrating Rails + React + Redux + Server Rendering.
|
@@ -43,7 +43,14 @@ module ReactOnRails
|
|
43
43
|
end
|
44
44
|
|
45
45
|
def add_yarn_dependencies
|
46
|
-
|
46
|
+
major_minor_patch_only = /\A\d+\.\d+\.\d+\z/.freeze
|
47
|
+
if ReactOnRails::VERSION.match?(major_minor_patch_only)
|
48
|
+
run "yarn add react-on-rails@#{ReactOnRails::VERSION} --exact"
|
49
|
+
else
|
50
|
+
# otherwise add latest
|
51
|
+
puts "Adding the lastest react-on-rails NPM module. Double check this is correct in package.json"
|
52
|
+
run "yarn add react-on-rails --exact"
|
53
|
+
end
|
47
54
|
end
|
48
55
|
|
49
56
|
def append_to_spec_rails_helper
|