react_on_rails 11.1.8 → 11.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/.eslintrc +8 -2
  3. data/.prettierignore +1 -0
  4. data/.prettierrc +20 -0
  5. data/.release-it.json +3 -0
  6. data/.travis.yml +10 -9
  7. data/CHANGELOG.md +55 -3
  8. data/CONTRIBUTING.md +2 -10
  9. data/Gemfile +1 -2
  10. data/Gemfile.rails32 +0 -1
  11. data/README.md +20 -11
  12. data/SUMMARY.md +3 -1
  13. data/docs/additional-reading/images.md +1 -1
  14. data/docs/additional-reading/rails_view_rendering_from_inline_javascript.md +2 -1
  15. data/docs/additional-reading/upgrade-webpacker-v3-to-v4.md +10 -0
  16. data/docs/api/view-helpers-api.md +12 -8
  17. data/docs/basics/configuration.md +4 -4
  18. data/docs/basics/minitest-configuration.md +31 -0
  19. data/docs/basics/recommended-project-structure.md +1 -1
  20. data/docs/basics/rspec-configuration.md +2 -2
  21. data/docs/basics/upgrading-react-on-rails.md +11 -1
  22. data/docs/misc-pending/code-splitting.md +2 -2
  23. data/docs/testimonials/hvmn.md +3 -3
  24. data/docs/testimonials/resortpass.md +13 -0
  25. data/docs/testimonials/testimonials.md +11 -1
  26. data/docs/tutorial.md +31 -6
  27. data/lib/generators/react_on_rails/dev_tests_generator.rb +1 -0
  28. data/lib/generators/react_on_rails/install_generator.rb +2 -0
  29. data/lib/generators/react_on_rails/templates/dev_tests/spec/rails_helper.rb +8 -1
  30. data/lib/react_on_rails.rb +1 -0
  31. data/lib/react_on_rails/assets_precompile.rb +3 -0
  32. data/lib/react_on_rails/configuration.rb +2 -1
  33. data/lib/react_on_rails/git_utils.rb +2 -0
  34. data/lib/react_on_rails/helper.rb +72 -73
  35. data/lib/react_on_rails/json_output.rb +1 -1
  36. data/lib/react_on_rails/locales_to_js.rb +2 -0
  37. data/lib/react_on_rails/react_component/render_options.rb +4 -0
  38. data/lib/react_on_rails/server_rendering_js_code.rb +42 -0
  39. data/lib/react_on_rails/server_rendering_pool/ruby_embedded_java_script.rb +30 -5
  40. data/lib/react_on_rails/utils.rb +1 -1
  41. data/lib/react_on_rails/version.rb +1 -1
  42. data/lib/react_on_rails/version_checker.rb +4 -1
  43. data/lib/react_on_rails/webpacker_utils.rb +4 -1
  44. data/package-scripts.yml +46 -0
  45. data/package.json +24 -15
  46. data/rakelib/release.rake +3 -2
  47. data/react_on_rails.gemspec +1 -1
  48. data/webpackConfigLoader.js +2 -2
  49. data/yarn.lock +4431 -1689
  50. metadata +13 -6
