react-rails 1.2.0 → 1.3.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 15df12f33d7eebb048c97c8cd0bb64e95ccce6aa
4
- data.tar.gz: ed212e1fdfa9fd6aa5f401cf931e9d0d72a22d24
3
+ metadata.gz: fcffb8326ddf9468f84991dc075b824339192aa6
4
+ data.tar.gz: 732958fbaa2b917816cc4febcd340e4d439ac397
5
5
  SHA512:
6
- metadata.gz: 426958555a561b2b3bd2ea3954919123b5f7cbc764892c426b3d461b43650384fc5f1d570a65eb8eec156aac9108f1917b98987cbeff71ce50ecce270220d10b
7
- data.tar.gz: c2c7cd00745aa11c70c04295d6aeb8461777a1279dacafcc48df1ea2b4bffba025de5130953ba1c829f7c3e8350b26c79297f042d3cab42cf330b51eb3b01706
6
+ metadata.gz: 03572f213be4ef8de3be2a513fe56b8fe825f456e704271a785e2f8f9afbe8c0f12670809e441b0da1d1968bce0676db5d993333879dd9b6b126c4f32cf67680
7
+ data.tar.gz: 33c018c9e2dc905b5c3e505f75882344345e00ecfd8fb9a6aa4a8ee85468bd74a30fa44ca1b6a75105df06ae98c28c050f3b5c82d15d5aacd34a14b4c9c62640
data/README.md CHANGED
@@ -9,7 +9,7 @@
9
9
  # react-rails
10
10
 
11
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)
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
13
  in your Ruby on Rails (3.2+) application. `react-rails` can:
14
14
 
