react-rails 1.9.0 → 3.2.1

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.
Files changed (61) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +345 -9
  3. data/README.md +137 -389
  4. data/lib/assets/javascripts/JSXTransformer.js +6 -6
  5. data/lib/assets/javascripts/react_ujs.js +1 -7
  6. data/lib/assets/react-source/development/react-server.js +423 -21528
  7. data/lib/assets/react-source/development/react.js +191 -21409
  8. data/lib/assets/react-source/production/react-server.js +2 -19
  9. data/lib/assets/react-source/production/react.js +2 -19
  10. data/lib/generators/react/component_generator.rb +203 -73
  11. data/lib/generators/react/install_generator.rb +98 -25
  12. data/lib/generators/templates/component.es6.jsx +9 -12
  13. data/lib/generators/templates/component.es6.tsx +24 -0
  14. data/lib/generators/templates/component.js.jsx +15 -18
  15. data/lib/generators/templates/component.js.jsx.coffee +5 -8
  16. data/lib/generators/templates/component.js.jsx.tsx +36 -0
  17. data/lib/generators/templates/react_server_rendering.rb +4 -0
  18. data/lib/generators/templates/server_rendering.js +6 -0
  19. data/lib/generators/templates/server_rendering_pack.js +5 -0
  20. data/lib/react/jsx/babel_transformer.rb +12 -6
  21. data/lib/react/jsx/jsx_transformer.rb +7 -6
  22. data/lib/react/jsx/processor.rb +3 -1
  23. data/lib/react/jsx/sprockets_strategy.rb +12 -6
  24. data/lib/react/jsx/template.rb +7 -6
  25. data/lib/react/jsx.rb +11 -7
  26. data/lib/react/rails/asset_variant.rb +7 -8
  27. data/lib/react/rails/component_mount.rb +48 -14
  28. data/lib/react/rails/controller_lifecycle.rb +36 -7
  29. data/lib/react/rails/controller_renderer.rb +13 -4
  30. data/lib/react/rails/railtie.rb +34 -29
  31. data/lib/react/rails/test_helper.rb +25 -0
  32. data/lib/react/rails/version.rb +4 -2
  33. data/lib/react/rails/view_helper.rb +3 -1
  34. data/lib/react/rails.rb +9 -7
  35. data/lib/react/server_rendering/{sprockets_renderer → bundle_renderer}/console_replay.js +1 -1
  36. data/lib/react/server_rendering/bundle_renderer/console_reset.js +3 -0
  37. data/lib/react/server_rendering/bundle_renderer/timeout_polyfill.js +26 -0
  38. data/lib/react/server_rendering/bundle_renderer.rb +117 -0
  39. data/lib/react/server_rendering/environment_container.rb +2 -0
  40. data/lib/react/server_rendering/exec_js_renderer.rb +43 -16
  41. data/lib/react/server_rendering/manifest_container.rb +5 -1
  42. data/lib/react/server_rendering/separate_server_bundle_container.rb +19 -0
  43. data/lib/react/server_rendering/yaml_manifest_container.rb +12 -4
  44. data/lib/react/server_rendering.rb +26 -12
  45. data/lib/react-rails.rb +12 -4
  46. data/lib/react.rb +8 -4
  47. metadata +106 -41
  48. data/lib/assets/javascripts/react_ujs_event_setup.js +0 -29
  49. data/lib/assets/javascripts/react_ujs_mount.js +0 -104
  50. data/lib/assets/javascripts/react_ujs_native.js +0 -18
  51. data/lib/assets/javascripts/react_ujs_pjax.js +0 -10
  52. data/lib/assets/javascripts/react_ujs_turbolinks.js +0 -9
  53. data/lib/assets/javascripts/react_ujs_turbolinks_classic.js +0 -10
  54. data/lib/assets/javascripts/react_ujs_turbolinks_classic_deprecated.js +0 -13
  55. data/lib/assets/react-source/development-with-addons/react-server.js +0 -24053
  56. data/lib/assets/react-source/development-with-addons/react.js +0 -23890
  57. data/lib/assets/react-source/production-with-addons/react-server.js +0 -19
  58. data/lib/assets/react-source/production-with-addons/react.js +0 -19
  59. data/lib/generators/react/ujs_generator.rb +0 -44
  60. data/lib/react/server_rendering/sprockets_renderer.rb +0 -79
  61. /data/lib/react/server_rendering/{sprockets_renderer → bundle_renderer}/console_polyfill.js +0 -0
