react_on_rails 11.3.0 → 12.0.0.pre.beta.4
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 +9 -22
- data/CHANGELOG.md +65 -6
- data/CONTRIBUTING.md +60 -71
- data/Gemfile +3 -4
- data/{COMM-LICENSE → REACT-ON-RAILS-PRO-LICENSE} +6 -9
- data/README.md +129 -92
- data/Rakefile +0 -7
- data/SUMMARY.md +7 -11
- 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 +6 -7
- data/docs/basics/configuration.md +83 -69
- data/docs/basics/deployment.md +2 -4
- data/docs/basics/heroku-deployment.md +24 -0
- data/docs/basics/hmr-and-hot-reloading-with-the-webpack-dev-server.md +49 -0
- data/docs/basics/i18n.md +45 -23
- data/docs/basics/installation-into-an-existing-rails-app.md +4 -9
- data/docs/basics/react-server-rendering.md +1 -1
- data/docs/basics/recommended-project-structure.md +5 -22
- data/docs/basics/{generator-functions-and-railscontext.md → render-functions-and-railscontext.md} +59 -21
- data/docs/basics/rspec-configuration.md +27 -16
- data/docs/basics/upgrading-react-on-rails.md +58 -2
- data/docs/basics/webpack-configuration.md +18 -8
- 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/{basics → outdated}/how-react-on-rails-works.md +8 -4
- 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 +2 -12
- data/docs/{misc → outdated}/rails3.md +0 -0
- data/docs/tutorial.md +94 -68
- 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 +4 -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 +58 -28
- data/lib/react_on_rails/error.rb +2 -0
- data/lib/react_on_rails/helper.rb +41 -91
- 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/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/test_helper/webpack_assets_compiler.rb +17 -0
- 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 +19 -2
- data/lib/tasks/assets.rake +33 -46
- 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 +4 -5
- data/tsconfig.json +14 -0
- data/webpackConfigLoader.js +3 -2
- data/yarn.lock +4333 -2209
- metadata +46 -57
- data/Gemfile.rails32 +0 -73
- data/docs/additional-reading/babel.md +0 -5
- data/docs/additional-reading/heroku-deployment.md +0 -92
- 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
@@ -0,0 +1,150 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "erb"
|
4
|
+
|
5
|
+
module ReactOnRails
|
6
|
+
module Locales
|
7
|
+
def self.compile
|
8
|
+
if ReactOnRails.configuration.i18n_output_format&.downcase == "js"
|
9
|
+
ReactOnRails::Locales::ToJs.new
|
10
|
+
else
|
11
|
+
ReactOnRails::Locales::ToJson.new
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class Base
|
16
|
+
def initialize
|
17
|
+
return if i18n_dir.nil?
|
18
|
+
return unless obsolete?
|
19
|
+
|
20
|
+
@translations, @defaults = generate_translations
|
21
|
+
convert
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def file_format; end
|
27
|
+
|
28
|
+
def obsolete?
|
29
|
+
return true if exist_files.empty?
|
30
|
+
|
31
|
+
files_are_outdated
|
32
|
+
end
|
33
|
+
|
34
|
+
def exist_files
|
35
|
+
@exist_files ||= files.select(&File.method(:exist?))
|
36
|
+
end
|
37
|
+
|
38
|
+
def files_are_outdated
|
39
|
+
latest_yml = locale_files.map(&File.method(:mtime)).max
|
40
|
+
earliest = exist_files.map(&File.method(:mtime)).min
|
41
|
+
latest_yml > earliest
|
42
|
+
end
|
43
|
+
|
44
|
+
def file_names
|
45
|
+
%w[translations default]
|
46
|
+
end
|
47
|
+
|
48
|
+
def files
|
49
|
+
@files ||= file_names.map { |n| file(n) }
|
50
|
+
end
|
51
|
+
|
52
|
+
def file(name)
|
53
|
+
"#{i18n_dir}/#{name}.#{file_format}"
|
54
|
+
end
|
55
|
+
|
56
|
+
def locale_files
|
57
|
+
@locale_files ||= begin
|
58
|
+
if i18n_yml_dir.present?
|
59
|
+
Dir["#{i18n_yml_dir}/**/*.yml"]
|
60
|
+
else
|
61
|
+
ReactOnRails::Utils.truthy_presence(
|
62
|
+
Rails.application && Rails.application.config.i18n.load_path
|
63
|
+
).presence
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def i18n_dir
|
69
|
+
@i18n_dir ||= ReactOnRails.configuration.i18n_dir
|
70
|
+
end
|
71
|
+
|
72
|
+
def i18n_yml_dir
|
73
|
+
@i18n_yml_dir ||= ReactOnRails.configuration.i18n_yml_dir
|
74
|
+
end
|
75
|
+
|
76
|
+
def default_locale
|
77
|
+
@default_locale ||= I18n.default_locale.to_s || "en"
|
78
|
+
end
|
79
|
+
|
80
|
+
def convert
|
81
|
+
file_names.each do |name|
|
82
|
+
template = send("template_#{name}")
|
83
|
+
path = file(name)
|
84
|
+
generate_file(template, path)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def generate_file(template, path)
|
89
|
+
result = ERB.new(template).result()
|
90
|
+
File.open(path, "w") do |f|
|
91
|
+
f.write(result)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def generate_translations
|
96
|
+
translations = {}
|
97
|
+
defaults = {}
|
98
|
+
locale_files.each do |f|
|
99
|
+
translation = YAML.safe_load(File.open(f))
|
100
|
+
key = translation.keys[0]
|
101
|
+
val = flatten(translation[key])
|
102
|
+
translations = translations.deep_merge(key => val)
|
103
|
+
defaults = defaults.deep_merge(flatten_defaults(val)) if key == default_locale
|
104
|
+
end
|
105
|
+
[translations.to_json, defaults.to_json]
|
106
|
+
end
|
107
|
+
|
108
|
+
def format(input)
|
109
|
+
input.to_s.tr(".", "_").camelize(:lower).to_sym
|
110
|
+
end
|
111
|
+
|
112
|
+
def flatten_defaults(val)
|
113
|
+
flatten(val).each_with_object({}) do |(k, v), h|
|
114
|
+
key = format(k)
|
115
|
+
h[key] = { id: k, defaultMessage: v }
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def flatten(translations)
|
120
|
+
translations.each_with_object({}) do |(k, v), h|
|
121
|
+
if v.is_a? Hash
|
122
|
+
flatten(v).map { |hk, hv| h["#{k}.#{hk}".to_sym] = hv }
|
123
|
+
elsif v.is_a?(String)
|
124
|
+
h[k] = v.gsub("%{", "{")
|
125
|
+
elsif !v.is_a?(Array)
|
126
|
+
h[k] = v
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def template_translations
|
132
|
+
<<-JS.strip_heredoc
|
133
|
+
export const translations = #{@translations};
|
134
|
+
JS
|
135
|
+
end
|
136
|
+
|
137
|
+
def template_default
|
138
|
+
<<-JS.strip_heredoc
|
139
|
+
import { defineMessages } from 'react-intl';
|
140
|
+
|
141
|
+
const defaultLocale = \'#{default_locale}\';
|
142
|
+
|
143
|
+
const defaultMessages = defineMessages(#{@defaults});
|
144
|
+
|
145
|
+
export { defaultMessages, defaultLocale };
|
146
|
+
JS
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "erb"
|
4
|
+
|
5
|
+
module ReactOnRails
|
6
|
+
module Locales
|
7
|
+
class ToJs < Base
|
8
|
+
def initialize
|
9
|
+
super
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def file_format
|
15
|
+
"js"
|
16
|
+
end
|
17
|
+
|
18
|
+
def template_translations
|
19
|
+
<<-JS.strip_heredoc
|
20
|
+
export const translations = #{@translations};
|
21
|
+
JS
|
22
|
+
end
|
23
|
+
|
24
|
+
def template_default
|
25
|
+
<<-JS.strip_heredoc
|
26
|
+
import { defineMessages } from 'react-intl';
|
27
|
+
|
28
|
+
const defaultLocale = \'#{default_locale}\';
|
29
|
+
|
30
|
+
const defaultMessages = defineMessages(#{@defaults});
|
31
|
+
|
32
|
+
export { defaultMessages, defaultLocale };
|
33
|
+
JS
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "erb"
|
4
|
+
|
5
|
+
module ReactOnRails
|
6
|
+
module Locales
|
7
|
+
class ToJson < Base
|
8
|
+
def initialize
|
9
|
+
super
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def file_format
|
15
|
+
"json"
|
16
|
+
end
|
17
|
+
|
18
|
+
def template_translations
|
19
|
+
@translations
|
20
|
+
end
|
21
|
+
|
22
|
+
def template_default
|
23
|
+
@defaults
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -48,33 +48,29 @@ module ReactOnRails
|
|
48
48
|
def calc_message(component_name, console_messages, err, js_code, props)
|
49
49
|
message = "ERROR in SERVER PRERENDERING\n".dup
|
50
50
|
if err
|
51
|
-
|
52
|
-
|
53
|
-
Encountered error: \"#{err}\"
|
51
|
+
message << <<~MSG
|
52
|
+
Encountered error: \"#{err}\"
|
54
53
|
MSG
|
55
|
-
|
54
|
+
|
56
55
|
backtrace = err.backtrace.join("\n")
|
57
56
|
else
|
58
57
|
backtrace = nil
|
59
58
|
end
|
60
|
-
|
61
|
-
|
62
|
-
when prerendering #{component_name} with props: #{Utils.smart_trim(props, MAX_ERROR_SNIPPET_TO_LOG)}
|
59
|
+
message << <<~MSG
|
60
|
+
when prerendering #{component_name} with props: #{Utils.smart_trim(props, MAX_ERROR_SNIPPET_TO_LOG)}
|
63
61
|
|
64
|
-
code:
|
62
|
+
code:
|
65
63
|
|
66
|
-
#{Utils.smart_trim(js_code, MAX_ERROR_SNIPPET_TO_LOG)}
|
64
|
+
#{Utils.smart_trim(js_code, MAX_ERROR_SNIPPET_TO_LOG)}
|
67
65
|
|
68
66
|
MSG
|
69
|
-
# rubocop:enable Layout/IndentHeredoc
|
70
67
|
|
71
68
|
if console_messages
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
#{console_messages}
|
69
|
+
message << <<~MSG
|
70
|
+
console messages:
|
71
|
+
#{console_messages}
|
76
72
|
MSG
|
77
|
-
|
73
|
+
|
78
74
|
end
|
79
75
|
[backtrace, message]
|
80
76
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "open-uri"
|
4
|
+
require "execjs"
|
4
5
|
|
5
6
|
module ReactOnRails
|
6
7
|
module ServerRenderingPool
|
@@ -121,14 +122,12 @@ module ReactOnRails
|
|
121
122
|
return if ReactOnRails.configuration.server_bundle_js_file.blank?
|
122
123
|
|
123
124
|
bundle_js_code = read_bundle_js_code
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
#{
|
128
|
-
#{execjs_timer_polyfills}
|
129
|
-
#{bundle_js_code};
|
125
|
+
base_js_code = <<~JS
|
126
|
+
#{console_polyfill}
|
127
|
+
#{execjs_timer_polyfills}
|
128
|
+
#{bundle_js_code};
|
130
129
|
JS
|
131
|
-
|
130
|
+
|
132
131
|
file_name = "tmp/base_js_code.js"
|
133
132
|
begin
|
134
133
|
if ReactOnRails.configuration.trace
|
@@ -151,33 +150,31 @@ module ReactOnRails
|
|
151
150
|
end
|
152
151
|
|
153
152
|
def execjs_timer_polyfills
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
}
|
153
|
+
<<~JS
|
154
|
+
function getStackTrace () {
|
155
|
+
var stack;
|
156
|
+
try {
|
157
|
+
throw new Error('');
|
158
|
+
}
|
159
|
+
catch (error) {
|
160
|
+
stack = error.stack || '';
|
161
|
+
}
|
162
|
+
stack = stack.split('\\n').map(function (line) { return line.trim(); });
|
163
|
+
return stack.splice(stack[0] == 'Error' ? 2 : 1);
|
164
|
+
}
|
165
|
+
|
166
|
+
function setInterval() {
|
167
|
+
#{undefined_for_exec_js_logging('setInterval')}
|
168
|
+
}
|
169
|
+
|
170
|
+
function setTimeout() {
|
171
|
+
#{undefined_for_exec_js_logging('setTimeout')}
|
172
|
+
}
|
173
|
+
|
174
|
+
function clearTimeout() {
|
175
|
+
#{undefined_for_exec_js_logging('clearTimeout')}
|
176
|
+
}
|
179
177
|
JS
|
180
|
-
# rubocop:enable Layout/IndentHeredoc
|
181
178
|
end
|
182
179
|
|
183
180
|
def undefined_for_exec_js_logging(function_name)
|
@@ -191,20 +188,18 @@ function clearTimeout() {
|
|
191
188
|
|
192
189
|
# Reimplement console methods for replaying on the client
|
193
190
|
def console_polyfill
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
[
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
});
|
191
|
+
<<~JS
|
192
|
+
var console = { history: [] };
|
193
|
+
['error', 'log', 'info', 'warn'].forEach(function (level) {
|
194
|
+
console[level] = function () {
|
195
|
+
var argArray = Array.prototype.slice.call(arguments);
|
196
|
+
if (argArray.length > 0) {
|
197
|
+
argArray[0] = '[SERVER] ' + argArray[0];
|
198
|
+
}
|
199
|
+
console.history.push({level: level, arguments: argArray});
|
200
|
+
};
|
201
|
+
});
|
206
202
|
JS
|
207
|
-
# rubocop:enable Layout/IndentHeredoc
|
208
203
|
end
|
209
204
|
|
210
205
|
private
|
@@ -5,6 +5,7 @@ module ReactOnRails
|
|
5
5
|
class EnsureAssetsCompiled
|
6
6
|
class << self
|
7
7
|
attr_accessor :has_been_run
|
8
|
+
|
8
9
|
@has_been_run = false
|
9
10
|
end
|
10
11
|
|
@@ -29,7 +30,7 @@ module ReactOnRails
|
|
29
30
|
# Be sure we don't do this again.
|
30
31
|
self.class.has_been_run = true
|
31
32
|
|
32
|
-
ReactOnRails::
|
33
|
+
ReactOnRails::Locales.compile
|
33
34
|
|
34
35
|
stale_gen_files = webpack_assets_status_checker.stale_generated_webpack_files
|
35
36
|
|
@@ -43,17 +44,15 @@ module ReactOnRails
|
|
43
44
|
end
|
44
45
|
|
45
46
|
def puts_start_compile_check_message(stale_files)
|
46
|
-
|
47
|
-
puts <<-MSG
|
47
|
+
puts <<~MSG
|
48
48
|
|
49
|
-
Detected the following stale generated files:
|
50
|
-
|
49
|
+
Detected the following stale generated files:
|
50
|
+
#{stale_files.join("\n ")}
|
51
51
|
|
52
|
-
React on Rails will ensure your JavaScript generated files are up to date, using your
|
53
|
-
`#{ReactOnRails::Utils.prepend_cd_node_modules_directory(ReactOnRails.configuration.build_test_command)}` command.
|
52
|
+
React on Rails will ensure your JavaScript generated files are up to date, using your
|
53
|
+
`#{ReactOnRails::Utils.prepend_cd_node_modules_directory(ReactOnRails.configuration.build_test_command)}` command.
|
54
54
|
|
55
55
|
MSG
|
56
|
-
# rubocop:enable Layout/IndentHeredoc
|
57
56
|
end
|
58
57
|
end
|
59
58
|
end
|
@@ -6,6 +6,23 @@ module ReactOnRails
|
|
6
6
|
module TestHelper
|
7
7
|
class WebpackAssetsCompiler
|
8
8
|
def compile_assets
|
9
|
+
if ReactOnRails.configuration.build_test_command.blank?
|
10
|
+
msg = <<~MSG
|
11
|
+
You are using the React on Rails test helper.
|
12
|
+
Either you used:
|
13
|
+
ReactOnRails::TestHelper.configure_rspec_to_compile_assets or
|
14
|
+
ReactOnRails::TestHelper.ensure_assets_compiled
|
15
|
+
but you did not specify the config.build_test_command
|
16
|
+
|
17
|
+
React on Rails is aborting your test run
|
18
|
+
|
19
|
+
If you wish to use the config/webpacker.yml compile option for tests
|
20
|
+
them remove your call to the ReactOnRails test helper.
|
21
|
+
MSG
|
22
|
+
puts Rainbow(msg).red
|
23
|
+
exit!(1)
|
24
|
+
end
|
25
|
+
|
9
26
|
puts "\nBuilding Webpack assets..."
|
10
27
|
|
11
28
|
cmd = ReactOnRails::Utils.prepend_cd_node_modules_directory(
|