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.
- checksums.yaml +5 -5
- data/CHANGELOG.md +345 -9
- data/README.md +137 -389
- data/lib/assets/javascripts/JSXTransformer.js +6 -6
- data/lib/assets/javascripts/react_ujs.js +1 -7
- data/lib/assets/react-source/development/react-server.js +423 -21528
- data/lib/assets/react-source/development/react.js +191 -21409
- data/lib/assets/react-source/production/react-server.js +2 -19
- data/lib/assets/react-source/production/react.js +2 -19
- data/lib/generators/react/component_generator.rb +203 -73
- data/lib/generators/react/install_generator.rb +98 -25
- data/lib/generators/templates/component.es6.jsx +9 -12
- data/lib/generators/templates/component.es6.tsx +24 -0
- data/lib/generators/templates/component.js.jsx +15 -18
- data/lib/generators/templates/component.js.jsx.coffee +5 -8
- data/lib/generators/templates/component.js.jsx.tsx +36 -0
- data/lib/generators/templates/react_server_rendering.rb +4 -0
- data/lib/generators/templates/server_rendering.js +6 -0
- data/lib/generators/templates/server_rendering_pack.js +5 -0
- data/lib/react/jsx/babel_transformer.rb +12 -6
- data/lib/react/jsx/jsx_transformer.rb +7 -6
- data/lib/react/jsx/processor.rb +3 -1
- data/lib/react/jsx/sprockets_strategy.rb +12 -6
- data/lib/react/jsx/template.rb +7 -6
- data/lib/react/jsx.rb +11 -7
- data/lib/react/rails/asset_variant.rb +7 -8
- data/lib/react/rails/component_mount.rb +48 -14
- data/lib/react/rails/controller_lifecycle.rb +36 -7
- data/lib/react/rails/controller_renderer.rb +13 -4
- data/lib/react/rails/railtie.rb +34 -29
- data/lib/react/rails/test_helper.rb +25 -0
- data/lib/react/rails/version.rb +4 -2
- data/lib/react/rails/view_helper.rb +3 -1
- data/lib/react/rails.rb +9 -7
- data/lib/react/server_rendering/{sprockets_renderer → bundle_renderer}/console_replay.js +1 -1
- data/lib/react/server_rendering/bundle_renderer/console_reset.js +3 -0
- data/lib/react/server_rendering/bundle_renderer/timeout_polyfill.js +26 -0
- data/lib/react/server_rendering/bundle_renderer.rb +117 -0
- data/lib/react/server_rendering/environment_container.rb +2 -0
- data/lib/react/server_rendering/exec_js_renderer.rb +43 -16
- data/lib/react/server_rendering/manifest_container.rb +5 -1
- data/lib/react/server_rendering/separate_server_bundle_container.rb +19 -0
- data/lib/react/server_rendering/yaml_manifest_container.rb +12 -4
- data/lib/react/server_rendering.rb +26 -12
- data/lib/react-rails.rb +12 -4
- data/lib/react.rb +8 -4
- metadata +106 -41
- data/lib/assets/javascripts/react_ujs_event_setup.js +0 -29
- data/lib/assets/javascripts/react_ujs_mount.js +0 -104
- data/lib/assets/javascripts/react_ujs_native.js +0 -18
- data/lib/assets/javascripts/react_ujs_pjax.js +0 -10
- data/lib/assets/javascripts/react_ujs_turbolinks.js +0 -9
- data/lib/assets/javascripts/react_ujs_turbolinks_classic.js +0 -10
- data/lib/assets/javascripts/react_ujs_turbolinks_classic_deprecated.js +0 -13
- data/lib/assets/react-source/development-with-addons/react-server.js +0 -24053
- data/lib/assets/react-source/development-with-addons/react.js +0 -23890
- data/lib/assets/react-source/production-with-addons/react-server.js +0 -19
- data/lib/assets/react-source/production-with-addons/react.js +0 -19
- data/lib/generators/react/ujs_generator.rb +0 -44
- data/lib/react/server_rendering/sprockets_renderer.rb +0 -79
- /data/lib/react/server_rendering/{sprockets_renderer → bundle_renderer}/console_polyfill.js +0 -0
data/README.md
CHANGED
@@ -1,391 +1,139 @@
|
|
1
|
-
|
2
|
-
[](https://travis-ci.org/reactjs/react-rails)
|
3
|
-
[](https://gemnasium.com/reactjs/react-rails)
|
4
|
-
[](https://codeclimate.com/github/reactjs/react-rails)
|
5
|
-
[](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="{"name":"John"}"></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="{"name":"John"}">
|
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
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
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
|
+
[](http://rubygems.org/gems/react-rails)
|
4
|
+
[](https://www.npmjs.com/package/react_ujs)
|
5
|
+
[](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
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
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 =
|
15711
|
+
* var MyComponent = createReactClass({
|
15712
15712
|
* render: ...
|
15713
15713
|
* });
|
15714
15714
|
*
|
15715
15715
|
* into:
|
15716
15716
|
*
|
15717
|
-
* var MyComponent =
|
15717
|
+
* var MyComponent = createReactClass({
|
15718
15718
|
* displayName: 'MyComponent',
|
15719
15719
|
* render: ...
|
15720
15720
|
* });
|
15721
15721
|
*
|
15722
15722
|
* Also catches:
|
15723
15723
|
*
|
15724
|
-
* MyComponent =
|
15725
|
-
* exports.MyComponent =
|
15726
|
-
* module.exports = {MyComponent:
|
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
|
-
|
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__})()));
|