react-rails-stupid 1.5.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +201 -0
- data/README.md +423 -0
- data/lib/react/rails/component_mount.rb +52 -0
- data/lib/react/rails/version.rb +7 -0
- data/lib/react/rails/view_helper.rb +25 -0
- data/lib/react/rails.rb +3 -0
- data/lib/react-rails-stupid.rb +1 -0
- metadata +121 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: a9438b66a924541d0d5cd30245eecf8e8485be39e8ce11481347cefdb67c8db1
|
4
|
+
data.tar.gz: c30a7dfb638a2cc96c360bd00494fb0c12d8269c889ba907b717f7fb26089071
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 509dab980a0931502243251a96f4230b192822254c612a38caef85da3df1971e029f7d68dbd2dd15e22feb9edb1a66f2c4f11b9cb3632f4074e9146f59c21cc8
|
7
|
+
data.tar.gz: 27515b984ff1944d42042b80f50eb6836e7b5aba18925a64773b9fb923829f57e5a0e42c3faadf729fc9bc3a49eeb510477a407a0b49e92c01e48c35eb358729
|
data/LICENSE
ADDED
@@ -0,0 +1,201 @@
|
|
1
|
+
Apache License
|
2
|
+
Version 2.0, January 2004
|
3
|
+
http://www.apache.org/licenses/
|
4
|
+
|
5
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
6
|
+
|
7
|
+
1. Definitions.
|
8
|
+
|
9
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
10
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
11
|
+
|
12
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
13
|
+
the copyright owner that is granting the License.
|
14
|
+
|
15
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
16
|
+
other entities that control, are controlled by, or are under common
|
17
|
+
control with that entity. For the purposes of this definition,
|
18
|
+
"control" means (i) the power, direct or indirect, to cause the
|
19
|
+
direction or management of such entity, whether by contract or
|
20
|
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
21
|
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
22
|
+
|
23
|
+
"You" (or "Your") shall mean an individual or Legal Entity
|
24
|
+
exercising permissions granted by this License.
|
25
|
+
|
26
|
+
"Source" form shall mean the preferred form for making modifications,
|
27
|
+
including but not limited to software source code, documentation
|
28
|
+
source, and configuration files.
|
29
|
+
|
30
|
+
"Object" form shall mean any form resulting from mechanical
|
31
|
+
transformation or translation of a Source form, including but
|
32
|
+
not limited to compiled object code, generated documentation,
|
33
|
+
and conversions to other media types.
|
34
|
+
|
35
|
+
"Work" shall mean the work of authorship, whether in Source or
|
36
|
+
Object form, made available under the License, as indicated by a
|
37
|
+
copyright notice that is included in or attached to the work
|
38
|
+
(an example is provided in the Appendix below).
|
39
|
+
|
40
|
+
"Derivative Works" shall mean any work, whether in Source or Object
|
41
|
+
form, that is based on (or derived from) the Work and for which the
|
42
|
+
editorial revisions, annotations, elaborations, or other modifications
|
43
|
+
represent, as a whole, an original work of authorship. For the purposes
|
44
|
+
of this License, Derivative Works shall not include works that remain
|
45
|
+
separable from, or merely link (or bind by name) to the interfaces of,
|
46
|
+
the Work and Derivative Works thereof.
|
47
|
+
|
48
|
+
"Contribution" shall mean any work of authorship, including
|
49
|
+
the original version of the Work and any modifications or additions
|
50
|
+
to that Work or Derivative Works thereof, that is intentionally
|
51
|
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
52
|
+
or by an individual or Legal Entity authorized to submit on behalf of
|
53
|
+
the copyright owner. For the purposes of this definition, "submitted"
|
54
|
+
means any form of electronic, verbal, or written communication sent
|
55
|
+
to the Licensor or its representatives, including but not limited to
|
56
|
+
communication on electronic mailing lists, source code control systems,
|
57
|
+
and issue tracking systems that are managed by, or on behalf of, the
|
58
|
+
Licensor for the purpose of discussing and improving the Work, but
|
59
|
+
excluding communication that is conspicuously marked or otherwise
|
60
|
+
designated in writing by the copyright owner as "Not a Contribution."
|
61
|
+
|
62
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
63
|
+
on behalf of whom a Contribution has been received by Licensor and
|
64
|
+
subsequently incorporated within the Work.
|
65
|
+
|
66
|
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
67
|
+
this License, each Contributor hereby grants to You a perpetual,
|
68
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
69
|
+
copyright license to reproduce, prepare Derivative Works of,
|
70
|
+
publicly display, publicly perform, sublicense, and distribute the
|
71
|
+
Work and such Derivative Works in Source or Object form.
|
72
|
+
|
73
|
+
3. Grant of Patent License. Subject to the terms and conditions of
|
74
|
+
this License, each Contributor hereby grants to You a perpetual,
|
75
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
76
|
+
(except as stated in this section) patent license to make, have made,
|
77
|
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
78
|
+
where such license applies only to those patent claims licensable
|
79
|
+
by such Contributor that are necessarily infringed by their
|
80
|
+
Contribution(s) alone or by combination of their Contribution(s)
|
81
|
+
with the Work to which such Contribution(s) was submitted. If You
|
82
|
+
institute patent litigation against any entity (including a
|
83
|
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
84
|
+
or a Contribution incorporated within the Work constitutes direct
|
85
|
+
or contributory patent infringement, then any patent licenses
|
86
|
+
granted to You under this License for that Work shall terminate
|
87
|
+
as of the date such litigation is filed.
|
88
|
+
|
89
|
+
4. Redistribution. You may reproduce and distribute copies of the
|
90
|
+
Work or Derivative Works thereof in any medium, with or without
|
91
|
+
modifications, and in Source or Object form, provided that You
|
92
|
+
meet the following conditions:
|
93
|
+
|
94
|
+
(a) You must give any other recipients of the Work or
|
95
|
+
Derivative Works a copy of this License; and
|
96
|
+
|
97
|
+
(b) You must cause any modified files to carry prominent notices
|
98
|
+
stating that You changed the files; and
|
99
|
+
|
100
|
+
(c) You must retain, in the Source form of any Derivative Works
|
101
|
+
that You distribute, all copyright, patent, trademark, and
|
102
|
+
attribution notices from the Source form of the Work,
|
103
|
+
excluding those notices that do not pertain to any part of
|
104
|
+
the Derivative Works; and
|
105
|
+
|
106
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
107
|
+
distribution, then any Derivative Works that You distribute must
|
108
|
+
include a readable copy of the attribution notices contained
|
109
|
+
within such NOTICE file, excluding those notices that do not
|
110
|
+
pertain to any part of the Derivative Works, in at least one
|
111
|
+
of the following places: within a NOTICE text file distributed
|
112
|
+
as part of the Derivative Works; within the Source form or
|
113
|
+
documentation, if provided along with the Derivative Works; or,
|
114
|
+
within a display generated by the Derivative Works, if and
|
115
|
+
wherever such third-party notices normally appear. The contents
|
116
|
+
of the NOTICE file are for informational purposes only and
|
117
|
+
do not modify the License. You may add Your own attribution
|
118
|
+
notices within Derivative Works that You distribute, alongside
|
119
|
+
or as an addendum to the NOTICE text from the Work, provided
|
120
|
+
that such additional attribution notices cannot be construed
|
121
|
+
as modifying the License.
|
122
|
+
|
123
|
+
You may add Your own copyright statement to Your modifications and
|
124
|
+
may provide additional or different license terms and conditions
|
125
|
+
for use, reproduction, or distribution of Your modifications, or
|
126
|
+
for any such Derivative Works as a whole, provided Your use,
|
127
|
+
reproduction, and distribution of the Work otherwise complies with
|
128
|
+
the conditions stated in this License.
|
129
|
+
|
130
|
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
131
|
+
any Contribution intentionally submitted for inclusion in the Work
|
132
|
+
by You to the Licensor shall be under the terms and conditions of
|
133
|
+
this License, without any additional terms or conditions.
|
134
|
+
Notwithstanding the above, nothing herein shall supersede or modify
|
135
|
+
the terms of any separate license agreement you may have executed
|
136
|
+
with Licensor regarding such Contributions.
|
137
|
+
|
138
|
+
6. Trademarks. This License does not grant permission to use the trade
|
139
|
+
names, trademarks, service marks, or product names of the Licensor,
|
140
|
+
except as required for reasonable and customary use in describing the
|
141
|
+
origin of the Work and reproducing the content of the NOTICE file.
|
142
|
+
|
143
|
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
144
|
+
agreed to in writing, Licensor provides the Work (and each
|
145
|
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
146
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
147
|
+
implied, including, without limitation, any warranties or conditions
|
148
|
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
149
|
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
150
|
+
appropriateness of using or redistributing the Work and assume any
|
151
|
+
risks associated with Your exercise of permissions under this License.
|
152
|
+
|
153
|
+
8. Limitation of Liability. In no event and under no legal theory,
|
154
|
+
whether in tort (including negligence), contract, or otherwise,
|
155
|
+
unless required by applicable law (such as deliberate and grossly
|
156
|
+
negligent acts) or agreed to in writing, shall any Contributor be
|
157
|
+
liable to You for damages, including any direct, indirect, special,
|
158
|
+
incidental, or consequential damages of any character arising as a
|
159
|
+
result of this License or out of the use or inability to use the
|
160
|
+
Work (including but not limited to damages for loss of goodwill,
|
161
|
+
work stoppage, computer failure or malfunction, or any and all
|
162
|
+
other commercial damages or losses), even if such Contributor
|
163
|
+
has been advised of the possibility of such damages.
|
164
|
+
|
165
|
+
9. Accepting Warranty or Additional Liability. While redistributing
|
166
|
+
the Work or Derivative Works thereof, You may choose to offer,
|
167
|
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
168
|
+
or other liability obligations and/or rights consistent with this
|
169
|
+
License. However, in accepting such obligations, You may act only
|
170
|
+
on Your own behalf and on Your sole responsibility, not on behalf
|
171
|
+
of any other Contributor, and only if You agree to indemnify,
|
172
|
+
defend, and hold each Contributor harmless for any liability
|
173
|
+
incurred by, or claims asserted against, such Contributor by reason
|
174
|
+
of your accepting any such warranty or additional liability.
|
175
|
+
|
176
|
+
END OF TERMS AND CONDITIONS
|
177
|
+
|
178
|
+
APPENDIX: How to apply the Apache License to your work.
|
179
|
+
|
180
|
+
To apply the Apache License to your work, attach the following
|
181
|
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
182
|
+
replaced with your own identifying information. (Don't include
|
183
|
+
the brackets!) The text should be enclosed in the appropriate
|
184
|
+
comment syntax for the file format. We also recommend that a
|
185
|
+
file or class name and description of purpose be included on the
|
186
|
+
same "printed page" as the copyright notice for easier
|
187
|
+
identification within third-party archives.
|
188
|
+
|
189
|
+
Copyright [yyyy] [name of copyright owner]
|
190
|
+
|
191
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
192
|
+
you may not use this file except in compliance with the License.
|
193
|
+
You may obtain a copy of the License at
|
194
|
+
|
195
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
196
|
+
|
197
|
+
Unless required by applicable law or agreed to in writing, software
|
198
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
199
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
200
|
+
See the License for the specific language governing permissions and
|
201
|
+
limitations under the License.
|
data/README.md
ADDED
@@ -0,0 +1,423 @@
|
|
1
|
+
# react-rails-stupid
|
2
|
+
|
3
|
+
the call
|
4
|
+
`react_component 'Button', text: 'click me'`
|
5
|
+
|
6
|
+
ensures some html: `<div data-react-class="Button" data-react-props="{...}"/>`
|
7
|
+
|
8
|
+
next, you can use separeted frontend with a helper
|
9
|
+
|
10
|
+
<details><summary>the helper</summary>
|
11
|
+
|
12
|
+
```js
|
13
|
+
function get(obj, path){ return path.split('.').reduce((obj, key) => obj[key], obj) }
|
14
|
+
|
15
|
+
[...document.querySelectorAll('[data-react-class]')].forEach((root) => {
|
16
|
+
ReactDOM.render(
|
17
|
+
React.createElement(
|
18
|
+
get(window, root.dataset.reactClass),
|
19
|
+
JSON.parse(root.dataset.reactProps)
|
20
|
+
),
|
21
|
+
root
|
22
|
+
)
|
23
|
+
})
|
24
|
+
```
|
25
|
+
|
26
|
+
</details>
|
27
|
+
|
28
|
+
`window.Button` expected
|
29
|
+
|
30
|
+
also, you can use nested objects as a react components like `User.Title`
|
31
|
+
|
32
|
+
usage:
|
33
|
+
|
34
|
+
js: `window.User = { Title };`
|
35
|
+
|
36
|
+
rb: `react_component 'User.Title', name: 'Evan Smith'`
|
37
|
+
|
38
|
+
|
39
|
+
<br/><br/><br/><br/>
|
40
|
+
|
41
|
+
|
42
|
+
|
43
|
+
# Original readme
|
44
|
+
|
45
|
+
`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)
|
46
|
+
in your Ruby on Rails (3.2+) application. `react-rails` can:
|
47
|
+
|
48
|
+
- Provide [various `react` builds](#reactjs-builds) to your asset bundle
|
49
|
+
- Transform [`.jsx` in the asset pipeline](#jsx)
|
50
|
+
- [Render components into views and mount them](#rendering--mounting) via view helper & `react_ujs`
|
51
|
+
- [Render components server-side](#server-rendering) with `prerender: true`
|
52
|
+
- [Generate components](#component-generator) with a Rails generator
|
53
|
+
- [Be extended](#extending-react-rails) with custom renderers, transformers and view helpers
|
54
|
+
|
55
|
+
Just getting started with React? Make sure to check out the [Getting Started] (https://facebook.github.io/react/docs/getting-started.html) guide.
|
56
|
+
|
57
|
+
## Installation
|
58
|
+
|
59
|
+
Add `react-rails` to your gemfile:
|
60
|
+
|
61
|
+
```ruby
|
62
|
+
gem 'react-rails', '~> 1.5.0'
|
63
|
+
```
|
64
|
+
|
65
|
+
Next, run the installation script:
|
66
|
+
|
67
|
+
```bash
|
68
|
+
rails g react:install
|
69
|
+
```
|
70
|
+
|
71
|
+
This will:
|
72
|
+
- create a `components.js` manifest file and a `app/assets/javascripts/components/` directory,
|
73
|
+
where you will put your components
|
74
|
+
- place the following in your `application.js`:
|
75
|
+
|
76
|
+
```js
|
77
|
+
//= require react
|
78
|
+
//= require react_ujs
|
79
|
+
//= require components
|
80
|
+
```
|
81
|
+
|
82
|
+
## Usage
|
83
|
+
|
84
|
+
### React.js builds
|
85
|
+
|
86
|
+
You can pick which React.js build (development, production, with or without [add-ons]((http://facebook.github.io/react/docs/addons.html)))
|
87
|
+
to serve in each environment by adding a config. Here are the defaults:
|
88
|
+
|
89
|
+
```ruby
|
90
|
+
# config/environments/development.rb
|
91
|
+
MyApp::Application.configure do
|
92
|
+
config.react.variant = :development
|
93
|
+
end
|
94
|
+
|
95
|
+
# config/environments/production.rb
|
96
|
+
MyApp::Application.configure do
|
97
|
+
config.react.variant = :production
|
98
|
+
end
|
99
|
+
```
|
100
|
+
|
101
|
+
To include add-ons, use this config:
|
102
|
+
|
103
|
+
```ruby
|
104
|
+
MyApp::Application.configure do
|
105
|
+
config.react.addons = true # defaults to false
|
106
|
+
end
|
107
|
+
```
|
108
|
+
|
109
|
+
After restarting your Rails server, `//= require react` will provide the build of React.js which
|
110
|
+
was specified by the configurations.
|
111
|
+
|
112
|
+
`react-rails` offers a few other options for versions & builds of React.js.
|
113
|
+
See [VERSIONS.md](https://github.com/reactjs/react-rails/blob/master/VERSIONS.md) for more info about
|
114
|
+
using the `react-source` gem or dropping in your own copies of React.js.
|
115
|
+
|
116
|
+
### JSX
|
117
|
+
|
118
|
+
After installing `react-rails`, restart your server. Now, `.js.jsx` files will be transformed in the asset pipeline.
|
119
|
+
|
120
|
+
`react-rails` currently ships with two transformers, to convert jsx code -
|
121
|
+
|
122
|
+
* `BabelTransformer` using [Babel](http://babeljs.io), which is the default transformer.
|
123
|
+
* `JSXTransformer` using `JSXTransformer.js`
|
124
|
+
|
125
|
+
You can use the deprecated `JSXTransformer` by setting it in an application config:
|
126
|
+
|
127
|
+
```ruby
|
128
|
+
config.react.jsx_transformer_class = React::JSX::JSXTransformer
|
129
|
+
```
|
130
|
+
|
131
|
+
#### BabelTransformer options
|
132
|
+
|
133
|
+
You can use babel's [transformers](http://babeljs.io/docs/advanced/transformers/) and [custom plugins](http://babeljs.io/docs/advanced/plugins/),
|
134
|
+
and pass [options](http://babeljs.io/docs/usage/options/) to the babel transpiler adding following configurations:
|
135
|
+
|
136
|
+
```ruby
|
137
|
+
config.react.jsx_transform_options = {
|
138
|
+
blacklist: ['spec.functionName', 'validation.react', 'strict'], # default options
|
139
|
+
optional: ["transformerName"], # pass extra babel options
|
140
|
+
whitelist: ["useStrict"] # even more options
|
141
|
+
}
|
142
|
+
```
|
143
|
+
Under the hood, `react-rails` uses [ruby-babel-transpiler](https://github.com/babel/ruby-babel-transpiler), for transformation.
|
144
|
+
|
145
|
+
#### JSXTransformer options
|
146
|
+
|
147
|
+
You can use JSX `--harmony` or `--strip-types` options by adding a configuration:
|
148
|
+
|
149
|
+
```ruby
|
150
|
+
config.react.jsx_transform_options = {
|
151
|
+
harmony: true,
|
152
|
+
strip_types: true, # for removing Flow type annotations
|
153
|
+
asset_path: "path/to/JSXTransformer.js", # if your JSXTransformer is somewhere else
|
154
|
+
}
|
155
|
+
```
|
156
|
+
|
157
|
+
### Rendering & mounting
|
158
|
+
|
159
|
+
`react-rails` includes a view helper (`react_component`) and an unobtrusive JavaScript driver (`react_ujs`)
|
160
|
+
which work together to put React components on the page. You should require the UJS driver
|
161
|
+
in your manifest after `react` (and after `turbolinks` if you use [Turbolinks](https://github.com/rails/turbolinks)).
|
162
|
+
|
163
|
+
The __view helper__ puts a `div` on the page with the requested component class & props. For example:
|
164
|
+
|
165
|
+
```erb
|
166
|
+
<%= react_component('HelloMessage', name: 'John') %>
|
167
|
+
<!-- becomes: -->
|
168
|
+
<div data-react-class="HelloMessage" data-react-props="{"name":"John"}"></div>
|
169
|
+
```
|
170
|
+
|
171
|
+
On page load, the __`react_ujs` driver__ will scan the page and mount components using `data-react-class`
|
172
|
+
and `data-react-props`.
|
173
|
+
|
174
|
+
If Turbolinks is present components are mounted on the `page:change` event, and unmounted on `page:before-unload`.
|
175
|
+
__Turbolinks >= 2.4.0__ is recommended because it exposes better events.
|
176
|
+
|
177
|
+
The view helper's signature is:
|
178
|
+
|
179
|
+
```ruby
|
180
|
+
react_component(component_class_name, props={}, html_options={})
|
181
|
+
```
|
182
|
+
|
183
|
+
- `component_class_name` is a string which names a globally-accessible component class. It may have dots (eg, `"MyApp.Header.MenuItem"`).
|
184
|
+
- `props` is either an object that responds to `#to_json` or an already-stringified JSON object (eg, made with Jbuilder, see note below).
|
185
|
+
- `html_options` may include:
|
186
|
+
- `tag:` to use an element other than a `div` to embed `data-react-class` and `-props`.
|
187
|
+
- `prerender: true` to render the component on the server.
|
188
|
+
- `**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).
|
189
|
+
|
190
|
+
|
191
|
+
### Server rendering
|
192
|
+
|
193
|
+
To render components on the server, pass `prerender: true` to `react_component`:
|
194
|
+
|
195
|
+
```erb
|
196
|
+
<%= react_component('HelloMessage', {name: 'John'}, {prerender: true}) %>
|
197
|
+
<!-- becomes: -->
|
198
|
+
<div data-react-class="HelloMessage" data-react-props="{"name":"John"}">
|
199
|
+
<h1>Hello, John!</h1>
|
200
|
+
</div>
|
201
|
+
```
|
202
|
+
|
203
|
+
_(It will be also be mounted by the UJS on page load.)_
|
204
|
+
|
205
|
+
There are some requirements for this to work:
|
206
|
+
|
207
|
+
- `react-rails` must load your code. By convention it uses `components.js`, which was created
|
208
|
+
by the install task. This file must include your components _and_ their dependencies (eg, Underscore.js).
|
209
|
+
- Your components must be accessible in the global scope.
|
210
|
+
If you are using `.js.jsx.coffee` files then the wrapper function needs to be taken into account:
|
211
|
+
|
212
|
+
```coffee
|
213
|
+
# @ is `window`:
|
214
|
+
@Component = React.createClass
|
215
|
+
render: ->
|
216
|
+
`<ExampleComponent videos={this.props.videos} />`
|
217
|
+
```
|
218
|
+
- Your code can't reference `document`. Prerender processes don't have access to `document`,
|
219
|
+
so jQuery and some other libs won't work in this environment :(
|
220
|
+
|
221
|
+
You can configure your pool of JS virtual machines and specify where it should load code:
|
222
|
+
|
223
|
+
```ruby
|
224
|
+
# config/environments/application.rb
|
225
|
+
# These are the defaults if you dont specify any yourself
|
226
|
+
MyApp::Application.configure do
|
227
|
+
# Settings for the pool of renderers:
|
228
|
+
config.react.server_renderer_pool_size ||= 1 # ExecJS doesn't allow more than one on MRI
|
229
|
+
config.react.server_renderer_timeout ||= 20 # seconds
|
230
|
+
config.react.server_renderer = React::ServerRendering::SprocketsRenderer
|
231
|
+
config.react.server_renderer_options = {
|
232
|
+
files: ["react-server.js", "components.js"], # files to load for prerendering
|
233
|
+
replay_console: true, # if true, console.* will be replayed client-side
|
234
|
+
}
|
235
|
+
end
|
236
|
+
```
|
237
|
+
|
238
|
+
- On MRI, use `therubyracer` for the best performance (see [discussion](https://github.com/reactjs/react-rails/pull/290))
|
239
|
+
- On MRI, you'll get a deadlock with `pool_size` > 1
|
240
|
+
- If you're using JRuby, you can increase `pool_size` to have real multi-threaded rendering.
|
241
|
+
|
242
|
+
You can configure camelize_props option and pass props with an underscored hash from rails but get a camelized hash in jsx :
|
243
|
+
|
244
|
+
```ruby
|
245
|
+
MyApp::Application.configure do
|
246
|
+
config.react.camelize_props = true #default false
|
247
|
+
end
|
248
|
+
```
|
249
|
+
|
250
|
+
### Rendering components instead of views
|
251
|
+
|
252
|
+
Components can also be prerendered directly from a controller action with the custom `component` renderer. For example:
|
253
|
+
|
254
|
+
```ruby
|
255
|
+
class TodoController < ApplicationController
|
256
|
+
def index
|
257
|
+
@todos = Todo.all
|
258
|
+
render component: 'TodoList', props: { todos: @todos }, tag: 'span', class: 'todo'
|
259
|
+
end
|
260
|
+
end
|
261
|
+
```
|
262
|
+
|
263
|
+
This custom renderer behaves the same as a normal view renderer and accepts the usual arguments - `content_type`, `layout`, `location` and `status`.
|
264
|
+
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
|
265
|
+
can be passed like `data: {remote: true}`.
|
266
|
+
|
267
|
+
### Component generator
|
268
|
+
|
269
|
+
`react-rails` ships with a Rails generator to help you get started with a simple component scaffold.
|
270
|
+
You can run it using `rails generate react:component ComponentName (--es6)`.
|
271
|
+
The generator takes an optional list of arguments for default propTypes,
|
272
|
+
which follow the conventions set in the [Reusable Components](http://facebook.github.io/react/docs/reusable-components.html)
|
273
|
+
section of the React documentation.
|
274
|
+
|
275
|
+
For example:
|
276
|
+
|
277
|
+
```shell
|
278
|
+
rails generate react:component Post title:string body:string published:bool published_by:instanceOf{Person}
|
279
|
+
```
|
280
|
+
|
281
|
+
would generate the following in `app/assets/javascripts/components/post.js.jsx`:
|
282
|
+
|
283
|
+
```jsx
|
284
|
+
var Post = React.createClass({
|
285
|
+
propTypes: {
|
286
|
+
title: React.PropTypes.string,
|
287
|
+
body: React.PropTypes.string,
|
288
|
+
published: React.PropTypes.bool,
|
289
|
+
publishedBy: React.PropTypes.instanceOf(Person)
|
290
|
+
},
|
291
|
+
|
292
|
+
render: function() {
|
293
|
+
return (
|
294
|
+
<div>
|
295
|
+
<div>Title: {this.props.title}</div>
|
296
|
+
<div>Body: {this.props.body}</div>
|
297
|
+
<div>Published: {this.props.published}</div>
|
298
|
+
<div>Published By: {this.props.publishedBy}</div>
|
299
|
+
</div>
|
300
|
+
);
|
301
|
+
}
|
302
|
+
});
|
303
|
+
```
|
304
|
+
|
305
|
+
#### Options
|
306
|
+
|
307
|
+
**--es6** : Generate the same component but using cutting edge es6 class
|
308
|
+
|
309
|
+
For example:
|
310
|
+
|
311
|
+
```shell
|
312
|
+
rails generate react:component Label label:string --es6
|
313
|
+
```
|
314
|
+
|
315
|
+
**--coffee** : Generate the component using CoffeeScript syntax
|
316
|
+
|
317
|
+
For example:
|
318
|
+
|
319
|
+
```shell
|
320
|
+
rails generate react:component Label label:string --coffee
|
321
|
+
```
|
322
|
+
|
323
|
+
#### Arguments
|
324
|
+
|
325
|
+
The generator can use the following arguments to create basic propTypes:
|
326
|
+
|
327
|
+
* any
|
328
|
+
* array
|
329
|
+
* bool
|
330
|
+
* element
|
331
|
+
* func
|
332
|
+
* number
|
333
|
+
* object
|
334
|
+
* node
|
335
|
+
* shape
|
336
|
+
* string
|
337
|
+
|
338
|
+
The following additional arguments have special behavior:
|
339
|
+
|
340
|
+
* `instanceOf` takes an optional class name in the form of {className}.
|
341
|
+
* `oneOf` behaves like an enum, and takes an optional list of strings in the form of `'name:oneOf{one,two,three}'`.
|
342
|
+
* `oneOfType` takes an optional list of react and custom types in the form of `'model:oneOfType{string,number,OtherType}'`.
|
343
|
+
|
344
|
+
Note that the arguments for `oneOf` and `oneOfType` must be enclosed in single quotes
|
345
|
+
to prevent your terminal from expanding them into an argument list.
|
346
|
+
|
347
|
+
### Jbuilder & react-rails
|
348
|
+
|
349
|
+
If you use Jbuilder to pass a JSON string to `react_component`, make sure your JSON is a stringified hash,
|
350
|
+
not an array. This is not the Rails default -- you should add the root node yourself. For example:
|
351
|
+
|
352
|
+
```ruby
|
353
|
+
# BAD: returns a stringified array
|
354
|
+
json.array!(@messages) do |message|
|
355
|
+
json.extract! message, :id, :name
|
356
|
+
json.url message_url(message, format: :json)
|
357
|
+
end
|
358
|
+
|
359
|
+
# GOOD: returns a stringified hash
|
360
|
+
json.messages(@messages) do |message|
|
361
|
+
json.extract! message, :id, :name
|
362
|
+
json.url message_url(message, format: :json)
|
363
|
+
end
|
364
|
+
```
|
365
|
+
|
366
|
+
## CoffeeScript
|
367
|
+
|
368
|
+
It is possible to use JSX with CoffeeScript. To use CoffeeScript, create files with an extension `.js.jsx.coffee`.
|
369
|
+
We also need to embed JSX code inside backticks so that CoffeeScript ignores the syntax it doesn't understand.
|
370
|
+
Here's an example:
|
371
|
+
|
372
|
+
```coffee
|
373
|
+
Component = React.createClass
|
374
|
+
render: ->
|
375
|
+
`<ExampleComponent videos={this.props.videos} />`
|
376
|
+
```
|
377
|
+
|
378
|
+
Alternatively, the newer ES6 style class based syntax can be used like this:
|
379
|
+
|
380
|
+
```coffee
|
381
|
+
class Component extends React.Component
|
382
|
+
render: ->
|
383
|
+
`<ExampleComponent videos={this.props.videos} />`
|
384
|
+
```
|
385
|
+
|
386
|
+
## Extending `react-rails`
|
387
|
+
|
388
|
+
You can extend some of the core functionality of `react-rails` by injecting new implementations during configuration.
|
389
|
+
|
390
|
+
### Custom Server Renderer
|
391
|
+
|
392
|
+
`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:
|
393
|
+
|
394
|
+
- `#initialize(options={})`, which accepts the hash from `config.react.server_renderer_options`
|
395
|
+
- `#render(component_name, props, prerender_options)` to return a string of HTML
|
396
|
+
|
397
|
+
`react-rails` provides two renderer classes: `React::ServerRendering::ExecJSRenderer` and `React::ServerRendering::SprocketsRenderer`.
|
398
|
+
|
399
|
+
`ExecJSRenderer` offers two other points for extension:
|
400
|
+
|
401
|
+
- `#before_render(component_name, props, prerender_options)` to return a string of JavaScript to execute _before_ calling `React.render`
|
402
|
+
- `#after_render(component_name, props, prerender_options)` to return a string of JavaScript to execute _after_ calling `React.render`
|
403
|
+
|
404
|
+
Any subclass of `ExecJSRenderer` may use those hooks (for example, `SprocketsRenderer` uses them to handle `console.*` on the server).
|
405
|
+
|
406
|
+
### Custom View Helper
|
407
|
+
|
408
|
+
`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:
|
409
|
+
|
410
|
+
- `#react_component(name, props = {}, options = {}, &block)` to return a string to inject into the Rails view
|
411
|
+
- `#setup(controller_instance)`, called when the helper is initialized at the start of the request
|
412
|
+
- `#teardown(controller_instance)`, called at the end of the request
|
413
|
+
|
414
|
+
`react-rails` provides one implementation, `React::Rails::ComponentMount`.
|
415
|
+
|
416
|
+
### Custom JSX Transformer
|
417
|
+
|
418
|
+
`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:
|
419
|
+
|
420
|
+
- `#initialize(options)`, where options is the value passed to `config.react.jsx_transform_options`
|
421
|
+
- `#transform(code_string)` to return a string of transformed code
|
422
|
+
|
423
|
+
`react-rails` provides two transformers, `React::JSX::JSXTransformer` and `React::JSX::BabelTransformer`.
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module React
|
2
|
+
module Rails
|
3
|
+
# This is the default view helper implementation.
|
4
|
+
# It just inserts HTML into the DOM (see {#react_component}).
|
5
|
+
#
|
6
|
+
# You can extend this class or provide your own implementation
|
7
|
+
# by assigning it to `config.react.view_helper_implementation`.
|
8
|
+
class ComponentMount
|
9
|
+
include ActionView::Helpers::TagHelper
|
10
|
+
include ActionView::Helpers::TextHelper
|
11
|
+
attr_accessor :output_buffer
|
12
|
+
mattr_accessor :camelize_props_switch
|
13
|
+
|
14
|
+
# ControllerLifecycle calls these hooks
|
15
|
+
# You can use them in custom helper implementations
|
16
|
+
def setup(env)
|
17
|
+
end
|
18
|
+
|
19
|
+
def teardown(env)
|
20
|
+
end
|
21
|
+
|
22
|
+
# Render a UJS-type HTML tag annotated with data attributes, which
|
23
|
+
# are used by react_ujs to actually instantiate the React component
|
24
|
+
# on the client.
|
25
|
+
def react_component(name, props = {}, options = {}, &block)
|
26
|
+
options = {:tag => options} if options.is_a?(Symbol)
|
27
|
+
props = camelize_props_key(props) if camelize_props_switch
|
28
|
+
|
29
|
+
html_options = options.reverse_merge(:data => {})
|
30
|
+
html_options[:data].tap do |data|
|
31
|
+
data[:react_class] = name
|
32
|
+
data[:react_props] = (props.is_a?(String) ? props : props.to_json)
|
33
|
+
end
|
34
|
+
html_tag = html_options[:tag] || :div
|
35
|
+
|
36
|
+
# remove internally used properties so they aren't rendered to DOM
|
37
|
+
html_options.except!(:tag)
|
38
|
+
|
39
|
+
content_tag(html_tag, '', html_options, &block)
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def camelize_props_key(props)
|
45
|
+
return props unless props.is_a?(Hash)
|
46
|
+
props.inject({}) do |h, (k,v)|
|
47
|
+
h[k.to_s.camelize(:lower)] = v.is_a?(Hash) ? camelize_props_key(v) : v; h
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module React
|
2
|
+
module Rails
|
3
|
+
module ViewHelper
|
4
|
+
# This class will be used for inserting tags into HTML.
|
5
|
+
# It should implement:
|
6
|
+
# - #setup(controller_instance)
|
7
|
+
# - #teardown(controller_instance)
|
8
|
+
# - #react_component(name, props, options &block)
|
9
|
+
# The default is {React::Rails::ComponentMount}
|
10
|
+
mattr_accessor :helper_implementation_class
|
11
|
+
|
12
|
+
# Render a React component into the view
|
13
|
+
# using the {helper_implementation_class}
|
14
|
+
#
|
15
|
+
# If called during a Rails controller-managed request, use the instance
|
16
|
+
# created by the controller.
|
17
|
+
#
|
18
|
+
# Otherwise, make a new instance.
|
19
|
+
def react_component(*args, &block)
|
20
|
+
helper_obj = @__react_component_helper ||= helper_implementation_class.new
|
21
|
+
helper_obj.react_component(*args, &block)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/react/rails.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'react/rails'
|
metadata
ADDED
@@ -0,0 +1,121 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: react-rails-stupid
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.5.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- a-x-
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-11-03 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: coffee-script-source
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.8'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.8'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: connection_pool
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: execjs
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rails
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '3.2'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '3.2'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: tilt
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
description: Compile your JSX on demand or precompile for production.
|
84
|
+
email:
|
85
|
+
- invntrm@gmail.com
|
86
|
+
executables: []
|
87
|
+
extensions: []
|
88
|
+
extra_rdoc_files: []
|
89
|
+
files:
|
90
|
+
- LICENSE
|
91
|
+
- README.md
|
92
|
+
- lib/react-rails-stupid.rb
|
93
|
+
- lib/react/rails.rb
|
94
|
+
- lib/react/rails/component_mount.rb
|
95
|
+
- lib/react/rails/version.rb
|
96
|
+
- lib/react/rails/view_helper.rb
|
97
|
+
homepage: https://github.com/reactjs/react-rails
|
98
|
+
licenses:
|
99
|
+
- Apache-2.0
|
100
|
+
metadata: {}
|
101
|
+
post_install_message:
|
102
|
+
rdoc_options: []
|
103
|
+
require_paths:
|
104
|
+
- lib
|
105
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - ">="
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
111
|
+
requirements:
|
112
|
+
- - ">="
|
113
|
+
- !ruby/object:Gem::Version
|
114
|
+
version: '0'
|
115
|
+
requirements: []
|
116
|
+
rubyforge_project:
|
117
|
+
rubygems_version: 2.7.7
|
118
|
+
signing_key:
|
119
|
+
specification_version: 4
|
120
|
+
summary: Stupid React/JSX adapter for the Ruby on Rails asset pipeline.
|
121
|
+
test_files: []
|