react_on_rails 11.2.1 → 12.0.0.pre.beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.circleci/config.yml +320 -0
- data/.eslintignore +2 -1
- data/.eslintrc +23 -1
- data/.github/FUNDING.yml +1 -0
- data/.gitignore +3 -1
- data/.prettierignore +10 -1
- data/.prettierrc +3 -0
- data/.rubocop.yml +37 -11
- data/.travis.yml +10 -20
- data/CHANGELOG.md +85 -9
- data/CONTRIBUTING.md +60 -71
- data/Gemfile +3 -4
- data/{COMM-LICENSE → REACT-ON-RAILS-PRO-LICENSE} +6 -9
- data/README.md +121 -71
- data/Rakefile +0 -7
- data/SUMMARY.md +9 -12
- data/book.json +5 -5
- data/docs/additional-reading/asset-pipeline.md +8 -16
- data/docs/additional-reading/react-helmet.md +30 -10
- data/docs/additional-reading/react-router.md +52 -75
- data/docs/additional-reading/server-rendering-tips.md +12 -7
- data/docs/api/javascript-api.md +3 -3
- data/docs/api/redux-store-api.md +4 -2
- data/docs/api/view-helpers-api.md +8 -9
- data/docs/basics/configuration.md +68 -59
- data/docs/basics/deployment.md +1 -2
- data/docs/basics/hmr-and-hot-reloading-with-the-webpack-dev-server.md +49 -0
- data/docs/basics/i18n.md +44 -22
- data/docs/basics/installation-into-an-existing-rails-app.md +2 -2
- data/docs/basics/minitest-configuration.md +31 -0
- data/docs/basics/react-server-rendering.md +1 -1
- data/docs/basics/{generator-functions-and-railscontext.md → render-functions-and-railscontext.md} +59 -21
- data/docs/basics/rspec-configuration.md +29 -17
- data/docs/basics/upgrading-react-on-rails.md +67 -3
- data/docs/basics/webpack-configuration.md +15 -1
- data/docs/contributor-info/errors-with-hooks.md +45 -0
- data/docs/contributor-info/pull-requests.md +44 -0
- data/docs/misc/doctrine.md +1 -1
- data/docs/{misc-pending → outdated}/code-splitting.md +12 -8
- data/docs/{additional-reading → outdated}/heroku-deployment.md +0 -6
- data/docs/{basics → outdated}/how-react-on-rails-works.md +3 -3
- data/docs/{misc-pending → outdated}/manual-installation-overview.md +5 -5
- data/docs/{additional-reading → outdated}/rails-assets-relative-paths.md +3 -3
- data/docs/{misc-pending → outdated}/rails-assets.md +4 -7
- data/docs/{misc → outdated}/rails3.md +0 -0
- data/docs/testimonials/resortpass.md +13 -0
- data/docs/testimonials/testimonials.md +11 -1
- data/docs/tutorial.md +96 -70
- data/jest.config.js +4 -0
- data/lib/generators/react_on_rails/base_generator.rb +2 -2
- data/lib/generators/react_on_rails/dev_tests_generator.rb +1 -1
- data/lib/generators/react_on_rails/generator_helper.rb +4 -6
- data/lib/generators/react_on_rails/templates/base/base/Procfile.dev +3 -1
- data/lib/generators/react_on_rails/templates/base/base/Procfile.dev-hmr +26 -0
- data/lib/generators/react_on_rails/templates/base/base/app/javascript/bundles/HelloWorld/components/HelloWorld.jsx +20 -40
- data/lib/generators/react_on_rails/templates/base/base/config/initializers/react_on_rails.rb +2 -1
- data/lib/generators/react_on_rails/templates/redux/base/app/javascript/bundles/HelloWorld/components/HelloWorld.jsx +4 -8
- data/lib/generators/react_on_rails/templates/redux/base/app/javascript/bundles/HelloWorld/store/helloWorldStore.js +1 -3
- data/lib/react_on_rails.rb +3 -1
- data/lib/react_on_rails/configuration.rb +13 -22
- data/lib/react_on_rails/error.rb +2 -0
- data/lib/react_on_rails/helper.rb +100 -143
- data/lib/react_on_rails/json_parse_error.rb +2 -0
- data/lib/react_on_rails/locales/base.rb +150 -0
- data/lib/react_on_rails/locales/to_js.rb +37 -0
- data/lib/react_on_rails/locales/to_json.rb +27 -0
- data/lib/react_on_rails/prerender_error.rb +11 -15
- data/lib/react_on_rails/react_component/render_options.rb +4 -0
- data/lib/react_on_rails/server_rendering_pool/ruby_embedded_java_script.rb +41 -46
- data/lib/react_on_rails/test_helper/ensure_assets_compiled.rb +7 -8
- data/lib/react_on_rails/utils.rb +14 -19
- data/lib/react_on_rails/version.rb +1 -1
- data/lib/react_on_rails/version_checker.rb +1 -0
- data/lib/react_on_rails/webpacker_utils.rb +13 -2
- data/lib/tasks/assets.rake +19 -44
- data/lib/tasks/locale.rake +4 -2
- data/package-scripts.yml +11 -8
- data/package.json +29 -28
- data/rakelib/dummy_apps.rake +1 -9
- data/rakelib/example_type.rb +3 -1
- data/rakelib/examples.rake +3 -0
- data/rakelib/lint.rake +2 -7
- data/rakelib/node_package.rake +2 -2
- data/rakelib/release.rake +0 -6
- data/rakelib/run_rspec.rake +5 -18
- data/react_on_rails.gemspec +3 -5
- data/tsconfig.json +14 -0
- data/webpackConfigLoader.js +3 -2
- data/yarn.lock +4170 -2197
- metadata +34 -57
- data/Gemfile.rails32 +0 -73
- data/docs/additional-reading/babel.md +0 -5
- data/docs/additional-reading/hot-reloading-rails-development-asset-pipeline.md +0 -47
- data/docs/api/ruby-api-hot-reload-view-helpers.md +0 -44
- data/lib/generators/react_on_rails/templates/base/base/Procfile.dev-server +0 -12
- data/lib/react_on_rails/assets_precompile.rb +0 -153
- data/lib/react_on_rails/locales_to_js.rb +0 -138
data/jest.config.js
ADDED
@@ -33,7 +33,7 @@ module ReactOnRails
|
|
33
33
|
app/views/layouts/hello_world.html.erb
|
34
34
|
config/initializers/react_on_rails.rb
|
35
35
|
Procfile.dev
|
36
|
-
Procfile.dev-
|
36
|
+
Procfile.dev-hmr]
|
37
37
|
base_files.each { |file| copy_file("#{base_path}#{file}", file) }
|
38
38
|
end
|
39
39
|
|
@@ -107,7 +107,7 @@ module ReactOnRails
|
|
107
107
|
foreman start -f Procfile.dev
|
108
108
|
|
109
109
|
- To turn on HMR, edit config/webpacker.yml and set HMR to true. Restart the rails server
|
110
|
-
and bin/webpack-dev-server. Or use Procfile.dev-
|
110
|
+
and bin/webpack-dev-server. Or use Procfile.dev-hmr.
|
111
111
|
|
112
112
|
- To server render, change this line app/views/hello_world/index.html.erb to
|
113
113
|
`prerender: true` to see server rendering (right click on page and select "view source").
|
@@ -50,7 +50,7 @@ module ReactOnRails
|
|
50
50
|
contents = File.read(package_json)
|
51
51
|
replacement_value = <<-STRING
|
52
52
|
"scripts": {
|
53
|
-
"postinstall": "
|
53
|
+
"postinstall": "yalc link react-on-rails",
|
54
54
|
STRING
|
55
55
|
new_client_package_json_contents = contents.gsub(/ {2}"scripts": {/,
|
56
56
|
replacement_value)
|
@@ -15,13 +15,11 @@ module GeneratorHelper
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def setup_file_error(file, data)
|
18
|
-
|
19
|
-
|
20
|
-
#{file}
|
21
|
-
|
22
|
-
#{data}
|
18
|
+
<<~MSG
|
19
|
+
#{file} was not found.
|
20
|
+
Please add the following content to your #{file} file:
|
21
|
+
#{data}
|
23
22
|
MSG
|
24
|
-
# rubocop:enable Layout/IndentHeredoc
|
25
23
|
end
|
26
24
|
|
27
25
|
def empty_directory_with_keep_file(destination, config = {})
|
@@ -4,4 +4,6 @@ web: rails s -p 3000
|
|
4
4
|
# Next line runs a watch process with webpack to compile the changed files.
|
5
5
|
# When making frequent changes to client side assets, you will prefer building webpack assets
|
6
6
|
# upon saving rather than when you refresh your browser page.
|
7
|
-
|
7
|
+
# Note, if using React on Rails localization you will need to run
|
8
|
+
# `bundle exec rake react_on_rails:locale` before you run bin/webpack
|
9
|
+
client: sh -c 'rm -rf public/packs/* || true && bin/webpack -w'
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# Procfile for development using HMR
|
2
|
+
|
3
|
+
web: rails s -p 3000
|
4
|
+
|
5
|
+
# Note, hot and live reloading don't work with the default generator setup on
|
6
|
+
# top of the rails/webpacker Webpack config with server rendering.
|
7
|
+
# If you have server rendering enabled (prerender is true), you either need to
|
8
|
+
# a. Ensure that you have dev_server.hmr and dev_server.inline BOTH set to false,
|
9
|
+
# and you have this option in your config/initializers/react_on_rails.rb:
|
10
|
+
# config.same_bundle_for_client_and_server = true
|
11
|
+
# If you have either config/webpacker.yml option set to true, you'll see errors like
|
12
|
+
# "ReferenceError: window is not defined" (if hmr is true)
|
13
|
+
# "TypeError: Cannot read property 'prototype' of undefined" (if inline is true)
|
14
|
+
# b. Skip using the webpack-dev-server. bin/webpack --watch is typically
|
15
|
+
fast enough.
|
16
|
+
# c. See the React on Rails README for a link to documentation for how to setup
|
17
|
+
# SSR with HMR and React hot loading using the webpack-dev-server only for the
|
18
|
+
# client bundles and a static file for the server bundle.
|
19
|
+
|
20
|
+
# Run the webpack-dev-server for client and maybe server files
|
21
|
+
webpack-dev-server: bin/webpack-dev-server
|
22
|
+
|
23
|
+
# Keep the JS fresh for server rendering. Remove if not server rendering.
|
24
|
+
# Especially if you have not configured generation of a server bundle without a hash.
|
25
|
+
# as that will conflict with the manifest created by the bin/webpack-dev-server
|
26
|
+
# rails-server-assets: SERVER_BUNDLE_ONLY=yes bin/webpack --watch
|
@@ -1,45 +1,25 @@
|
|
1
1
|
import PropTypes from 'prop-types';
|
2
|
-
import React from 'react';
|
2
|
+
import React, { useState } from 'react';
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
name: PropTypes.string.isRequired, // this is passed from the Rails view
|
7
|
-
};
|
4
|
+
const HelloWorld = (props) => {
|
5
|
+
const [name, setName] = useState(props.name);
|
8
6
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
7
|
+
return (
|
8
|
+
<div>
|
9
|
+
<h3>Hello, {name}!</h3>
|
10
|
+
<hr />
|
11
|
+
<form>
|
12
|
+
<label htmlFor="name">
|
13
|
+
Say hello to:
|
14
|
+
<input id="name" type="text" value={name} onChange={(e) => setName(e.target.value)} />
|
15
|
+
</label>
|
16
|
+
</form>
|
17
|
+
</div>
|
18
|
+
);
|
19
|
+
};
|
14
20
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
}
|
21
|
+
HelloWorld.propTypes = {
|
22
|
+
name: PropTypes.string.isRequired, // this is passed from the Rails view
|
23
|
+
};
|
19
24
|
|
20
|
-
|
21
|
-
this.setState({ name });
|
22
|
-
};
|
23
|
-
|
24
|
-
render() {
|
25
|
-
return (
|
26
|
-
<div>
|
27
|
-
<h3>
|
28
|
-
Hello, {this.state.name}!
|
29
|
-
</h3>
|
30
|
-
<hr />
|
31
|
-
<form >
|
32
|
-
<label htmlFor="name">
|
33
|
-
Say hello to:
|
34
|
-
</label>
|
35
|
-
<input
|
36
|
-
id="name"
|
37
|
-
type="text"
|
38
|
-
value={this.state.name}
|
39
|
-
onChange={(e) => this.updateName(e.target.value)}
|
40
|
-
/>
|
41
|
-
</form>
|
42
|
-
</div>
|
43
|
-
);
|
44
|
-
}
|
45
|
-
}
|
25
|
+
export default HelloWorld;
|
data/lib/generators/react_on_rails/templates/base/base/config/initializers/react_on_rails.rb
CHANGED
@@ -6,7 +6,8 @@
|
|
6
6
|
ReactOnRails.configure do |config|
|
7
7
|
# This configures the script to run to build the production assets by webpack. Set this to nil
|
8
8
|
# if you don't want react_on_rails building this file for you.
|
9
|
-
|
9
|
+
# If nil, then the standard rails/webpacker assets:precompile will run
|
10
|
+
# config.build_production_command = nil
|
10
11
|
|
11
12
|
################################################################################
|
12
13
|
################################################################################
|
@@ -4,19 +4,15 @@ import React from 'react';
|
|
4
4
|
const HelloWorld = ({ name, updateName }) => (
|
5
5
|
<div>
|
6
6
|
<h3>
|
7
|
-
Hello,
|
7
|
+
Hello,
|
8
|
+
{name}!
|
8
9
|
</h3>
|
9
10
|
<hr />
|
10
|
-
<form
|
11
|
+
<form>
|
11
12
|
<label htmlFor="name">
|
12
13
|
Say hello to:
|
14
|
+
<input id="name" type="text" value={name} onChange={(e) => updateName(e.target.value)} />
|
13
15
|
</label>
|
14
|
-
<input
|
15
|
-
id="name"
|
16
|
-
type="text"
|
17
|
-
value={name}
|
18
|
-
onChange={(e) => updateName(e.target.value)}
|
19
|
-
/>
|
20
16
|
</form>
|
21
17
|
</div>
|
22
18
|
);
|
@@ -1,8 +1,6 @@
|
|
1
1
|
import { createStore } from 'redux';
|
2
2
|
import helloWorldReducer from '../reducers/helloWorldReducer';
|
3
3
|
|
4
|
-
const configureStore = (railsProps) => (
|
5
|
-
createStore(helloWorldReducer, railsProps)
|
6
|
-
);
|
4
|
+
const configureStore = (railsProps) => createStore(helloWorldReducer, railsProps);
|
7
5
|
|
8
6
|
export default configureStore;
|
data/lib/react_on_rails.rb
CHANGED
@@ -22,4 +22,6 @@ require "react_on_rails/webpacker_utils"
|
|
22
22
|
require "react_on_rails/test_helper/webpack_assets_compiler"
|
23
23
|
require "react_on_rails/test_helper/webpack_assets_status_checker"
|
24
24
|
require "react_on_rails/test_helper/ensure_assets_compiled"
|
25
|
-
require "react_on_rails/
|
25
|
+
require "react_on_rails/locales/base"
|
26
|
+
require "react_on_rails/locales/to_js"
|
27
|
+
require "react_on_rails/locales/to_json"
|
@@ -31,10 +31,11 @@ module ReactOnRails
|
|
31
31
|
webpack_generated_files: %w[manifest.json],
|
32
32
|
rendering_extension: nil,
|
33
33
|
server_render_method: nil,
|
34
|
-
symlink_non_digested_assets_regex: nil,
|
35
34
|
build_test_command: "",
|
36
35
|
build_production_command: "",
|
37
|
-
random_dom_id: DEFAULT_RANDOM_DOM_ID
|
36
|
+
random_dom_id: DEFAULT_RANDOM_DOM_ID,
|
37
|
+
same_bundle_for_client_and_server: false,
|
38
|
+
i18n_output_format: nil
|
38
39
|
)
|
39
40
|
end
|
40
41
|
|
@@ -46,8 +47,9 @@ module ReactOnRails
|
|
46
47
|
:generated_assets_dirs, :generated_assets_dir,
|
47
48
|
:webpack_generated_files, :rendering_extension, :build_test_command,
|
48
49
|
:build_production_command,
|
49
|
-
:i18n_dir, :i18n_yml_dir,
|
50
|
-
:server_render_method, :
|
50
|
+
:i18n_dir, :i18n_yml_dir, :i18n_output_format,
|
51
|
+
:server_render_method, :random_dom_id,
|
52
|
+
:same_bundle_for_client_and_server
|
51
53
|
|
52
54
|
def initialize(node_modules_location: nil, server_bundle_js_file: nil, prerender: nil,
|
53
55
|
replay_console: nil,
|
@@ -58,16 +60,17 @@ module ReactOnRails
|
|
58
60
|
generated_assets_dir: nil, webpack_generated_files: nil,
|
59
61
|
rendering_extension: nil, build_test_command: nil,
|
60
62
|
build_production_command: nil,
|
61
|
-
|
62
|
-
|
63
|
+
same_bundle_for_client_and_server: nil,
|
64
|
+
i18n_dir: nil, i18n_yml_dir: nil, i18n_output_format: nil,
|
65
|
+
random_dom_id: nil, server_render_method: nil)
|
63
66
|
self.node_modules_location = node_modules_location.present? ? node_modules_location : Rails.root
|
64
|
-
self.server_bundle_js_file = server_bundle_js_file
|
65
67
|
self.generated_assets_dirs = generated_assets_dirs
|
66
68
|
self.generated_assets_dir = generated_assets_dir
|
67
69
|
self.build_test_command = build_test_command
|
68
70
|
self.build_production_command = build_production_command
|
69
71
|
self.i18n_dir = i18n_dir
|
70
72
|
self.i18n_yml_dir = i18n_yml_dir
|
73
|
+
self.i18n_output_format = i18n_output_format
|
71
74
|
|
72
75
|
self.random_dom_id = random_dom_id
|
73
76
|
self.prerender = prerender
|
@@ -83,6 +86,8 @@ module ReactOnRails
|
|
83
86
|
self.skip_display_none = skip_display_none
|
84
87
|
|
85
88
|
# Server rendering:
|
89
|
+
self.server_bundle_js_file = server_bundle_js_file
|
90
|
+
self.same_bundle_for_client_and_server = same_bundle_for_client_and_server
|
86
91
|
self.server_renderer_pool_size = self.development_mode ? 1 : server_renderer_pool_size
|
87
92
|
self.server_renderer_timeout = server_renderer_timeout # seconds
|
88
93
|
|
@@ -90,7 +95,6 @@ module ReactOnRails
|
|
90
95
|
self.rendering_extension = rendering_extension
|
91
96
|
|
92
97
|
self.server_render_method = server_render_method
|
93
|
-
self.symlink_non_digested_assets_regex = symlink_non_digested_assets_regex
|
94
98
|
end
|
95
99
|
|
96
100
|
# on ReactOnRails
|
@@ -99,7 +103,6 @@ module ReactOnRails
|
|
99
103
|
configure_generated_assets_dirs_deprecation
|
100
104
|
configure_skip_display_none_deprecation
|
101
105
|
ensure_generated_assets_dir_present
|
102
|
-
ensure_server_bundle_js_file_has_no_path
|
103
106
|
check_i18n_directory_exists
|
104
107
|
check_i18n_yml_directory_exists
|
105
108
|
check_server_render_method_is_only_execjs
|
@@ -198,24 +201,12 @@ module ReactOnRails
|
|
198
201
|
def ensure_webpack_generated_files_exists
|
199
202
|
return unless webpack_generated_files.empty?
|
200
203
|
|
201
|
-
files = ["
|
204
|
+
files = ["manifest.json"]
|
202
205
|
files << server_bundle_js_file if server_bundle_js_file.present?
|
203
206
|
|
204
207
|
self.webpack_generated_files = files
|
205
208
|
end
|
206
209
|
|
207
|
-
def ensure_server_bundle_js_file_has_no_path
|
208
|
-
return unless server_bundle_js_file.include?(File::SEPARATOR)
|
209
|
-
|
210
|
-
assets_dir = ReactOnRails::Utils.generated_assets_full_path
|
211
|
-
self.server_bundle_js_file = File.basename(server_bundle_js_file)
|
212
|
-
|
213
|
-
Rails.logger.warn do
|
214
|
-
"[DEPRECATION] ReactOnRails: remove path from server_bundle_js_file in configuration. "\
|
215
|
-
"All generated files must go in #{assets_dir}. Using file basename #{server_bundle_js_file}"
|
216
|
-
end
|
217
|
-
end
|
218
|
-
|
219
210
|
def configure_skip_display_none_deprecation
|
220
211
|
return if skip_display_none.nil?
|
221
212
|
|
data/lib/react_on_rails/error.rb
CHANGED
@@ -15,68 +15,20 @@ module ReactOnRails
|
|
15
15
|
module Helper
|
16
16
|
include ReactOnRails::Utils::Required
|
17
17
|
|
18
|
-
COMPONENT_HTML_KEY = "componentHtml"
|
18
|
+
COMPONENT_HTML_KEY = "componentHtml"
|
19
19
|
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
20
|
+
# react_component_name: can be a React function or class component or a "render function".
|
21
|
+
# "render functions" differ from a React function in that they take two parameters, the
|
22
|
+
# props and the railsContext, like this:
|
23
23
|
#
|
24
|
-
#
|
25
|
-
# these params are optional, and support either a single value, or an array.
|
24
|
+
# let MyReactComponentApp = (props, railsContext) => <MyReactComponent {...props}/>;
|
26
25
|
#
|
27
|
-
#
|
28
|
-
#
|
26
|
+
# Alternately, you can define the render function with an additional property
|
27
|
+
# `.renderFunction = true`:
|
29
28
|
#
|
30
|
-
#
|
31
|
-
#
|
32
|
-
# media: 'all',
|
33
|
-
# 'data-turbolinks-track' => "reload") %>
|
29
|
+
# let MyReactComponentApp = (props) => <MyReactComponent {...props}/>;
|
30
|
+
# MyReactComponent.renderFunction = true;
|
34
31
|
#
|
35
|
-
# <!-- These do not use turbolinks, so no data-turbolinks-track -->
|
36
|
-
# <!-- This is to load the hot assets. -->
|
37
|
-
# <%= env_javascript_include_tag(hot: ['http://localhost:3500/vendor-bundle.js',
|
38
|
-
# 'http://localhost:3500/app-bundle.js']) %>
|
39
|
-
#
|
40
|
-
# <!-- These do use turbolinks -->
|
41
|
-
# <%= env_javascript_include_tag(static: 'application_static',
|
42
|
-
# hot: 'application_non_webpack',
|
43
|
-
# 'data-turbolinks-track' => "reload") %>
|
44
|
-
#
|
45
|
-
# NOTE: for Turbolinks 2.x, use 'data-turbolinks-track' => true
|
46
|
-
# See application.html.erb for usage example
|
47
|
-
# https://github.com/shakacode/react-webpack-rails-tutorial/blob/master/app%2Fviews%2Flayouts%2Fapplication.html.erb
|
48
|
-
def env_javascript_include_tag(args = {})
|
49
|
-
send_tag_method(:javascript_include_tag, args)
|
50
|
-
end
|
51
|
-
|
52
|
-
# Helper to set CSS assets depending on if we want static or "hot", which means from the
|
53
|
-
# Webpack dev server.
|
54
|
-
#
|
55
|
-
# In this example, application_non_webpack is simply a CSS asset pipeline file which includes
|
56
|
-
# styles not placed in the webpack build.
|
57
|
-
#
|
58
|
-
# We don't need styles from the webpack build, as those will come via the JavaScript include
|
59
|
-
# tags.
|
60
|
-
#
|
61
|
-
# The key options are `static` and `hot` which specify what you want for static vs. hot. Both of
|
62
|
-
# these params are optional, and support either a single value, or an array.
|
63
|
-
#
|
64
|
-
# <%= env_stylesheet_link_tag(static: 'application_static',
|
65
|
-
# hot: 'application_non_webpack',
|
66
|
-
# media: 'all',
|
67
|
-
# 'data-turbolinks-track' => true) %>
|
68
|
-
#
|
69
|
-
def env_stylesheet_link_tag(args = {})
|
70
|
-
send_tag_method(:stylesheet_link_tag, args)
|
71
|
-
end
|
72
|
-
|
73
|
-
# react_component_name: can be a React component, created using a ES6 class, or
|
74
|
-
# React.createClass, or a
|
75
|
-
# `generator function` that returns a React component
|
76
|
-
# using ES6
|
77
|
-
# let MyReactComponentApp = (props, railsContext) => <MyReactComponent {...props}/>;
|
78
|
-
# or using ES5
|
79
|
-
# var MyReactComponentApp = function(props, railsContext) { return <YourReactComponent {...props}/>; }
|
80
32
|
# Exposing the react_component_name is necessary to both a plain ReactComponent as well as
|
81
33
|
# a generator:
|
82
34
|
# See README.md for how to "register" your react components.
|
@@ -98,7 +50,8 @@ module ReactOnRails
|
|
98
50
|
# raise_on_prerender_error: <true/false> Default to false. True will raise exception on server
|
99
51
|
# if the JS code throws
|
100
52
|
# Any other options are passed to the content tag, including the id.
|
101
|
-
# random_dom_id can be set to override the
|
53
|
+
# random_dom_id can be set to override the default from the config/initializers. That's only
|
54
|
+
# used if you have multiple instance of the same component on the Rails view.
|
102
55
|
def react_component(component_name, options = {})
|
103
56
|
internal_result = internal_react_component(component_name, options)
|
104
57
|
server_rendered_html = internal_result[:result]["html"]
|
@@ -112,20 +65,24 @@ module ReactOnRails
|
|
112
65
|
render_options: internal_result[:render_options]
|
113
66
|
)
|
114
67
|
elsif server_rendered_html.is_a?(Hash)
|
115
|
-
msg =
|
116
|
-
|
117
|
-
|
118
|
-
|
68
|
+
msg = <<~MSG
|
69
|
+
Use react_component_hash (not react_component) to return a Hash to your ruby view code. See
|
70
|
+
https://github.com/shakacode/react_on_rails/blob/master/spec/dummy/client/app/startup/ReactHelmetServerApp.jsx
|
71
|
+
for an example of the necessary javascript configuration.
|
119
72
|
MSG
|
120
73
|
raise ReactOnRails::Error, msg
|
121
|
-
|
122
74
|
else
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
75
|
+
class_name = server_rendered_html.class.name
|
76
|
+
msg = <<~MSG
|
77
|
+
ReactOnRails: server_rendered_html is expected to be a String or Hash for #{component_name}.
|
78
|
+
Type is #{class_name}
|
79
|
+
Value:
|
80
|
+
#{server_rendered_html}
|
81
|
+
|
82
|
+
If you're trying to use a render function to return a Hash to your ruby view code, then use
|
83
|
+
react_component_hash instead of react_component and see
|
84
|
+
https://github.com/shakacode/react_on_rails/blob/master/spec/dummy/client/app/startup/ReactHelmetServerApp.jsx
|
85
|
+
for an example of the JavaScript code.
|
129
86
|
MSG
|
130
87
|
raise ReactOnRails::Error, msg
|
131
88
|
end
|
@@ -136,7 +93,7 @@ module ReactOnRails
|
|
136
93
|
# It is exactly like react_component except for the following:
|
137
94
|
# 1. prerender: true is automatically added, as this method doesn't make sense for client only
|
138
95
|
# rendering.
|
139
|
-
# 2. Your JavaScript
|
96
|
+
# 2. Your JavaScript render function for server rendering must return an Object rather than a React component.
|
140
97
|
# 3. Your view code must expect an object and not a string.
|
141
98
|
#
|
142
99
|
# Here is an example of the view code:
|
@@ -166,10 +123,12 @@ module ReactOnRails
|
|
166
123
|
render_options: internal_result[:render_options]
|
167
124
|
)
|
168
125
|
else
|
169
|
-
msg =
|
170
|
-
|
126
|
+
msg = <<~MSG
|
127
|
+
render function used by react_component_hash for #{component_name} is expected to return
|
171
128
|
an Object. See https://github.com/shakacode/react_on_rails/blob/master/spec/dummy/client/app/startup/ReactHelmetServerApp.jsx
|
172
|
-
for an example of the JavaScript code.
|
129
|
+
for an example of the JavaScript code.
|
130
|
+
Note, your render function must either take 2 params or have the property
|
131
|
+
`.renderFunction = true` added to it to distinguish it from a React Function Component.
|
173
132
|
MSG
|
174
133
|
raise ReactOnRails::Error, msg
|
175
134
|
end
|
@@ -178,6 +137,9 @@ module ReactOnRails
|
|
178
137
|
# Separate initialization of store from react_component allows multiple react_component calls to
|
179
138
|
# use the same Redux store.
|
180
139
|
#
|
140
|
+
# NOTE: This technique not recommended as it prevents dynamic code splitting for performance.
|
141
|
+
# Instead, you should use the standard react_component view helper.
|
142
|
+
#
|
181
143
|
# store_name: name of the store, corresponding to your call to ReactOnRails.registerStores in your
|
182
144
|
# JavaScript code.
|
183
145
|
# props: Ruby Hash or JSON string which contains the properties to pass to the redux store.
|
@@ -277,6 +239,60 @@ module ReactOnRails
|
|
277
239
|
ReactOnRails::JsonOutput.escape(json_value)
|
278
240
|
end
|
279
241
|
|
242
|
+
# This is the definitive list of the default values used for the rails_context, which is the
|
243
|
+
# second parameter passed to both component and store render functions.
|
244
|
+
# This method can be called from views and from the controller, as `helpers.rails_context`
|
245
|
+
#
|
246
|
+
# rubocop:disable Metrics/AbcSize
|
247
|
+
def rails_context(server_side: true)
|
248
|
+
# ALERT: Keep in sync with node_package/src/types/index.ts for the properties of RailsContext
|
249
|
+
@rails_context ||= begin
|
250
|
+
result = {
|
251
|
+
railsEnv: Rails.env,
|
252
|
+
inMailer: in_mailer?,
|
253
|
+
# Locale settings
|
254
|
+
i18nLocale: I18n.locale,
|
255
|
+
i18nDefaultLocale: I18n.default_locale,
|
256
|
+
rorVersion: ReactOnRails::VERSION,
|
257
|
+
rorPro: ReactOnRails::Utils.react_on_rails_pro?
|
258
|
+
}
|
259
|
+
if defined?(request) && request.present?
|
260
|
+
# Check for encoding of the request's original_url and try to force-encoding the
|
261
|
+
# URLs as UTF-8. This situation can occur in browsers that do not encode the
|
262
|
+
# entire URL as UTF-8 already, mostly on the Windows platform (IE11 and lower).
|
263
|
+
original_url_normalized = request.original_url
|
264
|
+
if original_url_normalized.encoding.to_s == "ASCII-8BIT"
|
265
|
+
original_url_normalized = original_url_normalized.force_encoding("ISO-8859-1").encode("UTF-8")
|
266
|
+
end
|
267
|
+
|
268
|
+
# Using Addressable instead of standard URI to better deal with
|
269
|
+
# non-ASCII characters (see https://github.com/shakacode/react_on_rails/pull/405)
|
270
|
+
uri = Addressable::URI.parse(original_url_normalized)
|
271
|
+
# uri = Addressable::URI.parse("http://foo.com:3000/posts?id=30&limit=5#time=1305298413")
|
272
|
+
|
273
|
+
result.merge!(
|
274
|
+
# URL settings
|
275
|
+
href: uri.to_s,
|
276
|
+
location: "#{uri.path}#{uri.query.present? ? "?#{uri.query}" : ''}",
|
277
|
+
scheme: uri.scheme, # http
|
278
|
+
host: uri.host, # foo.com
|
279
|
+
port: uri.port,
|
280
|
+
pathname: uri.path, # /posts
|
281
|
+
search: uri.query, # id=30&limit=5
|
282
|
+
httpAcceptLanguage: request.env["HTTP_ACCEPT_LANGUAGE"]
|
283
|
+
)
|
284
|
+
end
|
285
|
+
if ReactOnRails.configuration.rendering_extension
|
286
|
+
custom_context = ReactOnRails.configuration.rendering_extension.custom_context(self)
|
287
|
+
result.merge!(custom_context) if custom_context
|
288
|
+
end
|
289
|
+
result
|
290
|
+
end
|
291
|
+
|
292
|
+
@rails_context.merge(serverSide: server_side)
|
293
|
+
end
|
294
|
+
# rubocop:enable Metrics/AbcSize
|
295
|
+
|
280
296
|
private
|
281
297
|
|
282
298
|
def build_react_component_result_for_server_rendered_string(
|
@@ -286,9 +302,15 @@ module ReactOnRails
|
|
286
302
|
render_options: required("render_options")
|
287
303
|
)
|
288
304
|
content_tag_options = render_options.html_options
|
305
|
+
if content_tag_options.key?(:tag)
|
306
|
+
content_tag_options_html_tag = content_tag_options[:tag]
|
307
|
+
content_tag_options.delete(:tag)
|
308
|
+
else
|
309
|
+
content_tag_options_html_tag = "div"
|
310
|
+
end
|
289
311
|
content_tag_options[:id] = render_options.dom_id
|
290
312
|
|
291
|
-
rendered_output = content_tag(
|
313
|
+
rendered_output = content_tag(content_tag_options_html_tag.to_sym,
|
292
314
|
server_rendered_html.html_safe,
|
293
315
|
content_tag_options)
|
294
316
|
|
@@ -336,13 +358,11 @@ module ReactOnRails
|
|
336
358
|
|
337
359
|
def compose_react_component_html_with_spec_and_console(component_specification_tag, rendered_output, console_script)
|
338
360
|
# IMPORTANT: Ensure that we mark string as html_safe to avoid escaping.
|
339
|
-
|
340
|
-
|
341
|
-
#{
|
342
|
-
|
343
|
-
#{console_script}
|
361
|
+
<<~HTML.html_safe
|
362
|
+
#{rendered_output}
|
363
|
+
#{component_specification_tag}
|
364
|
+
#{console_script}
|
344
365
|
HTML
|
345
|
-
# rubocop:enable Layout/IndentHeredoc
|
346
366
|
end
|
347
367
|
|
348
368
|
# prepend the rails_context if not yet applied
|
@@ -488,73 +508,10 @@ module ReactOnRails
|
|
488
508
|
result
|
489
509
|
end
|
490
510
|
|
491
|
-
# This is the definitive list of the default values used for the rails_context, which is the
|
492
|
-
# second parameter passed to both component and store generator functions.
|
493
|
-
# rubocop:disable Metrics/AbcSize
|
494
|
-
def rails_context(server_side: required("server_side"))
|
495
|
-
@rails_context ||= begin
|
496
|
-
result = {
|
497
|
-
railsEnv: Rails.env,
|
498
|
-
inMailer: in_mailer?,
|
499
|
-
# Locale settings
|
500
|
-
i18nLocale: I18n.locale,
|
501
|
-
i18nDefaultLocale: I18n.default_locale,
|
502
|
-
rorVersion: ReactOnRails::VERSION,
|
503
|
-
rorPro: ReactOnRails::Utils.react_on_rails_pro?
|
504
|
-
}
|
505
|
-
if defined?(request) && request.present?
|
506
|
-
# Check for encoding of the request's original_url and try to force-encoding the
|
507
|
-
# URLs as UTF-8. This situation can occur in browsers that do not encode the
|
508
|
-
# entire URL as UTF-8 already, mostly on the Windows platform (IE11 and lower).
|
509
|
-
original_url_normalized = request.original_url
|
510
|
-
if original_url_normalized.encoding.to_s == "ASCII-8BIT"
|
511
|
-
original_url_normalized = original_url_normalized.force_encoding("ISO-8859-1").encode("UTF-8")
|
512
|
-
end
|
513
|
-
|
514
|
-
# Using Addressable instead of standard URI to better deal with
|
515
|
-
# non-ASCII characters (see https://github.com/shakacode/react_on_rails/pull/405)
|
516
|
-
uri = Addressable::URI.parse(original_url_normalized)
|
517
|
-
# uri = Addressable::URI.parse("http://foo.com:3000/posts?id=30&limit=5#time=1305298413")
|
518
|
-
|
519
|
-
result.merge!(
|
520
|
-
# URL settings
|
521
|
-
href: uri.to_s,
|
522
|
-
location: "#{uri.path}#{uri.query.present? ? "?#{uri.query}" : ''}",
|
523
|
-
scheme: uri.scheme, # http
|
524
|
-
host: uri.host, # foo.com
|
525
|
-
port: uri.port,
|
526
|
-
pathname: uri.path, # /posts
|
527
|
-
search: uri.query, # id=30&limit=5
|
528
|
-
httpAcceptLanguage: request.env["HTTP_ACCEPT_LANGUAGE"]
|
529
|
-
)
|
530
|
-
end
|
531
|
-
if ReactOnRails.configuration.rendering_extension
|
532
|
-
custom_context = ReactOnRails.configuration.rendering_extension.custom_context(self)
|
533
|
-
result.merge!(custom_context) if custom_context
|
534
|
-
end
|
535
|
-
result
|
536
|
-
end
|
537
|
-
|
538
|
-
@rails_context.merge(serverSide: server_side)
|
539
|
-
end
|
540
|
-
|
541
|
-
# rubocop:enable Metrics/AbcSize
|
542
|
-
|
543
511
|
def replay_console_option(val)
|
544
512
|
val.nil? ? ReactOnRails.configuration.replay_console : val
|
545
513
|
end
|
546
514
|
|
547
|
-
def use_hot_reloading?
|
548
|
-
ENV["REACT_ON_RAILS_ENV"] == "HOT"
|
549
|
-
end
|
550
|
-
|
551
|
-
def send_tag_method(tag_method_name, args)
|
552
|
-
asset_type = use_hot_reloading? ? :hot : :static
|
553
|
-
assets = Array(args[asset_type])
|
554
|
-
options = args.delete_if { |key, _value| %i[hot static].include?(key) }
|
555
|
-
send(tag_method_name, *assets, options) unless assets.empty?
|
556
|
-
end
|
557
|
-
|
558
515
|
def in_mailer?
|
559
516
|
return false unless defined?(controller)
|
560
517
|
return false unless defined?(ActionMailer::Base)
|