15
15
  - Provide [various `react` builds](#reactjs-builds) to your asset bundle
@@ -17,13 +17,14 @@ in your Ruby on Rails (3.2+) application. `react-rails` can:
17
17
  - [Render components into views and mount them](#rendering--mounting) via view helper & `react_ujs`
18
18
  - [Render components server-side](#server-rendering) with `prerender: true`
19
19
  - [Generate components](#component-generator) with a Rails generator
20
+ - [Be extended](#extending-react-rails) with custom renderers, transformers and view helpers
20
21
 
21
22
  ## Installation
22
23
 
23
24
  Add `react-rails` to your gemfile:
24
25
 
25
26
  ```ruby
26
- gem 'react-rails', '~> 1.0'
27
+ gem 'react-rails', '~> 1.3.0'
27
28
  ```
28
29
 
29
30
  Next, run the installation script:
@@ -82,27 +83,31 @@ See [VERSIONS.md](https://github.com/reactjs/react-rails/blob/master/VERSIONS.md
82
83
  After installing `react-rails`, restart your server. Now, `.js.jsx` files will be transformed in the asset pipeline.
83
84
 
84
85
  `react-rails` currently ships with two transformers, to convert jsx code -
85
-
86
+
86
87
  * `BabelTransformer` using [Babel](http://babeljs.io), which is the default transformer.
87
88
  * `JSXTransformer` using `JSXTransformer.js`
88
89
 
90
+ You can use the deprecated `JSXTransformer` by setting it in an application config:
91
+
92
+ ```ruby
93
+ config.react.jsx_transformer_class = React::JSX::JSXTransformer
94
+ ```
95
+
89
96
  #### BabelTransformer options
90
97
 
91
- You can use babel's [transformers](http://babeljs.io/docs/advanced/transformers/) and [custom plugins](http://babeljs.io/docs/advanced/plugins/),
98
+ You can use babel's [transformers](http://babeljs.io/docs/advanced/transformers/) and [custom plugins](http://babeljs.io/docs/advanced/plugins/),
92
99
  and pass [options](http://babeljs.io/docs/usage/options/) to the babel transpiler adding following configurations:
93
100
 
94
101
  ```ruby
95
102
  config.react.jsx_transform_options = {
96
103
  blacklist: ['spec.functionName', 'validation.react'], # default options
97
104
  optional: ["transformerName"], # pass extra babel options
98
- whitelist: ["useStrict"] # even more options
105
+ whitelist: ["useStrict"] # even more options
99
106
  }
100
107
  ```
101
108
  Under the hood, `react-rails` uses [ruby-babel-transpiler](https://github.com/babel/ruby-babel-transpiler), for transformation.
102
-
103
- #### JSXTransformer options
104
109
 
105
- To use old JSXTransformer you can use `React::JSX.transformer_class = React::JSX::JSXTransformer`
110
+ #### JSXTransformer options
106
111
 
107
112
  You can use JSX `--harmony` or `--strip-types` options by adding a configuration:
108
113
 
@@ -199,6 +204,22 @@ end
199
204
  - On MRI, you'll get a deadlock with `pool_size` > 1
200
205
  - If you're using JRuby, you can increase `pool_size` to have real multi-threaded rendering.
201
206
 
207
+ ### Rendering components instead of views
208
+
209
+ Components can also be prerendered directly from a controller action with the custom `component` renderer. For example:
210
+
211
+ ```ruby
212
+ class TodoController < ApplicationController
213
+ def index
214
+ @todos = Todo.all
215
+ render component: 'TodoList', props: { todos: @todos }, tag: 'span'
216
+ end
217
+ end
218
+ ```
219
+
220
+ This custom renderer behaves the same as a normal view renderer and accepts the usual arguments - `content_type`, `layout`, `location` and `status`.
221
+ By default, your current layout will be used and the component, rather than a view, will be rendered in place of `yield`.
222
+
202
223
  ### Component generator
203
224
 
204
225
  `react-rails` ships with a Rails generator to help you get started with a simple component scaffold.
@@ -230,7 +251,7 @@ var Post = React.createClass({
230
251
  <div>Title: {this.props.title}</div>
231
252
  <div>Body: {this.props.body}</div>
232
253
  <div>Published: {this.props.published}</div>
233
- <div>Published By: {this.props.published_by}</div>
254
+ <div>Published By: {this.props.publishedBy}</div>
234
255
  </div>
235
256
  );
236
257
  }
@@ -301,3 +322,42 @@ Component = React.createClass
301
322
  render: ->
302
323
  `<ExampleComponent videos={this.props.videos} />`
303
324
  ```
325
+
326
+ ## Extending `react-rails`
327
+
328
+ You can extend some of the core functionality of `react-rails` by injecting new implementations during configuration.
329
+
330
+ ### Custom Server Renderer
331
+
332
+ `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:
333
+
334
+ - `#initialize(options={})`, which accepts the hash from `config.react.server_renderer_options`
335
+ - `#render(component_name, props, prerender_options)` to return a string of HTML
336
+
337
+ `react-rails` provides two renderer classes: `React::ServerRendering::ExecJSRenderer` and `React::ServerRendering::SprocketsRenderer`.
338
+
339
+ `ExecJSRenderer` offers two other points for extension:
340
+
341
+ - `#before_render(component_name, props, prerender_options)` to return a string of JavaScript to execute _before_ calling `React.render`
342
+ - `#after_render(component_name, props, prerender_options)` to return a string of JavaScript to execute _after_ calling `React.render`
343
+
344
+ Any subclass of `ExecJSRenderer` may use those hooks (for example, `SprocketsRenderer` uses them to handle `console.*` on the server).
345
+
346
+ ### Custom View Helper
347
+
348
+ `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:
349
+
350
+ - `#react_component(name, props = {}, options = {}, &block)` to return a string to inject into the Rails view
351
+ - `#setup(rack_env)`, called when the helper is initialized at the start of the request
352
+ - `#teardown(rack_env)`, called at the end of the request
353
+
354
+ `react-rails` provides one implementation, `React::Rails::ComponentMount`.
355
+
356
+ ### Custom JSX Transformer
357
+
358
+ `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:
359
+
360
+ - `#initialize(options)`, where options is the value passed to `config.react.jsx_transform_options`
361
+ - `#transform(code_string)` to return a string of transformed code
362
+
363
+ `react-rails` provides two transformers, `React::JSX::JSXTransformer` and `React::JSX::BabelTransformer`.
@@ -9,7 +9,7 @@ module React
9
9
  DEFAULT_TRANSFORMER = BabelTransformer
10
10
  mattr_accessor :transform_options, :transformer_class, :transformer
11
11
 
12
- # You can assign `React::JSX.transformer_class = `
12
+ # You can assign `config.react.jsx_transformer_class = `
13
13
  # to provide your own transformer. It must implement:
14
14
  # - #initialize(options)
15
15
  # - #transform(code) => new code
@@ -1,5 +1,8 @@
1
1
  require 'react/rails/asset_variant'
2
2
  require 'react/rails/engine'
3
3
  require 'react/rails/railtie'
4
+ require 'react/rails/render_middleware'
4
5
  require 'react/rails/version'
6
+ require 'react/rails/component_mount'
5
7
  require 'react/rails/view_helper'
8
+ require 'react/rails/controller_renderer'
@@ -0,0 +1,46 @@
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
+
13
+ # RenderMiddleware calls these hooks
14
+ # You can use them in custom helper implementations
15
+ def setup(env)
16
+ end
17
+
18
+ def teardown(env)
19
+ end
20
+
21
+ # Render a UJS-type HTML tag annotated with data attributes, which
22
+ # are used by react_ujs to actually instantiate the React component
23
+ # on the client.
24
+ def react_component(name, props = {}, options = {}, &block)
25
+ options = {:tag => options} if options.is_a?(Symbol)
26
+
27
+ prerender_options = options[:prerender]
28
+ if prerender_options
29
+ block = Proc.new{ concat React::ServerRendering.render(name, props, prerender_options) }
30
+ end
31
+
32
+ html_options = options.reverse_merge(:data => {})
33
+ html_options[:data].tap do |data|
34
+ data[:react_class] = name
35
+ data[:react_props] = (props.is_a?(String) ? props : props.to_json)
36
+ end
37
+ html_tag = html_options[:tag] || :div
38
+
39
+ # remove internally used properties so they aren't rendered to DOM
40
+ html_options.except!(:tag, :prerender)
41
+
42
+ content_tag(html_tag, '', html_options, &block)
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,18 @@
1
+ class React::Rails::ControllerRenderer
2
+ include React::Rails::ViewHelper
3
+ include ActionView::Helpers::TagHelper
4
+ include ActionView::Helpers::TextHelper
5
+
6
+ attr_accessor :output_buffer
7
+
8
+ attr_reader :request
9
+ def initialize(options={})
10
+ @request = options[:request]
11
+ end
12
+
13
+ def call(name, options, &block)
14
+ props = options.fetch(:props, {})
15
+ options = options.slice(:data, :tag).merge(prerender: true)
16
+ react_component(name, props, options, &block)
17
+ end
18
+ end
@@ -4,7 +4,6 @@ module React
4
4
  module Rails
5
5
  class Railtie < ::Rails::Railtie
6
6
  config.react = ActiveSupport::OrderedOptions.new
7
-
8
7
  # Sensible defaults. Can be overridden in application.rb
9
8
  config.react.variant = (::Rails.env.production? ? :production : :development)
10
9
  config.react.addons = false
@@ -15,6 +14,8 @@ module React
15
14
  config.react.server_renderer_timeout = 20 # seconds
16
15
  config.react.server_renderer = nil # defaults to SprocketsRenderer
17
16
  config.react.server_renderer_options = {} # SprocketsRenderer provides defaults
17
+ # View helper implementation:
18
+ config.react.view_helper_implementation = nil # Defaults to ComponentMount
18
19
 
19
20
  # Watch .jsx files for changes in dev, so we can reload the JS VMs with the new JS code.
20
21
  initializer "react_rails.add_watchable_files", group: :all do |app|
@@ -23,15 +24,27 @@ module React
23
24
 
24
25
  # Include the react-rails view helper lazily
25
26
  initializer "react_rails.setup_view_helpers", group: :all do |app|
27
+ app.config.middleware.use(::React::Rails::RenderMiddleware)
26
28
  app.config.react.jsx_transformer_class ||= React::JSX::DEFAULT_TRANSFORMER
27
29
  React::JSX.transformer_class = app.config.react.jsx_transformer_class
28
30
  React::JSX.transform_options = app.config.react.jsx_transform_options
29
31
 
32
+ app.config.react.view_helper_implementation ||= React::Rails::ComponentMount
33
+ React::Rails::ViewHelper.helper_implementation_class = app.config.react.view_helper_implementation
30
34
  ActiveSupport.on_load(:action_view) do
31
35
  include ::React::Rails::ViewHelper
32
36
  end
33
37
  end
34
38
 
39
+ initializer "react_rails.add_component_renderer", group: :all do |app|
40
+ ActionController::Renderers.add :component do |component_name, options|
41
+ renderer = ::React::Rails::ControllerRenderer.new(request: request)
42
+ html = renderer.call(component_name, options)
43
+ render_options = options.merge(inline: html)
44
+ render(render_options)
45
+ end
46
+ end
47
+
35
48
  initializer "react_rails.bust_cache", group: :all do |app|
36
49
  asset_variant = React::Rails::AssetVariant.new({
37
50
  variant: app.config.react.variant,
@@ -43,7 +56,7 @@ module React
43
56
 
44
57
  end
45
58
 
46
- config.before_initialize do |app|
59
+ initializer "react_rails.set_variant", after: :engines_blank_point, group: :all do |app|
47
60
  asset_variant = React::Rails::AssetVariant.new({
48
61
  variant: app.config.react.variant,
49
62
  addons: app.config.react.addons,
@@ -0,0 +1,19 @@
1
+ module React
2
+ module Rails
3
+ class RenderMiddleware
4
+ HELPER_IMPLEMENTATION_KEY = "react_rails.view_helper_implementation"
5
+ def initialize(app)
6
+ @app = app
7
+ end
8
+
9
+ def call(env)
10
+ new_helper = React::Rails::ViewHelper.helper_implementation_class.new
11
+ new_helper.setup(env)
12
+ env[HELPER_IMPLEMENTATION_KEY] = new_helper
13
+ response = @app.call(env)
14
+ new_helper.teardown(env)
15
+ response
16
+ end
17
+ end
18
+ end
19
+ end
@@ -1,6 +1,6 @@
1
1
  module React
2
2
  module Rails
3
3
  # If you change this, make sure to update VERSIONS.md
4
- VERSION = '1.2.0'
4
+ VERSION = '1.3.0'
5
5
  end
6
6
  end
@@ -1,28 +1,18 @@
1
1
  module React
2
2
  module Rails
3
3
  module ViewHelper
4
- # Render a UJS-type HTML tag annotated with data attributes, which
5
- # are used by react_ujs to actually instantiate the React component
6
- # on the client.
7
- def react_component(name, props = {}, options = {}, &block)
8
- options = {:tag => options} if options.is_a?(Symbol)
4
+ # This class will be used for inserting tags into HTML.
5
+ # It should implement:
6
+ # - #setup(env)
7
+ # - #teardown(env)
8
+ # - #react_component(name, props, options &block)
9
+ # The default is {React::Rails::ComponentMount}
10
+ mattr_accessor :helper_implementation_class
9
11
 
10
- prerender_options = options[:prerender]
11
- if prerender_options
12
- block = Proc.new{ concat React::ServerRendering.render(name, props, prerender_options) }
13
- end
14
-
15
- html_options = options.reverse_merge(:data => {})
16
- html_options[:data].tap do |data|
17
- data[:react_class] = name
18
- data[:react_props] = (props.is_a?(String) ? props : props.to_json)
19
- end
20
- html_tag = html_options[:tag] || :div
21
-
22
- # remove internally used properties so they aren't rendered to DOM
23
- html_options.except!(:tag, :prerender)
24
-
25
- content_tag(html_tag, '', html_options, &block)
12
+ def react_component(*args, &block)
13
+ impl_key = React::Rails::RenderMiddleware::HELPER_IMPLEMENTATION_KEY
14
+ helper_obj = request.env[impl_key]
15
+ helper_obj.react_component(*args, &block)
26
16
  end
27
17
  end
28
18
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: react-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Paul O’Shannessy
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-08-19 00:00:00.000000000 Z
11
+ date: 2015-09-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: appraisal
@@ -270,8 +270,11 @@ files:
270
270
  - lib/react/jsx/template.rb
271
271
  - lib/react/jsx.rb
272
272
  - lib/react/rails/asset_variant.rb
273
+ - lib/react/rails/component_mount.rb
274
+ - lib/react/rails/controller_renderer.rb
273
275
  - lib/react/rails/engine.rb
274
276
  - lib/react/rails/railtie.rb
277
+ - lib/react/rails/render_middleware.rb
275
278
  - lib/react/rails/version.rb
276
279
  - lib/react/rails/view_helper.rb
277
280
  - lib/react/rails.rb