Skip to content

Commit 3b6d6bd

Browse files
committed
- Added new BabelTransformer to start performing transformation using ruby-babel-transpiler
- Make new BabelTransformer the default transformer - README changes to reflect new Babel Transformer - Added deprecation warning for usage of old transformer options - Move old transformer to JSXTransformer - Fixed component generator test after changes to new transformer Fixes #292, #278
1 parent 6019be9 commit 3b6d6bd

File tree

7 files changed

+100
-22
lines changed

7 files changed

+100
-22
lines changed

README.md

Lines changed: 61 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
# react-rails
1010

1111

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) in your Ruby on Rails (3.2+) application. `react-rails` can:
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:
1314

1415
- Provide [various `react` builds](#reactjs-builds) to your asset bundle
1516
- Transform [`.jsx` in the asset pipeline](#jsx)
@@ -32,7 +33,8 @@ rails g react:install
3233
```
3334

3435
This will:
35-
- create a `components.js` manifest file and a `app/assets/javascripts/components/` directory, where you will put your components
36+
- create a `components.js` manifest file and a `app/assets/javascripts/components/` directory,
37+
where you will put your components
3638
- place the following in your `application.js`:
3739

3840
```js
@@ -45,7 +47,8 @@ This will:
4547

4648
### React.js builds
4749

48-
You can pick which React.js build (development, production, with or without [add-ons]((http://facebook.github.io/react/docs/addons.html))) to serve in each environment by adding a config. Here are the defaults:
50+
You can pick which React.js build (development, production, with or without [add-ons]((http://facebook.github.io/react/docs/addons.html)))
51+
to serve in each environment by adding a config. Here are the defaults:
4952

5053
```ruby
5154
# config/environments/development.rb
@@ -67,14 +70,40 @@ MyApp::Application.configure do
6770
end
6871
```
6972

70-
After restarting your Rails server, `//= require react` will provide the build of React.js which was specified by the configurations.
73+
After restarting your Rails server, `//= require react` will provide the build of React.js which
74+
was specified by the configurations.
7175

72-
`react-rails` offers a few other options for versions & builds of React.js. See [VERSIONS.md](https://github.com/reactjs/react-rails/blob/master/VERSIONS.md) for more info about using the `react-source` gem or dropping in your own copies of React.js.
76+
`react-rails` offers a few other options for versions & builds of React.js.
77+
See [VERSIONS.md](https://github.com/reactjs/react-rails/blob/master/VERSIONS.md) for more info about
78+
using the `react-source` gem or dropping in your own copies of React.js.
7379

7480
### JSX
7581

7682
After installing `react-rails`, restart your server. Now, `.js.jsx` files will be transformed in the asset pipeline.
7783

84+
`react-rails` currently ships with two transformers, to convert jsx code -
85+
86+
* `BabelTransformer` using [Babel](http://babeljs.io), which is the default transformer.
87+
* `JSXTransformer` using `JSXTransformer.js`
88+
89+
#### BabelTransformer options
90+
91+
You can use babel's [transformers](http://babeljs.io/docs/advanced/transformers/) and [custom plugins](http://babeljs.io/docs/advanced/plugins/),
92+
and pass [options](http://babeljs.io/docs/usage/options/) to the babel transpiler adding following configurations:
93+
94+
```ruby
95+
config.react.jsx_transform_options = {
96+
blacklist: ['spec.functionName', 'validation.react'], // default options
97+
optional: ["transformerName"], // pass extra babel options
98+
whitelist: ["useStrict"] // even more options
99+
}
100+
```
101+
Under the hood, `react-rails` users [ruby-babel-transpiler](https://github.com/babel/ruby-babel-transpiler), for transformation.
102+
103+
#### JSXTransformer options
104+
105+
To use old JSXTransformer you can use `React::JSX.transformer_class = React::JSX::JSXTransformer`
106+
78107
You can use JSX `--harmony` or `--strip-types` options by adding a configuration:
79108

80109
```ruby
@@ -85,6 +114,8 @@ config.react.jsx_transform_options = {
85114
}
86115
```
87116

117+
#### CoffeeScript
118+
88119
To use CoffeeScript, create `.js.jsx.coffee` files and embed JSX inside backticks, for example:
89120

90121
```coffee
@@ -95,7 +126,9 @@ Component = React.createClass
95126

96127
### Rendering & mounting
97128

98-
`react-rails` includes a view helper (`react_component`) and an unobtrusive JavaScript driver (`react_ujs`) which work together to put React components on the page. You should require the UJS driver in your manifest after `react` (and after `turbolinks` if you use [Turbolinks](https://github.com/rails/turbolinks)).
129+
`react-rails` includes a view helper (`react_component`) and an unobtrusive JavaScript driver (`react_ujs`)
130+
which work together to put React components on the page. You should require the UJS driver
131+
in your manifest after `react` (and after `turbolinks` if you use [Turbolinks](https://github.com/rails/turbolinks)).
99132

100133
The __view helper__ puts a `div` on the page with the requested component class & props. For example:
101134

@@ -105,9 +138,12 @@ The __view helper__ puts a `div` on the page with the requested component class
105138
<div data-react-class="HelloMessage" data-react-props="{&quot;name&quot;:&quot;John&quot;}"></div>
106139
```
107140

108-
On page load, the __`react_ujs` driver__ will scan the page and mount components using `data-react-class` and `data-react-props`. Before page unload, it will unmount components (if you want to disable this behavior, remove `data-react-class` attribute in `componentDidMount`).
141+
On page load, the __`react_ujs` driver__ will scan the page and mount components using `data-react-class`
142+
and `data-react-props`. Before page unload, it will unmount components (if you want to disable this behavior,
143+
remove `data-react-class` attribute in `componentDidMount`).
109144

110-
`react_ujs` uses Turbolinks events if they're available, otherwise, it uses native events. __Turbolinks >= 2.4.0__ is recommended because it exposes better events.
145+
`react_ujs` uses Turbolinks events if they're available, otherwise, it uses native events.
146+
__Turbolinks >= 2.4.0__ is recommended because it exposes better events.
111147

112148
The view helper's signature is:
113149

@@ -141,16 +177,19 @@ _(It will be also be mounted by the UJS on page load.)_
141177

142178
There are some requirements for this to work:
143179

144-
- `react-rails` must load your code. By convention it uses `components.js`, which was created by the install task. This file must include your components _and_ their dependencies (eg, Underscore.js).
145-
- Your components must be accessible in the global scope. If you are using `.js.jsx.coffee` files then the wrapper function needs to be taken into account:
180+
- `react-rails` must load your code. By convention it uses `components.js`, which was created
181+
by the install task. This file must include your components _and_ their dependencies (eg, Underscore.js).
182+
- Your components must be accessible in the global scope.
183+
If you are using `.js.jsx.coffee` files then the wrapper function needs to be taken into account:
146184

147185
```coffee
148186
# @ is `window`:
149187
@Component = React.createClass
150188
render: ->
151189
`<ExampleComponent videos={this.props.videos} />`
152190
```
153-
- Your code can't reference `document`. Prerender processes don't have access to `document`, so jQuery and some other libs won't work in this environment :(
191+
- Your code can't reference `document`. Prerender processes don't have access to `document`,
192+
so jQuery and some other libs won't work in this environment :(
154193

155194
You can configure your pool of JS virtual machines and specify where it should load code:
156195

@@ -171,7 +210,11 @@ end
171210

172211
### Component generator
173212

174-
`react-rails` ships with a Rails generator to help you get started with a simple component scaffold. You can run it using `rails generate react:component ComponentName`. The generator takes an optional list of arguments for default propTypes, which follow the conventions set in the [Reusable Components](http://facebook.github.io/react/docs/reusable-components.html) section of the React documentation.
213+
`react-rails` ships with a Rails generator to help you get started with a simple component scaffold.
214+
You can run it using `rails generate react:component ComponentName`.
215+
The generator takes an optional list of arguments for default propTypes,
216+
which follow the conventions set in the [Reusable Components](http://facebook.github.io/react/docs/reusable-components.html)
217+
section of the React documentation.
175218

176219
For example:
177220

@@ -222,11 +265,13 @@ The following additional arguments have special behavior:
222265
* `oneOf` behaves like an enum, and takes an optional list of strings in the form of `'name:oneOf{one,two,three}'`.
223266
* `oneOfType` takes an optional list of react and custom types in the form of `'model:oneOfType{string,number,OtherType}'`.
224267

225-
Note that the arguments for `oneOf` and `oneOfType` must be enclosed in single quotes to prevent your terminal from expanding them into an argument list.
268+
Note that the arguments for `oneOf` and `oneOfType` must be enclosed in single quotes
269+
to prevent your terminal from expanding them into an argument list.
226270

227271
### Jbuilder & react-rails
228272

229-
If you use Jbuilder to pass a JSON string to `react_component`, make sure your JSON is a stringified hash, not an array. This is not the Rails default -- you should add the root node yourself. For example:
273+
If you use Jbuilder to pass a JSON string to `react_component`, make sure your JSON is a stringified hash,
274+
not an array. This is not the Rails default -- you should add the root node yourself. For example:
230275

231276
```ruby
232277
# BAD: returns a stringified array
@@ -244,7 +289,8 @@ end
244289

245290
## CoffeeScript
246291

247-
It is possible to use JSX with CoffeeScript. We need to embed JSX inside backticks so CoffeeScript ignores the syntax it doesn't understand. Here's an example:
292+
It is possible to use JSX with CoffeeScript. We need to embed JSX inside backticks
293+
so CoffeeScript ignores the syntax it doesn't understand. Here's an example:
248294

249295
```coffee
250296
Component = React.createClass

lib/react/jsx.rb

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
require 'execjs'
22
require 'react/jsx/template'
3-
require 'react/jsx/transformer'
3+
require 'react/jsx/jsx_transformer'
4+
require 'react/jsx/babel_transformer'
45
require 'rails'
56

67
module React
@@ -11,7 +12,7 @@ module JSX
1112
# to provide your own transformer. It must implement:
1213
# - #initialize(options)
1314
# - #transform(code) => new code
14-
self.transformer_class = Transformer
15+
self.transformer_class = BabelTransformer
1516

1617
def self.transform(code)
1718
transformer.transform(code)

lib/react/jsx/babel_transformer.rb

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
require 'babel/transpiler'
2+
module React
3+
module JSX
4+
class BabelTransformer
5+
DEPRECATED_OPTIONS = [:harmony, :strip_types, :asset_path]
6+
7+
def initialize(options)
8+
_options = options.dup
9+
has_old_opts = DEPRECATED_OPTIONS.map do |option|
10+
_options.delete option
11+
end.any?
12+
13+
if has_old_opts
14+
ActiveSupport::Deprecation.warn("Setting config.react.jsx_transform_options for :harmony, :strip_types, and :asset_path keys is now deprecated and has no effect with the default Babel Transformer."+
15+
"Please use new Babel Transformer options :whitelist, :plugin instead.")
16+
end
17+
18+
@transform_options = {
19+
blacklist: ['spec.functionName', 'validation.react']
20+
}.merge(_options)
21+
end
22+
23+
def transform(code)
24+
puts @transform_options
25+
Babel::Transpiler.transform(code)['code']
26+
end
27+
end
28+
end
29+
end

lib/react/jsx/transformer.rb renamed to lib/react/jsx/jsx_transformer.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
module React
22
module JSX
3-
class Transformer
3+
class JSXTransformer
44
DEFAULT_ASSET_PATH = 'JSXTransformer.js'
55

66
def initialize(options)
@@ -30,4 +30,4 @@ def jsx_transform_code
3030
end
3131
end
3232
end
33-
end
33+
end

react-rails.gemspec

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ Gem::Specification.new do |s|
3131
s.add_dependency 'execjs'
3232
s.add_dependency 'rails', '>= 3.2'
3333
s.add_dependency 'tilt'
34+
s.add_dependency 'babel-transpiler', '>=0.7.0'
3435

3536
s.files = Dir[
3637
'lib/**/*',

test/generators/component_generator_test.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,8 @@ def filename
4747
end
4848

4949
test "generates working jsx" do
50-
expected_name_div = Regexp.escape('React.createElement("div", null, "Name: ", this.props.name)')
51-
expected_shape_div = Regexp.escape('React.createElement("div", null, "Address: ", this.props.address)')
50+
expected_name_div = /React\.createElement\(\s*"div",\s*null,\s*\"Name:\s*\",\s*this\.props\.name\s*\)/x
51+
expected_shape_div = /React\.createElement\(\s*"div",\s*null,\s*\"Address:\s*\",\s*this\.props\.address\s*\)/x
5252

5353
run_generator %w(GeneratedComponent name:string address:shape)
5454
jsx = React::JSX.transform(File.read(File.join(destination_root, filename)))

test/react/jsx_test.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ class JSXTransformTest < ActionDispatch::IntegrationTest
3434

3535
teardown do
3636
clear_sprockets_cache
37-
React::JSX.transformer_class = React::JSX::Transformer
37+
React::JSX.transformer_class = React::JSX::JSXTransformer
3838
React::JSX.transform_options = {}
3939
end
4040

@@ -89,6 +89,7 @@ class JSXTransformTest < ActionDispatch::IntegrationTest
8989
replacing_path = custom_path.join("CustomTransformer.js")
9090

9191
React::JSX.transform_options = {asset_path: "custom/CustomTransformer.js"}
92+
React::JSX.transformer_class = React::JSX::JSXTransformer
9293

9394
FileUtils.mkdir_p(custom_path)
9495
FileUtils.cp(hidden_path, replacing_path)

0 commit comments

Comments
 (0)