@@ -0,0 +1,31 @@
1
+ # Minitest Configuration
2
+
3
+ The setup for minitest is the same as for rspec with the following difference.
4
+
5
+ Rather than calling `ReactOnRails::TestHelper.configure_rspec_to_compile_assets(config)`, instead you will do something like this:
6
+
7
+ ```ruby
8
+ class ActiveSupport::TestCase
9
+ setup do
10
+ ReactOnRails::TestHelper.ensure_assets_compiled
11
+ end
12
+ end
13
+ ```
14
+
15
+
16
+ Or maybe something like this, from the [minitest docs](https://github.com/seattlerb/minitest/blob/master/lib/minitest/test.rb#L119):
17
+
18
+ ```ruby
19
+ module MyMinitestPlugin
20
+ def before_setup
21
+ super
22
+ ReactOnRails::TestHelper.ensure_assets_compiled
23
+ end
24
+ end
25
+
26
+ class MiniTest::Test
27
+ include MyMinitestPlugin
28
+ end
29
+ ```
30
+
31
+
@@ -47,7 +47,7 @@ mv app/javascript client
47
47
  `rails/webpacker` probably doesn't support having your main node_modules directory under `/client`, so only follow these steps if you want to use your own webpack configuration (which is highly recommended!).
48
48
 
49
49
  1. Move the `/package.json` to `/client/package.json`
50
- 2. Create a `/pacage.json` that delegates to `/client/package.json`. See the example in [spec/dummy/package.json](../../spec/dummy/package.json).
50
+ 2. Create a `/package.json` that delegates to `/client/package.json`. See the example in [spec/dummy/package.json](../../spec/dummy/package.json).
51
51
  3. See the webpack configuration in [spec/dummy/client](../../spec/dummy/client) for a webpack configuration example.
52
52
 
53
53
 
@@ -1,4 +1,6 @@
1
1
  # RSpec Configuration
2
+ _Click [here for minitest](./minitest-configuration.md)_
3
+
2
4
  Because you will probably want to run RSpec tests that rely on compiled webpack assets (typically, your integration/feature specs where `js: true`), you will want to ensure you don't accidentally run tests on missing or stale webpack assets. If you did use stale Webpack assets, you will get invalid test results as your tests do not use the very latest JavaScript code.
3
5
 
4
6
  ReactOnRails provides a helper method called `ReactOnRails::TestHelper.configure_rspec_to_compile_assets`. Call this method from inside of the `RSpec.configure` block in your `spec/rails_helper.rb` file, passing the config as an argument. See file [lib/react_on_rails/test_helper.rb](../../lib/react_on_rails/test_helper.rb) for more details. You can customize this to your particular needs by replacing any of the default components used by `ReactOnRails::TestHelper.configure_rspec_to_compile_assets`.
@@ -55,8 +57,6 @@ If you want to speed up the re-compiling process so you don't wait to run your t
55
57
 
56
58
  [spec/dummy](https://github.com/shakacode/react_on_rails/tree/master/spec/dummy) contains examples of how to set the proc files for this purpose.
57
59
 
58
- If you want to use a testing framework other than RSpec, please submit let us know on the changes you need to do and we'll update the docs.
59
-
60
60
  ![2016-01-27_02-36-43](https://cloud.githubusercontent.com/assets/1118459/12611951/7c56d070-c4a4-11e5-8a80-9615f99960d9.png)
61
61
 
62
62
  ![2016-01-27_03-18-05](https://cloud.githubusercontent.com/assets/1118459/12611975/a8011654-c4a4-11e5-84f9-1baca4835b4b.png)
@@ -5,12 +5,22 @@ If you would like help in migrating between React on Rails versions or help with
5
5
 
6
6
  We specialize in helping companies to quickly and efficiently move from versions before 9 to current. 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
+ ## Upgrading rails/webpacker from v3 to v4
9
+ ### Custom Webpack build file
10
+ 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.
11
+
12
+ ```yml
13
+ default: &default
14
+ # other stuff
15
+ extract_css: true
16
+ # by default, extract and emit a css file. The default is false
17
+ ```
18
+
8
19
  ## Upgrading to version 11
9
20
  * Remove `server_render_method` from config/initializers/react_on_rails.rb. Alternate server rendering methods are part of React on Rails Pro. If you want to use a custom renderer, contact justin@shakacode.com. We have a custom node rendering solution in production for egghead.io.
10
21
  * Remove your usage of ENV["TRACE_REACT_ON_RAILS"] usage. You can get all tracing with either specifying **`trace`** at your component or in your config/initializers/react_on_rails.rb file.
11
22
  * ReactOnRails::Utils.server_bundle_file_name and ReactOnRails::Utils.bundle_file_name were removed. React on Rails Pro contains upgrades to enable component and other types caching with React on Rails.
12
23
 
13
-
14
24
  ## Upgrading to version 10
15
25
 
16
26
  Pretty simple:
@@ -21,7 +21,7 @@ Different markup is generated on the client than on the server. Why does this ha
21
21
 
22
22
  ### The solution
23
23
 
24
- 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 generator function, except that the function you pass takes three arguments: `renderer(props, railsContext, domNodeId)`, and is responsible for calling `ReactDOM.render` to render the component to the DOM. React on rails will automatically detect when a generator function takes three arguments, and will not call `ReactDOM.render`, instead allowing you to control the initial render yourself.
24
+ 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 generator 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 generator 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.
25
25
 
26
26
  Here's an example of how you might use this in practice:
27
27
 
@@ -115,7 +115,7 @@ See:
115
115
 
116
116
  - [spec/dummy/client/app/startup/clientRegistration.jsx](https://github.com/shakacode/react_on_rails/tree/master/spec/dummy/client/app/startup/clientRegistration.jsx)
117
117
  - [spec/dummy/client/app/startup/serverRegistration.jsx](https://github.com/shakacode/react_on_rails/tree/master/spec/dummy/client/app/startup/serverRegistration.jsx)
118
- - [spec/dummy/client/app/startup/DeferredRenderAppRenderer.jsx](https://github.com/shakacode/react_on_rails/tree/master/spec/dummy/client/app/startup/DeferredRenderAppRenderer.jsx) <-- Code splitting implemented here
118
+ - [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
119
119
  - [spec/dummy/client/app/startup/DeferredRenderAppServer.jsx](https://github.com/shakacode/react_on_rails/tree/master/spec/dummy/client/app/startup/DeferredRenderAppServer.jsx)
120
120
  - [spec/dummy/client/app/components/DeferredRender.jsx](https://github.com/shakacode/react_on_rails/tree/master/spec/dummy/client/app/components/DeferredRender.jsx)
121
121
  - [spec/dummy/client/app/components/DeferredRenderAsyncPage.jsx](https://github.com/shakacode/react_on_rails/tree/master/spec/dummy/client/app/components/DeferredRenderAsyncPage.jsx)
@@ -16,9 +16,9 @@ The price we paid for the consultation + the React on Rails pro license has alre
16
16
 
17
17
  If you have any questions, please reach out.
18
18
 
19
- Paul Benigeri
20
- [paul@hvmn.com](mailto:paul@hvmn.com)
21
- [LinkedIn](https://www.linkedin.com/in/benigeri/)
19
+ Paul Benigeri, Head of E-Commerce
20
+
21
+ [paul@hvmn.com](mailto:paul@hvmn.com), [LinkedIn](https://www.linkedin.com/in/benigeri/)
22
22
 
23
23
  Related Article: [HVMN’s 90% Reduction in Server Response Time from React on Rails Pro](https://blog.shakacode.com/hvmns-90-reduction-in-server-response-time-from-react-on-rails-pro-eb08226687db)
24
24
 
@@ -0,0 +1,13 @@
1
+ # ResortPass Testimonial, by Leora Juster, December 10, 2018
2
+
3
+ Many can write code that "works." Even fewer can write sophisticated code that both works and reflects a deep understanding of the technologies and paradigms involved. Only a select few can do the aforementioned while assisting in managing the expectations and time constraints of less technically informed members of software product teams to make the best design decisions possible. Justin and his team were instrumental in assisting us in setting design foundations and standards for our transition to a react on rails application. Just three months of work with the team at Shaka code and we have a main page of our application server-side rendering at exponentially improved speeds. The code and CSS files are well-organized and contain repeatable patterns easy to understand, allowing my team to build on what has already been accomplished. I learned a great deal from my interactions with Justin and his team, as they are just as great teachers as they are developers, and feel like I get to continually learn from them as I build on top of their code. Their different support and pro plan options make it easy to build a continuous professional relationship despite fluctuations in my team's funding, and their team is always extremely personable, punctual, and professional.
4
+
5
+ Leora Juster, Full-Stack Lead Software Developer
6
+
7
+ [LinkedIn](https://www.linkedin.com/in/leora-juster-38933050)
8
+
9
+ ![image](https://user-images.githubusercontent.com/1118459/50050877-30399b00-00ab-11e9-9e52-2977de45ccae.png)
10
+
11
+ [ResortPass](https://resortpass.com/)
12
+
13
+ [![2018-12-15_20-48-35](https://user-images.githubusercontent.com/1118459/50050866-03858380-00ab-11e9-8588-461112f8045b.png)](https://resortpass.com/)
@@ -1,8 +1,18 @@
1
1
  # Testimonials
2
- [HVMN Testimonial, Written by Paul Benigeri, October 12, 2018](./testimonials/hvmn.md)
2
+ # [HVMN Testimonial, Written by Paul Benigeri, October 12, 2018](./hvmn.md)
3
3
 
4
4
  > The price we paid for the consultation + the React on Rails pro license has already been made back a couple of times from hosting fees alone. The entire process was super hands off, and our core team was able to focus on shipping new feature during that sprint.
5
5
 
6
+ Full writeup [here](./hvmn.md).
7
+
8
+ ---
9
+
10
+ # [Leora from ResortPass](./resortpass.md), December 10, 2018
11
+
12
+ Justin and his team were instrumental in assisting us in setting design foundations and standards for our transition to a react on rails application. Just three months of work with the team at Shaka code and we have a main page of our application server-side rendering at exponentially improved speeds.
13
+
14
+ Full writeup [here](./testimonials/resortpass.md).
15
+
6
16
  ---
7
17
 
8
18
  From Joel Hooks, Co-Founder, Chief Nerd at [egghead.io](https://egghead.io/), January 30, 2017:
@@ -1,6 +1,6 @@
1
1
  # React on Rails Basic Tutorial
2
2
 
3
- This tutorial guides you through setting up a new or existing Rails app with **React on Rails**, demonstrating Rails + React + Redux + Server Rendering. It is updated to 11.1.4.
3
+ This tutorial guides you through setting up a new or existing Rails app with **React on Rails**, demonstrating Rails + React + Redux + Server Rendering. It is updated to 11.2.1.
4
4
 
5
5
  After finishing this tutorial you will get an application that can do the following (live on Heroku):
6
6
 
@@ -57,10 +57,10 @@ bundle exec rails webpacker:install
57
57
  bundle exec rails webpacker:install:react
58
58
  ```
59
59
 
60
- Add the **React On Rails** gem to your Gemfile:
60
+ Add the **React On Rails** gem to your `Gemfile`:
61
61
 
62
62
  ```
63
- gem 'react_on_rails', '11.1.7' # prefer exact gem version to match npm version
63
+ gem 'react_on_rails', '11.2.1' # prefer exact gem version to match npm version
64
64
  ```
65
65
 
66
66
  Note: Latest released React On Rails version is considered stable. Please use the latest version to ensure you get all the security patches and the best support.
@@ -84,15 +84,40 @@ rails generate react_on_rails:install
84
84
  bundle && yarn
85
85
  ```
86
86
 
87
- and then run server with
87
+ Then run server with static client side files:
88
88
 
89
89
  ```
90
90
  foreman start -f Procfile.dev
91
91
  ```
92
92
 
93
+ To run with the webpack-dev-server:
94
+ ```
95
+ foreman start -f Procfile.dev-server
96
+ ```
97
+
93
98
  Visit [http://localhost:3000/hello_world](http://localhost:3000/hello_world) and see your **React On Rails** app running!
94
99
  Note, foreman defaults to PORT 5000 unless you set the value of PORT in your environment or in the Procfile.
95
100
 
101
+ ## Using a pre-release of rails/webpacker
102
+ Until `rails/webpacker` v4 ships, or if you ever want to try out the master branch, you can modify the React on Rails tutorial instructions slightly. You can see the sequence of commits here. To summarize:
103
+
104
+ **Don't run `rails new` with the `--webpack=react` option**. Instead, add the webpacker gem to the Gemfile such that it points to master, like this if `11.2.1` is the version you want.
105
+
106
+ ```ruby
107
+ gem 'webpacker', github: "rails/webpacker"
108
+ gem 'react_on_rails', '11.2.1' # always use exact version
109
+ ```
110
+
111
+ Then run these commands:
112
+
113
+ ```sh
114
+ bundle exec rails webpacker:install
115
+ yarn add "rails/webpacker" # because the installer has a bug that puts in an invalid version in your package.json.
116
+ bundle exec rails webpacker:install:react
117
+ yarn add --dev webpack-dev-server
118
+ run rails generate react_on_rails:install && bundle && yarn
119
+ ```
120
+
96
121
  ### Custom IP & PORT setup (Cloud9 example)
97
122
 
98
123
  In case you are running some custom setup with different IP or PORT you should also edit Procfile.dev. For example to be able to run on free Cloud9 IDE we are putting IP 0.0.0.0 and PORT 8080. The default generated file `Procfile.dev` uses `-p 3000`.
@@ -218,7 +243,7 @@ end
218
243
  Then after all changes are done don't forget to commit them with git and finally you can push your app to Heroku!
219
244
 
220
245
  ```
221
- git add -a
246
+ git add -A
222
247
  git commit -m "Changes for Heroku"
223
248
  git push heroku master
224
249
  ```
@@ -243,7 +268,7 @@ You can turn on server rendering by simply changing the `prerender` option to `t
243
268
  Then push to Heroku:
244
269
 
245
270
  ```
246
- git add -a
271
+ git add -A
247
272
  git commit -m "Enable server rendering"
248
273
  git push heroku master
249
274
  ```
@@ -36,6 +36,7 @@ module ReactOnRails
36
36
 
37
37
  def replace_prerender_if_server_rendering
38
38
  return unless options.example_server_rendering
39
+
39
40
  hello_world_index = File.join(destination_root, "app", "views", "hello_world", "index.html.erb")
40
41
  hello_world_contents = File.read(hello_world_index)
41
42
  new_hello_world_contents = hello_world_contents.gsub(/prerender: false/,
@@ -62,6 +62,7 @@ module ReactOnRails
62
62
 
63
63
  def missing_yarn?
64
64
  return false unless ReactOnRails::Utils.running_on_windows? ? `where yarn`.blank? : `which yarn`.blank?
65
+
65
66
  error = "yarn is required. Please install it before continuing. https://yarnpkg.com/en/docs/install"
66
67
  GeneratorMessages.add_error(error)
67
68
  true
@@ -69,6 +70,7 @@ module ReactOnRails
69
70
 
70
71
  def missing_node?
71
72
  return false unless ReactOnRails::Utils.running_on_windows? ? `where node`.blank? : `which node`.blank?
73
+
72
74
  error = "** nodejs is required. Please install it before continuing. https://nodejs.org/en/"
73
75
  GeneratorMessages.add_error(error)
74
76
  true
@@ -14,8 +14,15 @@ require "rspec/rails"
14
14
  require "capybara/rspec"
15
15
  require "capybara/rails"
16
16
  Capybara.javascript_driver = :selenium_chrome
17
+
18
+ # From https://stackoverflow.com/a/56522500/1009332
19
+ capabilities = Selenium::WebDriver::Remote::Capabilities.chrome(
20
+ chromeOptions: { args: %w[headless window-size=1280,800], w3c: false }
21
+ )
17
22
  Capybara.register_driver :selenium_chrome do |app|
18
- Capybara::Selenium::Driver.new(app, browser: :chrome)
23
+ Capybara::Selenium::Driver.new(app,
24
+ browser: :chrome,
25
+ desired_capabilities: capabilities)
19
26
  end
20
27
 
21
28
  # Requires supporting ruby files with custom matchers and macros, etc, in
@@ -11,6 +11,7 @@ require "react_on_rails/version"
11
11
  require "react_on_rails/version_checker"
12
12
  require "react_on_rails/configuration"
13
13
  require "react_on_rails/server_rendering_pool"
14
+ require "react_on_rails/server_rendering_js_code"
14
15
  require "react_on_rails/engine"
15
16
  require "react_on_rails/react_component/render_options"
16
17
  require "react_on_rails/version_syntax_converter"
@@ -64,6 +64,7 @@ module ReactOnRails
64
64
  # references from webpack's CSS would be invalid. The fix is to symlink the double-digested
65
65
  # file back to the original digested name, and make a similar symlink for the gz version.
66
66
  return unless @symlink_non_digested_assets_regex
67
+
67
68
  manifest_glob = Dir.glob(@assets_path.join(".sprockets-manifest-*.json")) +
68
69
  Dir.glob(@assets_path.join("manifest-*.json")) +
69
70
  Dir.glob(@assets_path.join("manifest.yml"))
@@ -86,6 +87,7 @@ module ReactOnRails
86
87
  manifest_data.each do |original_filename, rails_digested_filename|
87
88
  # TODO: we should remove any original_filename that is NOT in the webpack deploy folder.
88
89
  next unless original_filename =~ @symlink_non_digested_assets_regex
90
+
89
91
  # We're symlinking from the digested filename back to the original filename which has
90
92
  # already been symlinked by Webpack
91
93
  symlink_file(rails_digested_filename, original_filename)
@@ -100,6 +102,7 @@ module ReactOnRails
100
102
  def delete_broken_symlinks
101
103
  Dir.glob(@assets_path.join("*")).each do |filename|
102
104
  next unless File.lstat(filename).symlink?
105
+
103
106
  begin
104
107
  target = File.readlink(filename)
105
108
  rescue StandardError
@@ -21,7 +21,7 @@ module ReactOnRails
21
21
  prerender: false,
22
22
  replay_console: true,
23
23
  logging_on_server: true,
24
- raise_on_prerender_error: false,
24
+ raise_on_prerender_error: Rails.env.development?,
25
25
  trace: Rails.env.development?,
26
26
  development_mode: Rails.env.development?,
27
27
  server_renderer_pool_size: DEFAULT_POOL_SIZE,
@@ -218,6 +218,7 @@ module ReactOnRails
218
218
 
219
219
  def configure_skip_display_none_deprecation
220
220
  return if skip_display_none.nil?
221
+
221
222
  Rails.logger.warn "[DEPRECATION] ReactOnRails: remove skip_display_none from configuration."
222
223
  end
223
224
  end
@@ -6,8 +6,10 @@ module ReactOnRails
6
6
  module GitUtils
7
7
  def self.uncommitted_changes?(message_handler)
8
8
  return false if ENV["COVERAGE"] == "true"
9
+
9
10
  status = `git status --porcelain`
10
11
  return false if $CHILD_STATUS.success? && status.empty?
12
+
11
13
  error = if !$CHILD_STATUS.success?
12
14
  "You do not have Git installed. Please install Git, and commit your changes before continuing"
13
15
  else
@@ -136,7 +136,7 @@ module ReactOnRails
136
136
  # It is exactly like react_component except for the following:
137
137
  # 1. prerender: true is automatically added, as this method doesn't make sense for client only
138
138
  # rendering.
139
- # 2. Your JavaScript for server rendering must return an Object for the key server_rendered_html.
139
+ # 2. Your JavaScript generator function for server rendering must return an Object rather than a React component.
140
140
  # 3. Your view code must expect an object and not a string.
141
141
  #
142
142
  # Here is an example of the view code:
@@ -206,6 +206,7 @@ module ReactOnRails
206
206
  # that contains a data props.
207
207
  def redux_store_hydration_data
208
208
  return if @registered_stores_defer_render.blank?
209
+
209
210
  @registered_stores_defer_render.reduce("".dup) do |accum, redux_store_data|
210
211
  accum << render_redux_store_data(redux_store_data)
211
212
  end.html_safe
@@ -265,6 +266,7 @@ module ReactOnRails
265
266
 
266
267
  def json_safe_and_pretty(hash_or_string)
267
268
  return "{}" if hash_or_string.nil?
269
+
268
270
  unless hash_or_string.is_a?(String) || hash_or_string.is_a?(Hash)
269
271
  raise ReactOnRails::Error, "#{__method__} only accepts String or Hash as argument "\
270
272
  "(#{hash_or_string.class} given)."
@@ -275,6 +277,59 @@ module ReactOnRails
275
277
  ReactOnRails::JsonOutput.escape(json_value)
276
278
  end
277
279
 
280
+ # This is the definitive list of the default values used for the rails_context, which is the
281
+ # second parameter passed to both component and store generator functions.
282
+ # This method can be called from views and from the controller, as `helpers.rails_context`
283
+ #
284
+ # rubocop:disable Metrics/AbcSize
285
+ def rails_context(server_side: true)
286
+ @rails_context ||= begin
287
+ result = {
288
+ railsEnv: Rails.env,
289
+ inMailer: in_mailer?,
290
+ # Locale settings
291
+ i18nLocale: I18n.locale,
292
+ i18nDefaultLocale: I18n.default_locale,
293
+ rorVersion: ReactOnRails::VERSION,
294
+ rorPro: ReactOnRails::Utils.react_on_rails_pro?
295
+ }
296
+ if defined?(request) && request.present?
297
+ # Check for encoding of the request's original_url and try to force-encoding the
298
+ # URLs as UTF-8. This situation can occur in browsers that do not encode the
299
+ # entire URL as UTF-8 already, mostly on the Windows platform (IE11 and lower).
300
+ original_url_normalized = request.original_url
301
+ if original_url_normalized.encoding.to_s == "ASCII-8BIT"
302
+ original_url_normalized = original_url_normalized.force_encoding("ISO-8859-1").encode("UTF-8")
303
+ end
304
+
305
+ # Using Addressable instead of standard URI to better deal with
306
+ # non-ASCII characters (see https://github.com/shakacode/react_on_rails/pull/405)
307
+ uri = Addressable::URI.parse(original_url_normalized)
308
+ # uri = Addressable::URI.parse("http://foo.com:3000/posts?id=30&limit=5#time=1305298413")
309
+
310
+ result.merge!(
311
+ # URL settings
312
+ href: uri.to_s,
313
+ location: "#{uri.path}#{uri.query.present? ? "?#{uri.query}" : ''}",
314
+ scheme: uri.scheme, # http
315
+ host: uri.host, # foo.com
316
+ port: uri.port,
317
+ pathname: uri.path, # /posts
318
+ search: uri.query, # id=30&limit=5
319
+ httpAcceptLanguage: request.env["HTTP_ACCEPT_LANGUAGE"]
320
+ )
321
+ end
322
+ if ReactOnRails.configuration.rendering_extension
323
+ custom_context = ReactOnRails.configuration.rendering_extension.custom_context(self)
324
+ result.merge!(custom_context) if custom_context
325
+ end
326
+ result
327
+ end
328
+
329
+ @rails_context.merge(serverSide: server_side)
330
+ end
331
+ # rubocop:enable Metrics/AbcSize
332
+
278
333
  private
279
334
 
280
335
  def build_react_component_result_for_server_rendered_string(
@@ -284,9 +339,15 @@ module ReactOnRails
284
339
  render_options: required("render_options")
285
340
  )
286
341
  content_tag_options = render_options.html_options
342
+ if content_tag_options.key?(:tag)
343
+ content_tag_options_html_tag = content_tag_options[:tag]
344
+ content_tag_options.delete(:tag)
345
+ else
346
+ content_tag_options_html_tag = "div"
347
+ end
287
348
  content_tag_options[:id] = render_options.dom_id
288
349
 
289
- rendered_output = content_tag(:div,
350
+ rendered_output = content_tag(content_tag_options_html_tag.to_sym,
290
351
  server_rendered_html.html_safe,
291
352
  content_tag_options)
292
353
 
@@ -405,9 +466,7 @@ module ReactOnRails
405
466
 
406
467
  # Returns object with values that are NOT html_safe!
407
468
  def server_rendered_react_component(render_options)
408
- if !render_options.prerender || ReactOnRails::Utils.server_bundle_path_is_http?
409
- return { "html" => "", "consoleReplayScript" => "" }
410
- end
469
+ return { "html" => "", "consoleReplayScript" => "" } unless render_options.prerender
411
470
 
412
471
  react_component_name = render_options.react_component_name
413
472
  props = render_options.props
@@ -433,22 +492,13 @@ module ReactOnRails
433
492
  #
434
493
  # Read more here: http://timelessrepo.com/json-isnt-a-javascript-subset
435
494
 
436
- # rubocop:disable Layout/IndentHeredoc
437
- js_code = <<-JS
438
- (function() {
439
- var railsContext = #{rails_context(server_side: true).to_json};
440
- #{initialize_redux_stores}
441
- var props = #{props_string(props).gsub("\u2028", '\u2028').gsub("\u2029", '\u2029')};
442
- return ReactOnRails.serverRenderReactComponent({
443
- name: '#{react_component_name}',
444
- domNodeId: '#{render_options.dom_id}',
445
- props: props,
446
- trace: #{render_options.trace},
447
- railsContext: railsContext
448
- });
449
- })()
450
- JS
451
- # rubocop:enable Layout/IndentHeredoc
495
+ js_code = ReactOnRails::ServerRenderingJsCode.server_rendering_component_js_code(
496
+ props_string: props_string(props).gsub("\u2028", '\u2028').gsub("\u2029", '\u2029'),
497
+ rails_context: rails_context(server_side: true).to_json,
498
+ redux_stores: initialize_redux_stores,
499
+ react_component_name: react_component_name,
500
+ render_options: render_options
501
+ )
452
502
 
453
503
  begin
454
504
  result = ReactOnRails::ServerRenderingPool.server_render_js_with_console_logging(js_code, render_options)
@@ -480,6 +530,7 @@ module ReactOnRails
480
530
  JS
481
531
 
482
532
  return result unless @registered_stores.present? || @registered_stores_defer_render.present?
533
+
483
534
  declarations = "var reduxProps, store, storeGenerator;\n".dup
484
535
  all_stores = (@registered_stores || []) + (@registered_stores_defer_render || [])
485
536
 
@@ -496,58 +547,6 @@ module ReactOnRails
496
547
  result
497
548
  end
498
549
 
499
- # This is the definitive list of the default values used for the rails_context, which is the
500
- # second parameter passed to both component and store generator functions.
501
- # rubocop:disable Metrics/AbcSize
502
- def rails_context(server_side: required("server_side"))
503
- @rails_context ||= begin
504
- result = {
505
- railsEnv: Rails.env,
506
- inMailer: in_mailer?,
507
- # Locale settings
508
- i18nLocale: I18n.locale,
509
- i18nDefaultLocale: I18n.default_locale,
510
- rorVersion: ReactOnRails::VERSION,
511
- rorPro: ReactOnRails::Utils.react_on_rails_pro?
512
- }
513
- if defined?(request) && request.present?
514
- # Check for encoding of the request's original_url and try to force-encoding the
515
- # URLs as UTF-8. This situation can occur in browsers that do not encode the
516
- # entire URL as UTF-8 already, mostly on the Windows platform (IE11 and lower).
517
- original_url_normalized = request.original_url
518
- if original_url_normalized.encoding.to_s == "ASCII-8BIT"
519
- original_url_normalized = original_url_normalized.force_encoding("ISO-8859-1").encode("UTF-8")
520
- end
521
-
522
- # Using Addressable instead of standard URI to better deal with
523
- # non-ASCII characters (see https://github.com/shakacode/react_on_rails/pull/405)
524
- uri = Addressable::URI.parse(original_url_normalized)
525
- # uri = Addressable::URI.parse("http://foo.com:3000/posts?id=30&limit=5#time=1305298413")
526
-
527
- result.merge!(
528
- # URL settings
529
- href: uri.to_s,
530
- location: "#{uri.path}#{uri.query.present? ? "?#{uri.query}" : ''}",
531
- scheme: uri.scheme, # http
532
- host: uri.host, # foo.com
533
- port: uri.port,
534
- pathname: uri.path, # /posts
535
- search: uri.query, # id=30&limit=5
536
- httpAcceptLanguage: request.env["HTTP_ACCEPT_LANGUAGE"]
537
- )
538
- end
539
- if ReactOnRails.configuration.rendering_extension
540
- custom_context = ReactOnRails.configuration.rendering_extension.custom_context(self)
541
- result.merge!(custom_context) if custom_context
542
- end
543
- result
544
- end
545
-
546
- @rails_context.merge(serverSide: server_side)
547
- end
548
-
549
- # rubocop:enable Metrics/AbcSize
550
-
551
550
  def replay_console_option(val)
552
551
  val.nil? ? ReactOnRails.configuration.replay_console : val
553
552
  end