react_on_rails 11.1.4 → 12.0.0
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 +30 -2
- data/.github/FUNDING.yml +1 -0
- data/.gitignore +3 -1
- data/.prettierignore +10 -0
- data/.prettierrc +23 -0
- data/.release-it.json +3 -0
- data/.rubocop.yml +37 -11
- data/.travis.yml +10 -20
- data/CHANGELOG.md +126 -4
- data/CONTRIBUTING.md +61 -80
- data/Gemfile +3 -5
- data/KUDOS.md +4 -1
- data/REACT-ON-RAILS-PRO-LICENSE +95 -0
- data/README.md +148 -89
- data/Rakefile +0 -7
- data/SUMMARY.md +12 -12
- data/book.json +5 -5
- data/docs/additional-reading/asset-pipeline.md +8 -16
- data/docs/additional-reading/images.md +1 -1
- data/docs/additional-reading/rails_view_rendering_from_inline_javascript.md +2 -1
- 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/additional-reading/upgrade-webpacker-v3-to-v4.md +10 -0
- data/docs/api/javascript-api.md +3 -3
- data/docs/api/redux-store-api.md +4 -2
- data/docs/api/view-helpers-api.md +17 -14
- data/docs/basics/client-vs-server-rendering.md +8 -2
- data/docs/basics/configuration.md +87 -73
- data/docs/basics/deployment.md +2 -4
- data/docs/basics/generator-details.md +1 -1
- 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/minitest-configuration.md +31 -0
- data/docs/basics/react-server-rendering.md +3 -1
- data/docs/basics/recommended-project-structure.md +21 -15
- data/docs/basics/{generator-functions-and-railscontext.md → render-functions-and-railscontext.md} +59 -21
- data/docs/basics/rspec-configuration.md +29 -18
- data/docs/basics/upgrading-react-on-rails.md +74 -3
- data/docs/basics/webpack-configuration.md +29 -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 +13 -9
- 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/testimonials/hvmn.md +25 -0
- data/docs/testimonials/resortpass.md +13 -0
- data/docs/testimonials/testimonials.md +28 -0
- data/docs/tutorial.md +182 -44
- 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 +2 -1
- data/lib/generators/react_on_rails/generator_helper.rb +4 -6
- data/lib/generators/react_on_rails/install_generator.rb +2 -0
- 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/configuration.rb +60 -29
- data/lib/react_on_rails/error.rb +2 -0
- data/lib/react_on_rails/git_utils.rb +2 -0
- data/lib/react_on_rails/helper.rb +110 -159
- data/lib/react_on_rails/json_output.rb +1 -1
- 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_js_code.rb +42 -0
- data/lib/react_on_rails/server_rendering_pool/ruby_embedded_java_script.rb +85 -60
- 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 +19 -20
- data/lib/react_on_rails/version.rb +1 -1
- data/lib/react_on_rails/version_checker.rb +5 -1
- data/lib/react_on_rails/webpacker_utils.rb +27 -2
- data/lib/react_on_rails.rb +4 -1
- data/lib/tasks/assets.rake +33 -46
- data/lib/tasks/locale.rake +4 -2
- data/package-scripts.yml +49 -0
- data/package.json +41 -31
- 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 +3 -8
- data/rakelib/run_rspec.rake +5 -18
- data/react_on_rails.gemspec +4 -5
- data/tsconfig.json +14 -0
- data/webpackConfigLoader.js +5 -4
- data/yarn.lock +7177 -2311
- metadata +54 -55
- data/Gemfile.rails32 +0 -74
- 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.md +0 -57
- data/docs/api/ruby-api-hot-reload-view-helpers.md +0 -44
- data/docs/testimonials.md +0 -11
- data/lib/generators/react_on_rails/templates/base/base/Procfile.dev-server +0 -12
- data/lib/react_on_rails/assets_precompile.rb +0 -150
- data/lib/react_on_rails/locales_to_js.rb +0 -134
- /data/docs/{misc → outdated}/rails3.md +0 -0
|
@@ -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
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ReactOnRails
|
|
4
|
+
module ServerRenderingJsCode
|
|
5
|
+
class << self
|
|
6
|
+
def js_code_renderer
|
|
7
|
+
@js_code_renderer ||= if ReactOnRails::Utils.react_on_rails_pro?
|
|
8
|
+
ReactOnRailsPro::ServerRenderingJsCode
|
|
9
|
+
else
|
|
10
|
+
self
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def server_rendering_component_js_code(
|
|
15
|
+
props_string: nil,
|
|
16
|
+
rails_context: nil,
|
|
17
|
+
redux_stores: nil,
|
|
18
|
+
react_component_name: nil,
|
|
19
|
+
render_options: nil
|
|
20
|
+
)
|
|
21
|
+
js_code_renderer.render(props_string, rails_context, redux_stores, react_component_name, render_options)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def render(props_string, rails_context, redux_stores, react_component_name, render_options)
|
|
25
|
+
<<-JS
|
|
26
|
+
(function() {
|
|
27
|
+
var railsContext = #{rails_context};
|
|
28
|
+
#{redux_stores}
|
|
29
|
+
var props = #{props_string};
|
|
30
|
+
return ReactOnRails.serverRenderReactComponent({
|
|
31
|
+
name: '#{react_component_name}',
|
|
32
|
+
domNodeId: '#{render_options.dom_id}',
|
|
33
|
+
props: props,
|
|
34
|
+
trace: #{render_options.trace},
|
|
35
|
+
railsContext: railsContext
|
|
36
|
+
});
|
|
37
|
+
})()
|
|
38
|
+
JS
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -1,10 +1,13 @@
|
|
|
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
|
|
8
|
+
# rubocop:disable Metrics/ClassLength
|
|
7
9
|
class RubyEmbeddedJavaScript
|
|
10
|
+
# rubocop:enable Metrics/ClassLength
|
|
8
11
|
class << self
|
|
9
12
|
def reset_pool
|
|
10
13
|
options = {
|
|
@@ -17,12 +20,17 @@ module ReactOnRails
|
|
|
17
20
|
def reset_pool_if_server_bundle_was_modified
|
|
18
21
|
return unless ReactOnRails.configuration.development_mode
|
|
19
22
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
return if @server_bundle_timestamp == file_mtime
|
|
23
|
+
if ReactOnRails::Utils.server_bundle_path_is_http?
|
|
24
|
+
return if @server_bundle_url == ReactOnRails::Utils.server_bundle_js_file_path
|
|
23
25
|
|
|
24
|
-
|
|
26
|
+
@server_bundle_url = ReactOnRails::Utils.server_bundle_js_file_path
|
|
27
|
+
else
|
|
28
|
+
file_mtime = File.mtime(ReactOnRails::Utils.server_bundle_js_file_path)
|
|
29
|
+
@server_bundle_timestamp ||= file_mtime
|
|
30
|
+
return if @server_bundle_timestamp == file_mtime
|
|
25
31
|
|
|
32
|
+
@server_bundle_timestamp = file_mtime
|
|
33
|
+
end
|
|
26
34
|
ReactOnRails::ServerRenderingPool.reset_pool
|
|
27
35
|
end
|
|
28
36
|
|
|
@@ -72,6 +80,7 @@ module ReactOnRails
|
|
|
72
80
|
|
|
73
81
|
def trace_js_code_used(msg, js_code, file_name = "tmp/server-generated.js", force: false)
|
|
74
82
|
return unless ReactOnRails.configuration.trace || force
|
|
83
|
+
|
|
75
84
|
# Set to anything to print generated code.
|
|
76
85
|
File.write(file_name, js_code)
|
|
77
86
|
msg = <<-MSG.strip_heredoc
|
|
@@ -95,30 +104,37 @@ module ReactOnRails
|
|
|
95
104
|
end
|
|
96
105
|
end
|
|
97
106
|
|
|
98
|
-
def
|
|
99
|
-
return if ReactOnRails.configuration.server_bundle_js_file.blank?
|
|
100
|
-
|
|
107
|
+
def read_bundle_js_code
|
|
101
108
|
server_js_file = ReactOnRails::Utils.server_bundle_js_file_path
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
109
|
+
if ReactOnRails::Utils.server_bundle_path_is_http?
|
|
110
|
+
file_url_to_string(server_js_file)
|
|
111
|
+
else
|
|
112
|
+
File.read(server_js_file)
|
|
113
|
+
end
|
|
114
|
+
rescue StandardError => e
|
|
115
|
+
msg = "You specified server rendering JS file: #{server_js_file}, but it cannot be "\
|
|
107
116
|
"read. You may set the server_bundle_js_file in your configuration to be \"\" to "\
|
|
108
117
|
"avoid this warning.\nError is: #{e}"
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
118
|
+
raise ReactOnRails::Error, msg
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def create_js_context
|
|
122
|
+
return if ReactOnRails.configuration.server_bundle_js_file.blank?
|
|
123
|
+
|
|
124
|
+
bundle_js_code = read_bundle_js_code
|
|
125
|
+
base_js_code = <<~JS
|
|
126
|
+
#{console_polyfill}
|
|
127
|
+
#{execjs_timer_polyfills}
|
|
128
|
+
#{bundle_js_code};
|
|
116
129
|
JS
|
|
117
|
-
|
|
130
|
+
|
|
118
131
|
file_name = "tmp/base_js_code.js"
|
|
119
132
|
begin
|
|
120
133
|
if ReactOnRails.configuration.trace
|
|
121
|
-
Rails.logger.info
|
|
134
|
+
Rails.logger.info do
|
|
135
|
+
"[react_on_rails] Created JavaScript context with file "\
|
|
136
|
+
"#{ReactOnRails::Utils.server_bundle_js_file_path}"
|
|
137
|
+
end
|
|
122
138
|
end
|
|
123
139
|
ExecJS.compile(base_js_code)
|
|
124
140
|
rescue StandardError => e
|
|
@@ -134,33 +150,31 @@ module ReactOnRails
|
|
|
134
150
|
end
|
|
135
151
|
|
|
136
152
|
def execjs_timer_polyfills
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
}
|
|
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
|
+
}
|
|
162
177
|
JS
|
|
163
|
-
# rubocop:enable Layout/IndentHeredoc
|
|
164
178
|
end
|
|
165
179
|
|
|
166
180
|
def undefined_for_exec_js_logging(function_name)
|
|
@@ -174,20 +188,31 @@ function clearTimeout() {
|
|
|
174
188
|
|
|
175
189
|
# Reimplement console methods for replaying on the client
|
|
176
190
|
def console_polyfill
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
[
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
});
|
|
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
|
+
});
|
|
189
202
|
JS
|
|
190
|
-
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
private
|
|
206
|
+
|
|
207
|
+
def file_url_to_string(url)
|
|
208
|
+
response = Net::HTTP.get_response(URI.parse(url))
|
|
209
|
+
content_type_header = response["content-type"]
|
|
210
|
+
match = content_type_header.match(/\A.*; charset=(?<encoding>.*)\z/)
|
|
211
|
+
encoding_type = match[:encoding]
|
|
212
|
+
response.body.force_encoding(encoding_type)
|
|
213
|
+
rescue StandardError => e
|
|
214
|
+
msg = "file_url_to_string #{url} failed\nError is: #{e}"
|
|
215
|
+
raise ReactOnRails::Error, msg
|
|
191
216
|
end
|
|
192
217
|
end
|
|
193
218
|
end
|
|
@@ -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(
|
data/lib/react_on_rails/utils.rb
CHANGED
|
@@ -8,7 +8,7 @@ require "active_support/core_ext/string"
|
|
|
8
8
|
|
|
9
9
|
module ReactOnRails
|
|
10
10
|
module Utils
|
|
11
|
-
TRUNCATION_FILLER = "\n... TRUNCATED ...\n"
|
|
11
|
+
TRUNCATION_FILLER = "\n... TRUNCATED ...\n"
|
|
12
12
|
|
|
13
13
|
# https://forum.shakacode.com/t/yak-of-the-week-ruby-2-4-pathname-empty-changed-to-look-at-file-size/901
|
|
14
14
|
# return object if truthy, else return nil
|
|
@@ -24,13 +24,12 @@ module ReactOnRails
|
|
|
24
24
|
# Pass in the msg and color as a symbol.
|
|
25
25
|
def self.wrap_message(msg, color = :red)
|
|
26
26
|
wrapper_line = ("=" * 80).to_s
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
#{
|
|
30
|
-
#{
|
|
31
|
-
#{wrapper_line}
|
|
27
|
+
fenced_msg = <<~MSG
|
|
28
|
+
#{wrapper_line}
|
|
29
|
+
#{msg.strip}
|
|
30
|
+
#{wrapper_line}
|
|
32
31
|
MSG
|
|
33
|
-
|
|
32
|
+
|
|
34
33
|
Rainbow(fenced_msg).color(color)
|
|
35
34
|
end
|
|
36
35
|
|
|
@@ -48,14 +47,13 @@ module ReactOnRails
|
|
|
48
47
|
unless status.success?
|
|
49
48
|
stdout_msg = stdout.present? ? "\nstdout:\n#{stdout.strip}\n" : ""
|
|
50
49
|
stderr_msg = stderr.present? ? "\nstderr:\n#{stderr.strip}\n" : ""
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
#{
|
|
55
|
-
|
|
56
|
-
exitstatus: #{status.exitstatus}#{stdout_msg}#{stderr_msg}
|
|
50
|
+
msg = <<~MSG
|
|
51
|
+
React on Rails FATAL ERROR!
|
|
52
|
+
#{failure_message}
|
|
53
|
+
cmd: #{cmd}
|
|
54
|
+
exitstatus: #{status.exitstatus}#{stdout_msg}#{stderr_msg}
|
|
57
55
|
MSG
|
|
58
|
-
|
|
56
|
+
|
|
59
57
|
puts wrap_message(msg)
|
|
60
58
|
|
|
61
59
|
# Rspec catches exit without! in the exit callbacks
|
|
@@ -64,15 +62,16 @@ exitstatus: #{status.exitstatus}#{stdout_msg}#{stderr_msg}
|
|
|
64
62
|
[stdout, stderr, status]
|
|
65
63
|
end
|
|
66
64
|
|
|
65
|
+
def self.server_bundle_path_is_http?
|
|
66
|
+
server_bundle_js_file_path =~ %r{https?://}
|
|
67
|
+
end
|
|
68
|
+
|
|
67
69
|
def self.server_bundle_js_file_path
|
|
68
70
|
# Either:
|
|
69
71
|
# 1. Using same bundle for both server and client, so server bundle will be hashed in manifest
|
|
70
72
|
# 2. Using a different bundle (different Webpack config), so file is not hashed, and
|
|
71
|
-
# bundle_js_path will throw.
|
|
72
|
-
# 3. Not using webpacker, and
|
|
73
|
-
|
|
74
|
-
# Note, server bundle should not be in the manifest
|
|
75
|
-
# If using webpacker gem per https://github.com/rails/webpacker/issues/571
|
|
73
|
+
# bundle_js_path will throw so the default path is used without a hash.
|
|
74
|
+
# 3. Not using webpacker, and this method returns the bundle_js_file_path
|
|
76
75
|
return @server_bundle_path if @server_bundle_path && !Rails.env.development?
|
|
77
76
|
|
|
78
77
|
bundle_name = ReactOnRails.configuration.server_bundle_js_file
|
|
@@ -92,7 +91,7 @@ exitstatus: #{status.exitstatus}#{stdout_msg}#{stderr_msg}
|
|
|
92
91
|
|
|
93
92
|
def self.bundle_js_file_path(bundle_name)
|
|
94
93
|
if ReactOnRails::WebpackerUtils.using_webpacker? && bundle_name != "manifest.json"
|
|
95
|
-
ReactOnRails::WebpackerUtils.
|
|
94
|
+
ReactOnRails::WebpackerUtils.bundle_js_uri_from_webpacker(bundle_name)
|
|
96
95
|
else
|
|
97
96
|
# Default to the non-hashed name in the specified output directory, which, for legacy
|
|
98
97
|
# React on Rails, this is the output directory picked up by the asset pipeline.
|