data/README.md CHANGED
@@ -1,391 +1,139 @@
1
- [![Gem](https://img.shields.io/gem/v/react-rails.svg?style=flat-square)](http://rubygems.org/gems/react-rails)
2
- [![Build Status](https://img.shields.io/travis/reactjs/react-rails/master.svg?style=flat-square)](https://travis-ci.org/reactjs/react-rails)
3
- [![Gemnasium](https://img.shields.io/gemnasium/reactjs/react-rails.svg?style=flat-square)](https://gemnasium.com/reactjs/react-rails)
4
- [![Code Climate](https://img.shields.io/codeclimate/github/reactjs/react-rails.svg?style=flat-square)](https://codeclimate.com/github/reactjs/react-rails)
5
- [![Test Coverage](https://img.shields.io/codeclimate/coverage/github/reactjs/react-rails.svg?style=flat-square)](https://codeclimate.com/github/reactjs/react-rails/coverage)
6
-
7
- * * *
8
-
9
- # react-rails
10
-
11
-
12
- `react-rails` makes it easy to use [React](http://facebook.github.io/react/) and [JSX](http://facebook.github.io/react/docs/jsx-in-depth.html)
13
- in your Ruby on Rails (3.2+) application. `react-rails` can:
14
-
15
- - Provide [various `react` builds](#reactjs-builds) to your asset bundle
16
- - Transform [`.jsx` in the asset pipeline](#jsx)
17
- - [Render components into views and mount them](#rendering--mounting) via view helper & `react_ujs`
18
- - [Render components server-side](#server-rendering) with `prerender: true`
19
- - [Generate components](#component-generator) with a Rails generator
20
- - [Be extended](#extending-react-rails) with custom renderers, transformers and view helpers
21
-
22
- Just getting started with React? Make sure to check out the [Getting Started] (https://facebook.github.io/react/docs/getting-started.html) guide. Also, see [Related Projects](#related-projects) below.
23
-
24
- ## Installation
25
-
26
- Add `react-rails` to your gemfile:
27
-
28
- ```ruby
29
- gem 'react-rails'
30
- ```
31
-
32
- And install:
33
-
34
- ```
35
- bundle install
36
- ```
37
-
38
- Next, run the installation script:
39
-
40
- ```bash
41
- rails g react:install
42
- ```
43
-
44
- This will:
45
- - create a `components.js` manifest file and a `app/assets/javascripts/components/` directory,
46
- where you will put your components
47
- - place the following in your `application.js`:
48
-
49
- ```js
50
- //= require react
51
- //= require react_ujs
52
- //= require components
53
- ```
54
-
55
- ## Usage
56
-
57
- ### React.js builds
58
-
59
- You can pick which React.js build (development, production, with or without [add-ons]((http://facebook.github.io/react/docs/addons.html)))
60
- to serve in each environment by adding a config. Here are the defaults:
61
-
62
- ```ruby
63
- # config/environments/development.rb
64
- MyApp::Application.configure do
65
- config.react.variant = :development
66
- end
67
-
68
- # config/environments/production.rb
69
- MyApp::Application.configure do
70
- config.react.variant = :production
71
- end
72
- ```
73
-
74
- To include add-ons, use this config:
75
-
76
- ```ruby
77
- MyApp::Application.configure do
78
- config.react.addons = true # defaults to false
79
- end
80
- ```
81
-
82
- After restarting your Rails server, `//= require react` will provide the build of React.js which
83
- was specified by the configurations.
84
-
85
- `react-rails` offers a few other options for versions & builds of React.js.
86
- See [VERSIONS.md](https://github.com/reactjs/react-rails/blob/master/VERSIONS.md) for more info about
87
- using the `react-source` gem or dropping in your own copies of React.js.
88
-
89
- ### JSX
90
-
91
- After installing `react-rails`, restart your server. Now, `.js.jsx` files will be transformed in the asset pipeline.
92
-
93
- #### BabelTransformer options
94
-
95
- You can use babel's [transformers](http://babeljs.io/docs/advanced/transformers/) and [custom plugins](http://babeljs.io/docs/advanced/plugins/),
96
- and pass [options](http://babeljs.io/docs/usage/options/) to the babel transpiler adding following configurations:
97
-
98
- ```ruby
99
- config.react.jsx_transform_options = {
100
- blacklist: ['spec.functionName', 'validation.react', 'strict'], # default options
101
- optional: ["transformerName"], # pass extra babel options
102
- whitelist: ["useStrict"] # even more options
103
- }
104
- ```
105
- Under the hood, `react-rails` uses [ruby-babel-transpiler](https://github.com/babel/ruby-babel-transpiler), for transformation.
106
-
107
- ### Rendering & mounting
108
-
109
- `react-rails` includes a view helper (`react_component`) and an unobtrusive JavaScript driver (`react_ujs`)
110
- which work together to put React components on the page. You should require the UJS driver
111
- in your manifest after `react` (and after `turbolinks` if you use [Turbolinks](https://github.com/rails/turbolinks)).
112
-
113
- The __view helper__ puts a `div` on the page with the requested component class & props. For example:
114
-
115
- ```erb
116
- <%= react_component('HelloMessage', name: 'John') %>
117
- <!-- becomes: -->
118
- <div data-react-class="HelloMessage" data-react-props="{&quot;name&quot;:&quot;John&quot;}"></div>
119
- ```
120
-
121
- On page load, the __`react_ujs` driver__ will scan the page and mount components using `data-react-class`
122
- and `data-react-props`.
123
-
124
- If Turbolinks is present components are mounted on the `page:change` event, and unmounted on `page:before-unload`.
125
- __Turbolinks >= 2.4.0__ is recommended because it exposes better events.
126
-
127
- In case of __Ajax calls__, the UJS mounting can be triggered manually by calling from javascript:
128
-
129
- ```javascript
130
- ReactRailsUJS.mountComponents()
131
- ```
132
-
133
- The view helper's signature is:
134
-
135
- ```ruby
136
- react_component(component_class_name, props={}, html_options={})
137
- ```
138
-
139
- - `component_class_name` is a string which names a globally-accessible component class. It may have dots (eg, `"MyApp.Header.MenuItem"`).
140
- - `props` is either an object that responds to `#to_json` or an already-stringified JSON object (eg, made with Jbuilder, see note below).
141
- - `html_options` may include:
142
- - `tag:` to use an element other than a `div` to embed `data-react-class` and `data-react-props`.
143
- - `prerender: true` to render the component on the server.
144
- - `**other` Any other arguments (eg `class:`, `id:`) are passed through to [`content_tag`](http://api.rubyonrails.org/classes/ActionView/Helpers/TagHelper.html#method-i-content_tag).
145
-
146
-
147
- ### Server rendering
148
-
149
- To render components on the server, pass `prerender: true` to `react_component`:
150
-
151
- ```erb
152
- <%= react_component('HelloMessage', {name: 'John'}, {prerender: true}) %>
153
- <!-- becomes: -->
154
- <div data-react-class="HelloMessage" data-react-props="{&quot;name&quot;:&quot;John&quot;}">
155
- <h1>Hello, John!</h1>
156
- </div>
157
- ```
158
-
159
- _(It will also be mounted by the UJS on page load.)_
160
-
161
- There are some requirements for this to work:
162
-
163
- - `react-rails` must load your code. By convention, it uses `components.js`, which was created
164
- by the install task. This file must include your components _and_ their dependencies (eg, Underscore.js).
165
- - Your components must be accessible in the global scope.
166
- If you are using `.js.jsx.coffee` files then the wrapper function needs to be taken into account:
167
-
168
- ```coffee
169
- # @ is `window`:
170
- @Component = React.createClass
171
- render: ->
172
- `<ExampleComponent videos={this.props.videos} />`
173
- ```
174
- - Your code can't reference `document`. Prerender processes don't have access to `document`,
175
- so jQuery and some other libs won't work in this environment :(
176
-
177
- You can configure your pool of JS virtual machines and specify where it should load code:
178
-
179
- ```ruby
180
- # config/environments/application.rb
181
- # These are the defaults if you don't specify any yourself
182
- MyApp::Application.configure do
183
- # Settings for the pool of renderers:
184
- config.react.server_renderer_pool_size ||= 1 # ExecJS doesn't allow more than one on MRI
185
- config.react.server_renderer_timeout ||= 20 # seconds
186
- config.react.server_renderer = React::ServerRendering::SprocketsRenderer
187
- config.react.server_renderer_options = {
188
- files: ["react-server.js", "components.js"], # files to load for prerendering
189
- replay_console: true, # if true, console.* will be replayed client-side
190
- }
191
- end
192
- ```
193
-
194
- - On MRI, use `therubyracer` for the best performance (see [discussion](https://github.com/reactjs/react-rails/pull/290))
195
- - On MRI, you'll get a deadlock with `pool_size` > 1
196
- - If you're using JRuby, you can increase `pool_size` to have real multi-threaded rendering.
197
-
198
- You can configure camelize_props option and pass props with an underscored hash from rails but get a camelized hash in jsx :
199
-
200
- ```ruby
201
- MyApp::Application.configure do
202
- config.react.camelize_props = true #default false
203
- end
204
- ```
1
+ # React-Rails v3
205
2
 
206
- ### Rendering components instead of views
207
-
208
- Components can also be prerendered directly from a controller action with the custom `component` renderer. For example:
209
-
210
- ```ruby
211
- class TodoController < ApplicationController
212
- def index
213
- @todos = Todo.all
214
- render component: 'TodoList', props: { todos: @todos }, tag: 'span', class: 'todo'
215
- end
216
- end
217
- ```
218
-
219
- This custom renderer behaves the same as a normal view renderer and accepts the usual arguments - `content_type`, `layout`, `location` and `status`.
220
- By default, your current layout will be used and the component, rather than a view, will be rendered in place of `yield`. Custom data-* attributes
221
- can be passed like `data: {remote: true}`.
222
-
223
- ### Component generator
224
-
225
- `react-rails` ships with a Rails generator to help you get started with a simple component scaffold.
226
- You can run it using `rails generate react:component ComponentName (--es6)`.
227
- The generator takes an optional list of arguments for default propTypes,
228
- which follow the conventions set in the [Reusable Components](http://facebook.github.io/react/docs/reusable-components.html)
229
- section of the React documentation.
230
-
231
- For example:
232
-
233
- ```shell
234
- rails generate react:component Post title:string body:string published:bool published_by:instanceOf{Person}
235
- ```
236
-
237
- would generate the following in `app/assets/javascripts/components/post.js.jsx`:
238
-
239
- ```jsx
240
- var Post = React.createClass({
241
- propTypes: {
242
- title: React.PropTypes.string,
243
- body: React.PropTypes.string,
244
- published: React.PropTypes.bool,
245
- publishedBy: React.PropTypes.instanceOf(Person)
246
- },
247
-
248
- render: function() {
249
- return (
250
- <div>
251
- <div>Title: {this.props.title}</div>
252
- <div>Body: {this.props.body}</div>
253
- <div>Published: {this.props.published}</div>
254
- <div>Published By: {this.props.publishedBy}</div>
255
- </div>
256
- );
257
- }
258
- });
259
- ```
260
-
261
- #### Options
262
-
263
- **--es6** : Generate the same component but using cutting edge es6 class
264
-
265
- For example:
266
-
267
- ```shell
268
- rails generate react:component Label label:string --es6
269
- ```
270
-
271
- **--coffee** : Generate the component using CoffeeScript syntax
272
-
273
- For example:
274
-
275
- ```shell
276
- rails generate react:component Label label:string --coffee
277
- ```
278
-
279
- #### Arguments
280
-
281
- The generator can use the following arguments to create basic propTypes:
282
-
283
- * any
284
- * array
285
- * bool
286
- * element
287
- * func
288
- * number
289
- * object
290
- * node
291
- * shape
292
- * string
293
-
294
- The following additional arguments have special behavior:
295
-
296
- * `instanceOf` takes an optional class name in the form of {className}.
297
- * `oneOf` behaves like an enum, and takes an optional list of strings in the form of `'name:oneOf{one,two,three}'`.
298
- * `oneOfType` takes an optional list of react and custom types in the form of `'model:oneOfType{string,number,OtherType}'`.
299
-
300
- Note that the arguments for `oneOf` and `oneOfType` must be enclosed in single quotes
301
- to prevent your terminal from expanding them into an argument list.
302
-
303
- ### Jbuilder & react-rails
304
-
305
- If you use Jbuilder to pass a JSON string to `react_component`, make sure your JSON is a stringified hash,
306
- not an array. This is not the Rails default -- you should add the root node yourself. For example:
307
-
308
- ```ruby
309
- # BAD: returns a stringified array
310
- json.array!(@messages) do |message|
311
- json.extract! message, :id, :name
312
- json.url message_url(message, format: :json)
313
- end
314
-
315
- # GOOD: returns a stringified hash
316
- json.messages(@messages) do |message|
317
- json.extract! message, :id, :name
318
- json.url message_url(message, format: :json)
319
- end
320
- ```
321
-
322
- ## CoffeeScript
323
-
324
- It is possible to use JSX with CoffeeScript. To use CoffeeScript, create files with an extension `.js.jsx.coffee`.
325
- We also need to embed JSX code inside backticks so that CoffeeScript ignores the syntax it doesn't understand.
326
- Here's an example:
327
-
328
- ```coffee
329
- Component = React.createClass
330
- render: ->
331
- `<ExampleComponent videos={this.props.videos} />`
332
- ```
333
-
334
- Alternatively, the newer ES6 style class based syntax can be used like this:
335
-
336
- ```coffee
337
- class Component extends React.Component
338
- render: ->
339
- `<ExampleComponent videos={this.props.videos} />`
340
- ```
341
-
342
- ## Extending `react-rails`
343
-
344
- You can extend some of the core functionality of `react-rails` by injecting new implementations during configuration.
345
-
346
- ### Custom Server Renderer
347
-
348
- `react-rails` depends on a renderer class for rendering components on the server. You can provide a custom renderer class to `config.react.server_renderer`. The class must implement:
349
-
350
- - `#initialize(options={})`, which accepts the hash from `config.react.server_renderer_options`
351
- - `#render(component_name, props, prerender_options)` to return a string of HTML
352
-
353
- `react-rails` provides two renderer classes: `React::ServerRendering::ExecJSRenderer` and `React::ServerRendering::SprocketsRenderer`.
354
-
355
- `ExecJSRenderer` offers two other points for extension:
356
-
357
- - `#before_render(component_name, props, prerender_options)` to return a string of JavaScript to execute _before_ calling `React.render`
358
- - `#after_render(component_name, props, prerender_options)` to return a string of JavaScript to execute _after_ calling `React.render`
359
-
360
- Any subclass of `ExecJSRenderer` may use those hooks (for example, `SprocketsRenderer` uses them to handle `console.*` on the server).
361
-
362
- ### Custom View Helper
363
-
364
- `react-rails` uses a "helper implementation" class to generate the output of the `react_component` helper. The helper is initialized once per request and used for each `react_component` call during that request. You can provide a custom helper class to `config.react.view_helper_implementation`. The class must implement:
365
-
366
- - `#react_component(name, props = {}, options = {}, &block)` to return a string to inject into the Rails view
367
- - `#setup(controller_instance)`, called when the helper is initialized at the start of the request
368
- - `#teardown(controller_instance)`, called at the end of the request
369
-
370
- `react-rails` provides one implementation, `React::Rails::ComponentMount`.
371
-
372
- ### Custom JSX Transformer
373
-
374
- `react-rails` uses a transformer class to transform JSX for the browser. The transformer is initialized once, at boot. You can provide a custom transformer to `config.react.jsx_transformer_class`. The transformer must implement:
375
-
376
- - `#initialize(options)`, where options is the value passed to `config.react.jsx_transform_options`
377
- - `#transform(code_string)` to return a string of transformed code
378
-
379
- `react-rails` provides two transformers, `React::JSX::JSXTransformer` and `React::JSX::BabelTransformer`.
380
-
381
- ### Related Projects
382
-
383
- - [react\_on\_rails Gem](https://github.com/shakacode/react_on_rails): Webpack Integration of React with Rails utilizing the modern JavaScript tooling and libraries, including Webpack, Babel, React, Redux, React-Router. You can an example of this live at [www.reactrails.com](http://www.reactrails.com).
384
- - [React.rb](http://reactrb.org/): Use Ruby to build reactive user interfaces with React under the covers.[github source code here](https://github.com/zetachang/react.rb).
385
- - [react-rails-hot-loader](https://github.com/rmosolgo/react-rails-hot-loader) is a simple live-reloader for `react-rails`.
3
+ [![Gem](https://img.shields.io/gem/v/react-rails.svg?style=flat-square)](http://rubygems.org/gems/react-rails)
4
+ [![npm](https://img.shields.io/npm/v/react_ujs.svg?style=flat-square)](https://www.npmjs.com/package/react_ujs)
5
+ [![Ruby](https://github.com/reactjs/react-rails/actions/workflows/ruby.yml/badge.svg)](https://github.com/reactjs/react-rails/actions/workflows/ruby.yml)
6
+
7
+ For version 2.7 documentation, visit the [2.7-stable](https://github.com/reactjs/react-rails/tree/2.7-stable) branch.
8
+
9
+ ## Summary
10
+ React-Rails is a flexible tool to use [React](http://facebook.github.io/react/) with Rails. The benefits:
11
+ * Automatically renders React server-side and client-side
12
+ * Supports [Shakapacker](https://github.com/shakacode/shakapacker) v7
13
+ * Supports Sprockets 4.x, 3.x
14
+ * Lets you use [JSX](http://facebook.github.io/react/docs/jsx-in-depth.html), [ES6](http://es6-features.org/), [TypeScript](https://www.typescriptlang.org/), [CoffeeScript](http://coffeescript.org/)
15
+
16
+ ---
17
+
18
+ While ShakaCode will continue to support this gem, you might consider migrating to [React on Rails](https://github.com/shakacode/react_on_rails) or [React on Rails Pro with proper Node rendering](https://www.shakacode.com/react-on-rails-pro/).
19
+
20
+ Why? React on Rails code receives much more active development and testing. For example, consider the [ReactRailsUJS](https://github.com/reactjs/react-rails/blob/master/react_ujs/index.js) implementation compared to the [ReactOnRails Node package](https://github.com/shakacode/react_on_rails/tree/master/node_package) which is written in TypeScript. For another example, React on Rails has work underway to support the latest React features, such as [React Server Components](https://react.dev/reference/rsc/server-components).
21
+
22
+ You can find [migration to React on Rails steps here](https://github.com/reactjs/react-rails/blob/master/docs/migrating-from-react-rails-to-react_on_rails.md).
23
+
24
+ ---
25
+ ## ShakaCode Support
26
+
27
+ [ShakaCode](https://www.shakacode.com) focuses on helping Ruby on Rails teams use React and Webpack better. We can upgrade your project and improve your development and customer experiences, allowing you to focus on building new features or fixing bugs instead.
28
+
29
+ For an overview of working with us, see our [Client Engagement Model](https://www.shakacode.com/blog/client-engagement-model/) article and [how we bill for time](https://www.shakacode.com/blog/shortcut-jira-trello-github-toggl-time-and-task-tracking/).
30
+
31
+ We also specialize in helping development teams lower infrastructure and CI costs. Check out our project [Control Plane Flow](https://github.com/shakacode/control-plane-flow/), which can allow you to get the ease of Heroku with the power of Kubernetes and big cost savings.
32
+
33
+ If you think ShakaCode can help your project, [click here](https://meetings.hubspot.com/justingordon/30-minute-consultation) to book a call with [Justin Gordon](mailto:justin@shakacode.com), the creator of React on Rails and Shakapacker.
34
+
35
+ Here's a testimonial of how ShakaCode can help from [Florian Gößler](https://github.com/FGoessler) of [Blinkist](https://www.blinkist.com/), January 2, 2023:
36
+ > Hey Justin 👋
37
+ >
38
+ > I just wanted to let you know that we today shipped the webpacker to shakapacker upgrades and it all seems to be running smoothly! Thanks again for all your support and your teams work! 😍
39
+ >
40
+ > On top of your work, it was now also very easy for me to upgrade Tailwind and include our external node_module based web component library which we were using for our other (more modern) apps already. That work is going to be shipped later this week though as we are polishing the last bits of it. 😉
41
+ >
42
+ > Have a great 2023 and maybe we get to work together again later in the year! 🙌
43
+
44
+ Read the [full review here](https://clutch.co/profile/shakacode#reviews?sort_by=date_DESC#review-2118154).
45
+
46
+ ## Resources
47
+ * [Click to join **React + Rails Slack**](https://reactrails.slack.com/join/shared_invite/enQtNjY3NTczMjczNzYxLTlmYjdiZmY3MTVlMzU2YWE0OWM0MzNiZDI0MzdkZGFiZTFkYTFkOGVjODBmOWEyYWQ3MzA2NGE1YWJjNmVlMGE). Then join the channel `#react-rails`.
48
+ * If upgrading, consider migrating to the [react_on_rails](https://github.com/shakacode/react_on_rails) gem.
49
+ * Source code example utilizing React-Rails: https://github.com/BookOfGreg/react-rails-example-app
50
+
51
+ ## Documentation
52
+
53
+ - [Get started](docs/get-started.md)
54
+ - [Use with Shakapacker](docs/get-started.md#use-with-shakapacker)
55
+ - [Component name](docs/get-started.md#component-name)
56
+ - [File naming](docs/get-started.md#file-naming)
57
+ - [Typescript support](docs/get-started.md#typescript-support)
58
+ - [Test component](docs/get-started.md#test-component)
59
+ - [Use with Asset Pipeline](docs/get-started.md#use-with-asset-pipeline)
60
+ - [Custom JSX Transformer](docs/get-started.md#custom-jsx-transformer)
61
+ - [Transform Plugin Options](docs/get-started.md#transform-plugin-options)
62
+ - [React.js versions](docs/get-started.md#reactjs-versions)
63
+ - [View Helper](docs/view-helper.md)
64
+ - [Custom View Helper](docs/view-helper.md#custom-view-helper)
65
+ - [UJS](docs/ujs.md)
66
+ - [Mounting & Unmounting](docs/ujs.md#mounting--unmounting)
67
+ - [Event Handling](docs/ujs.md#event-handling)
68
+ - [`getConstructor`](docs/ujs.md#getconstructor)
69
+ - [Server-Side Rendering](docs/server-side-rendering.md)
70
+ - [Configuration](docs/server-side-rendering.md#configuration)
71
+ - [JavaScript State](docs/server-side-rendering.md#javascript-state)
72
+ - [Custom Server Renderer](docs/server-side-rendering.md#custom-server-renderer)
73
+ - [Controller Actions](docs/controller-actions.md)
74
+ - [Component Generator](docs/component-generator.md)
75
+ - [Use with JBuilder](docs/component-generator.md#use-with-jbuilder)
76
+ - [Camelize Props](docs/component-generator.md#camelize-props)
77
+ - [Changing Component Templates](docs/component-generator.md#changing-component-templates)
78
+ - [Upgrading](docs/upgrading.md)
79
+ - [2.7 to 3.0](docs/upgrading.md#27-to-30)
80
+ - [2.3 to 2.4](docs/upgrading.md#23-to-24)
81
+ - [Migrating from `react-rails` to `react_on_rails`](docs/migrating-from-react-rails-to-react_on_rails.md)
82
+ - [Why migrate?](docs/migrating-from-react-rails-to-react_on_rails.md#why-migrate)
83
+ - [Steps to migrate](docs/migrating-from-react-rails-to-react_on_rails.md#steps-to-migrate)
84
+ - [Common Errors](docs/common-errors.md)
85
+ - [Getting warning for `Can't resolve 'react-dom/client'` in React < 18](docs/common-errors.md#getting-warning-for-cant-resolve-react-domclient-in-react--18)
86
+ - [Undefined Set](docs/common-errors.md#undefined-set)
87
+ - [Using TheRubyRacer](docs/common-errors.md#using-therubyracer)
88
+ - [HMR](docs/common-errors.md#hmr)
89
+ - [Tests in component directory](docs/common-errors.md#tests-in-component-directory)
90
+
91
+ After reading this README file, additional information about React-Rails can be found on the Wiki page:
92
+ https://github.com/reactjs/React-Rails/wiki
93
+ The Wiki page features a significant amount of additional information about React-Rails, including instructional articles and answers to the most frequently asked questions.
94
+
95
+ ## Related Projects
96
+
97
+ - [react\_on\_rails](https://github.com/shakacode/react_on_rails): Integration of React with Rails utilizing Webpack, Redux, React-Router.
98
+ - [React on Rails Pro](https://www.shakacode.com/react-on-rails-pro/):React on Rails with Node rendering and many other performance enhancements.
386
99
  - [react-rails-benchmark_renderer](https://github.com/pboling/react-rails-benchmark_renderer) adds performance instrumentation to server rendering.
387
-
388
- ## Development
389
-
390
- - Run tests with `rake test` or `appraisal rake test`
391
- - Update React assets with `rake react:update`
100
+ - [Ruby Hyperstack](https://hyperstack.org/): Use Ruby to build reactive user interfaces with React.
101
+
102
+ ## Contributing
103
+
104
+ 🎉 Thanks for taking the time to contribute! 🎉 See [CONTRIBUTING.md](./CONTRIBUTING.md) for more details.
105
+
106
+ # Supporters
107
+
108
+ The following companies provide licenses to the ShakaCode team, supporting the development of this and other open-source projects maintained by ShakaCode. ShakaCode stands by the usefulness of these products!
109
+
110
+ <br />
111
+ <br />
112
+
113
+ <a href="https://www.jetbrains.com">
114
+ <img src="https://user-images.githubusercontent.com/4244251/184881139-42e4076b-024b-4b30-8c60-c3cd0e758c0a.png" alt="JetBrains" height="120px">
115
+ </a>
116
+ <a href="https://scoutapp.com">
117
+ <picture>
118
+ <source media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/4244251/184881147-0d077438-3978-40da-ace9-4f650d2efe2e.png">
119
+ <source media="(prefers-color-scheme: light)" srcset="https://user-images.githubusercontent.com/4244251/184881152-9f2d8fba-88ac-4ba6-873b-22387f8711c5.png">
120
+ <img alt="ScoutAPM" src="https://user-images.githubusercontent.com/4244251/184881152-9f2d8fba-88ac-4ba6-873b-22387f8711c5.png" height="120px">
121
+ </picture>
122
+ </a>
123
+ <a href="https://controlplane.com">
124
+ <picture>
125
+ <img alt="Control Plane" src="https://github.com/shakacode/.github/assets/20628911/90babd87-62c4-4de3-baa4-3d78ef4bec25" height="120px">
126
+ </picture>
127
+ </a>
128
+ <br />
129
+ <a href="https://www.browserstack.com">
130
+ <picture>
131
+ <source media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/4244251/184881122-407dcc29-df78-4b20-a9ad-f597b56f6cdb.png">
132
+ <source media="(prefers-color-scheme: light)" srcset="https://user-images.githubusercontent.com/4244251/184881129-e1edf4b7-3ae1-4ea8-9e6d-3595cf01609e.png">
133
+ <img alt="BrowserStack" src="https://user-images.githubusercontent.com/4244251/184881129-e1edf4b7-3ae1-4ea8-9e6d-3595cf01609e.png" height="55px">
134
+ </picture>
135
+ </a>
136
+
137
+ ---
138
+
139
+ ShakaCode is [hiring](https://jobs.lever.co/shakacode/3bdbfdb3-4495-4611-a279-01dddddb351abe)!
@@ -15708,22 +15708,22 @@ function addDisplayName(displayName, object, state) {
15708
15708
  /**
15709
15709
  * Transforms the following:
15710
15710
  *
15711
- * var MyComponent = React.createClass({
15711
+ * var MyComponent = createReactClass({
15712
15712
  * render: ...
15713
15713
  * });
15714
15714
  *
15715
15715
  * into:
15716
15716
  *
15717
- * var MyComponent = React.createClass({
15717
+ * var MyComponent = createReactClass({
15718
15718
  * displayName: 'MyComponent',
15719
15719
  * render: ...
15720
15720
  * });
15721
15721
  *
15722
15722
  * Also catches:
15723
15723
  *
15724
- * MyComponent = React.createClass(...);
15725
- * exports.MyComponent = React.createClass(...);
15726
- * module.exports = {MyComponent: React.createClass(...)};
15724
+ * MyComponent = createReactClass(...);
15725
+ * exports.MyComponent = createReactClass(...);
15726
+ * module.exports = {MyComponent: createReactClass(...)};
15727
15727
  */
15728
15728
  function visitReactDisplayName(traverse, object, path, state) {
15729
15729
  var left, right;
@@ -15916,4 +15916,4 @@ function inlineSourceMap(sourceMap, sourceCode, sourceFilename) {
15916
15916
  module.exports = inlineSourceMap;
15917
15917
 
15918
15918
  },{"buffer":3}]},{},[1])(1)
15919
- });
15919
+ });
@@ -1,7 +1 @@
1
- //= require react_ujs_mount
2
- //= require react_ujs_turbolinks
3
- //= require react_ujs_turbolinks_classic
4
- //= require react_ujs_turbolinks_classic_deprecated
5
- //= require react_ujs_pjax
6
- //= require react_ujs_native
7
- //= require react_ujs_event_setup
1
+ !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("react"),require("react-dom"),require("react-dom/server")):"function"==typeof define&&define.amd?define(["react","react-dom","react-dom/server"],t):"object"==typeof exports?exports.ReactRailsUJS=t(require("react"),require("react-dom"),require("react-dom/server")):e.ReactRailsUJS=t(e.React,e.ReactDOM,e.ReactDOMServer)}(self,((__WEBPACK_EXTERNAL_MODULE__787__,__WEBPACK_EXTERNAL_MODULE__156__,__WEBPACK_EXTERNAL_MODULE__997__)=>(()=>{var __webpack_modules__={634:(e,t,n)=>{"use strict";var o=n(156);t.createRoot=o.createRoot,t.hydrateRoot=o.hydrateRoot},10:(e,t,n)=>{var o=n(787),r=n(156),a=n(997),u=n(230),c=n(121),i=n(831),d=n(37),s=n(39),{supportsHydration:_,reactHydrate:l,createReactRootLike:p}=n(198),f=n(613),v={CLASS_NAME_ATTR:"data-react-class",PROPS_ATTR:"data-react-props",RENDER_ATTR:"data-hydrate",CACHE_ID_ATTR:"data-react-cache-id",TURBOLINKS_PERMANENT_ATTR:"data-turbolinks-permanent",jQuery:"undefined"!=typeof window&&void 0!==window.jQuery&&window.jQuery,components:{},roots:[],findDOMNodes:function(e){var t,n,o=v.CLASS_NAME_ATTR;switch(typeof e){case"undefined":t="["+o+"]",n=document;break;case"object":t="["+o+"]",n=e;break;case"string":t=e+"["+o+"], "+e+" ["+o+"]",n=document}return v.jQuery?v.jQuery(t,n):n.querySelectorAll(t)},getConstructor:c,constructorFromGlobal:c,constructorFromRequireContext:i,constructorFromRequireContextWithGlobalFallback:d,useContext:function(e){this.getConstructor=d(e)},useContexts:function(e){this.getConstructor=s(e)},serverRender:function(e,t,n){var r=this.getConstructor(t),u=o.createElement(r,n);return a[e](u)},mountComponents:function(e){for(var t=v,n=t.findDOMNodes(e),r=0;r<n.length;++r){var a=n[r],u=a.getAttribute(t.CLASS_NAME_ATTR),c=t.getConstructor(u),i=a.getAttribute(t.PROPS_ATTR),d=i&&JSON.parse(i),s=a.getAttribute(t.RENDER_ATTR),p=a.getAttribute(t.CACHE_ID_ATTR),f=a.hasAttribute(t.TURBOLINKS_PERMANENT_ATTR);if(!c){var E="Cannot find component: '"+u+"'";throw console&&console.log&&console.log("%c[react-rails] %c"+E+" for element","font-weight: bold","",a),new Error(E+". Make sure your component is available to render.")}var h=this.components[p];void 0===h&&(h=o.createElement(c,d),f&&(this.components[p]=h)),h=s&&_()?l(a,h):this.findOrCreateRoot(a).render(h)}},unmountComponents:function(e){for(var t=v.findDOMNodes(e),n=0;n<t.length;++n){var o=t[n];f?this.unmountRoot(o):r.unmountComponentAtNode(o)}},detectEvents:function(){u(this)},findOrCreateRoot:function(e){var t=this.findRoot(e);return t||(t=p(e),f&&this.roots.push({node:e,root:t})),t},findRoot:function(e){if(f){var t=this.roots.find((function(t){return t.node&&t.node===e}));return t?t.root:void 0}},unmountRoot:function(e){var t=this.findRoot(e);t&&(t.unmount(),this.roots=this.roots.filter((function(t){return t.node!==e})))},handleMount:function(e){var t=void 0;e&&e.target&&(t=e.target),v.mountComponents(t)},handleUnmount:function(e){var t=void 0;e&&e.target&&(t=e.target),v.unmountComponents(t)}};"undefined"!=typeof window&&v.detectEvents(),self.ReactRailsUJS=v,e.exports=v},230:(e,t,n)=>{var o=n(528),r=n(921),a=n(228),u=n(724),c=n(968);e.exports=function(e){e.handleEvent&&("undefined"!=typeof Turbolinks&&void 0!==Turbolinks.EVENTS&&c.teardown(e),a.teardown(e),u.teardown(e),r.teardown(e),o.teardown(e)),"addEventListener"in window?(e.handleEvent=function(e,t){document.addEventListener(e,t)},e.removeEvent=function(e,t){document.removeEventListener(e,t)}):(e.handleEvent=function(e,t){window.attachEvent(e,t)},e.removeEvent=function(e,t){window.detachEvent(e,t)}),"undefined"!=typeof Turbolinks&&Turbolinks.supported?void 0!==Turbolinks.EVENTS?c.setup(e):void 0!==Turbolinks.controller?a.setup(e):u.setup(e):"undefined"!=typeof $&&"function"==typeof $.pjax?r.setup(e):o.setup(e)}},528:e=>{e.exports={setup:function(e){"addEventListener"in window?e.handleEvent("DOMContentLoaded",e.handleMount):e.handleEvent("onload",e.handleMount)},teardown:function(e){e.removeEvent("DOMContentLoaded",e.handleMount),e.removeEvent("onload",e.handleMount)}}},921:e=>{e.exports={setup:function(e){e.handleEvent("ready",e.handleMount),e.handleEvent("pjax:end",e.handleMount),e.handleEvent("pjax:beforeReplace",e.handleUnmount)},teardown:function(e){e.removeEvent("ready",e.handleMount),e.removeEvent("pjax:end",e.handleMount),e.removeEvent("pjax:beforeReplace",e.handleUnmount)}}},228:e=>{e.exports={setup:function(e){e.handleEvent("turbolinks:load",e.handleMount)},teardown:function(e){e.removeEvent("turbolinks:load",e.handleMount)}}},968:e=>{e.exports={setup:function(e){e.handleEvent(Turbolinks.EVENTS.CHANGE,e.handleMount),e.handleEvent(Turbolinks.EVENTS.BEFORE_UNLOAD,e.handleUnmount)},teardown:function(e){e.removeEvent(Turbolinks.EVENTS.CHANGE,e.handleMount),e.removeEvent(Turbolinks.EVENTS.BEFORE_UNLOAD,e.handleUnmount)}}},724:e=>{e.exports={setup:function(e){Turbolinks.pagesCached(0),e.handleEvent("page:change",e.handleMount),e.handleEvent("page:receive",e.handleUnmount)},teardown:function(e){e.removeEvent("page:change",e.handleMount),e.removeEvent("page:receive",e.handleUnmount)}}},121:function(module){var topLevel="undefined"==typeof window?this:window;module.exports=function(className){var constructor;return constructor=topLevel[className],constructor||(constructor=eval(className)),constructor&&constructor.default&&(constructor=constructor.default),constructor}},831:e=>{e.exports=function(e){return function(t){var n=t.split("."),o=n.shift(),r=n,a=e("./"+o);return r.forEach((function(e){a=a[e]})),a.__esModule&&(a=a.default),a}}},37:(e,t,n)=>{var o=n(121),r=n(831);e.exports=function(e){var t=r(e);return function(e){var n;try{n=t(e)}catch(t){try{n=o(e)}catch(e){console.error(t),console.error(e)}}return n}}},39:(e,t,n)=>{var o=n(121),r=n(831);e.exports=function(e){var t=e.map((e=>r(e)));return function(e){var n;try{var r,a,u=0;do{r=t[u];try{n=r(e)}catch(e){a||(a=e)}u+=1}while(u<t.length);if(!n)throw a}catch(a){try{n=o(e)}catch(e){console.error(a),console.error(e)}}return n}}},198:(e,t,n)=>{"use strict";n.r(t),n.d(t,{createReactRootLike:()=>_,reactHydrate:()=>s,supportsHydration:()=>d});var o=n(156),r=n.n(o),a=n(613),u=n.n(a);let c=r();if(u())try{c=n(634)}catch(e){c=r()}const i=c;function d(){return"function"==typeof i.hydrate||"function"==typeof i.hydrateRoot}function s(e,t){return"function"==typeof i.hydrateRoot?i.hydrateRoot(e,t):i.hydrate(t,e)}function _(e){return u()?i.createRoot(e):function(e){return{render:t=>i.render(t,e)}}(e)}},613:(e,t,n)=>{var o,r=n(156);o=void 0!==r&&(r.version.split(".")[0]||16)>=18,e.exports=o},787:e=>{"use strict";e.exports=__WEBPACK_EXTERNAL_MODULE__787__},156:e=>{"use strict";e.exports=__WEBPACK_EXTERNAL_MODULE__156__},997:e=>{"use strict";e.exports=__WEBPACK_EXTERNAL_MODULE__997__}},__webpack_module_cache__={};function __webpack_require__(e){var t=__webpack_module_cache__[e];if(void 0!==t)return t.exports;var n=__webpack_module_cache__[e]={exports:{}};return __webpack_modules__[e].call(n.exports,n,n.exports,__webpack_require__),n.exports}__webpack_require__.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return __webpack_require__.d(t,{a:t}),t},__webpack_require__.d=(e,t)=>{for(var n in t)__webpack_require__.o(t,n)&&!__webpack_require__.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},__webpack_require__.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),__webpack_require__.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};var __webpack_exports__=__webpack_require__(10);return __webpack_exports__})()));