Skip to content

Commit 3fe755e

Browse files
author
Robert Mosolgo
authored
Merge pull request #591 from reactjs/directive-processor
Require .js and .coffee from .jsx
2 parents e43aabb + 43eb2e3 commit 3fe755e

File tree

10 files changed

+87
-29
lines changed

10 files changed

+87
-29
lines changed

lib/react/jsx.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
require 'react/jsx/template'
44
require 'react/jsx/jsx_transformer'
55
require 'react/jsx/babel_transformer'
6+
require 'react/jsx/sprockets_strategy'
67
require 'rails'
78

89
module React
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
module React
2+
module JSX
3+
# Depending on the Sprockets version,
4+
# attach JSX transformation the the Sprockets environment.
5+
#
6+
# You can override it with `config.sprockets_strategy`
7+
# @example Specifying a Sprockets strategy
8+
# app.config.react.sprockets_strategy = :register_engine
9+
#
10+
# @example Opting out of any Sprockets strategy
11+
# app.config.react.sprockets_strategy = false
12+
#
13+
module SprocketsStrategy
14+
module_function
15+
16+
# @param [Sprockets::Environment] the environment to attach JSX to
17+
# @param [Symbol, Nil] A strategy name, or `nil` to detect a strategy
18+
def attach_with_strategy(sprockets_env, strategy_or_nil)
19+
strategy = strategy_or_nil || detect_strategy
20+
self.public_send(strategy, sprockets_env)
21+
end
22+
23+
# @return [Symbol] based on the environment, return a method name to call with the sprockets environment
24+
def detect_strategy
25+
sprockets_version = Gem::Version.new(Sprockets::VERSION)
26+
if sprockets_version >= Gem::Version.new("4.x")
27+
:register_processors
28+
elsif sprockets_version >= Gem::Version.new("3.0.0")
29+
:register_engine_with_mime_type
30+
else
31+
:register_engine
32+
end
33+
end
34+
35+
def register_engine(sprockets_env)
36+
sprockets_env.register_engine(".jsx", React::JSX::Template)
37+
end
38+
39+
def register_engine_with_mime_type(sprockets_env)
40+
sprockets_env.register_engine(".jsx", React::JSX::Processor, mime_type: "application/javascript", silence_deprecation: true)
41+
end
42+
43+
def register_processors(sprockets_env)
44+
sprockets_env.register_mime_type("application/jsx", extensions: [".jsx", ".js.jsx", ".es.jsx", ".es6.jsx"])
45+
sprockets_env.register_mime_type("application/jsx+coffee", extensions: [".jsx.coffee", ".js.jsx.coffee"])
46+
sprockets_env.register_transformer("application/jsx", "application/javascript", React::JSX::Processor)
47+
sprockets_env.register_transformer("application/jsx+coffee", "application/jsx", Sprockets::CoffeeScriptProcessor)
48+
sprockets_env.register_preprocessor("application/jsx", Sprockets::DirectiveProcessor.new(comments: ["//", ["/*", "*/"]]))
49+
sprockets_env.register_preprocessor("application/jsx+coffee", Sprockets::DirectiveProcessor.new(comments: ["#", ["###", "###"]]))
50+
end
51+
end
52+
end
53+
end

lib/react/rails/railtie.rb

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ class Railtie < ::Rails::Railtie
1010
config.react.jsx_transform_options = {}
1111
config.react.jsx_transformer_class = nil # defaults to BabelTransformer
1212
config.react.camelize_props = false # pass in an underscored hash but get a camelized hash
13+
config.react.sprockets_strategy = nil # how to attach JSX to the asset pipeline (or `false` for none)
1314

1415
# Server rendering:
1516
config.react.server_renderer_pool_size = 1 # increase if you're on JRuby
@@ -100,19 +101,12 @@ class Railtie < ::Rails::Railtie
100101
# Sprockets 3.x expects this in a different place
101102
sprockets_env = app.assets || defined?(Sprockets) && Sprockets
102103

103-
if !sprockets_env.nil?
104-
if Gem::Version.new(Sprockets::VERSION) >= Gem::Version.new("3.7.0")
105-
sprockets_env.register_mime_type("application/jsx", extensions: [".jsx", ".js.jsx", ".es.jsx", ".es6.jsx"])
106-
sprockets_env.register_mime_type("application/jsx+coffee", extensions: [".jsx.coffee", ".js.jsx.coffee"])
107-
sprockets_env.register_transformer("application/jsx", "application/javascript", React::JSX::Processor)
108-
sprockets_env.register_transformer("application/jsx+coffee", "application/jsx", Sprockets::CoffeeScriptProcessor)
109-
sprockets_env.register_preprocessor("application/jsx", Sprockets::DirectiveProcessor.new(comments: ["//", ["/*", "*/"]]))
110-
sprockets_env.register_preprocessor("application/jsx+coffee", Sprockets::DirectiveProcessor.new(comments: ["#", ["###", "###"]]))
111-
elsif Gem::Version.new(Sprockets::VERSION) >= Gem::Version.new("3.0.0")
112-
sprockets_env.register_engine(".jsx", React::JSX::Processor, mime_type: "application/javascript")
113-
else
114-
sprockets_env.register_engine(".jsx", React::JSX::Template)
115-
end
104+
if app.config.react.sprockets_strategy == false
105+
# pass, Sprockets opt-out
106+
elsif sprockets_env.present?
107+
React::JSX::SprocketsStrategy.attach_with_strategy(sprockets_env, app.config.react.sprockets_strategy)
108+
else
109+
# pass, Sprockets is not preset
116110
end
117111
end
118112
end

test/dummy/app/assets/javascripts/require_test/jsx_preprocessor_test.jsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
//= require ./jsx_require_child_jsx
12
//= require ./jsx_require_child_js
3+
//= require ./jsx_require_child_coffee
24
<div className="le-javascript" />
3-
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
requireCoffee = true
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
var requirePlainJavascript = true;

test/dummy/app/assets/javascripts/require_test/jsx_require_child_js.jsx

Lines changed: 0 additions & 1 deletion
This file was deleted.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<div className="require-jsx" />
Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
11
require 'test_helper'
22

33
when_sprockets_available do
4-
class JSXPreprocessorTest < ActionDispatch::IntegrationTest
5-
EXPECTED_JS = <<javascript
6-
React.createElement(\"div\", { className: \"le-javascript-child\" });
7-
React.createElement(\"div\", { className: \"le-javascript\" });
8-
javascript
9-
4+
class JSXPreprocessorTest < ActiveSupport::TestCase
5+
REQUIRED_JAVASCRIPT = "var requirePlainJavascript = true;"
6+
REQUIRED_COFFEESCRIPT = "var requireCoffee; requireCoffee = true;"
7+
REQUIRED_JSX = "React.createElement(\"div\", { className: \"require-jsx\" });"
8+
OWN_JSX = "React.createElement(\"div\", { className: \"le-javascript\" });"
109
test 'executes //= require directives' do
11-
get '/assets/require_test/jsx_preprocessor_test.js'
12-
assert_response :success
13-
assert_compiled_javascript_matches(@response.body, EXPECTED_JS)
10+
require_parent = fetch_asset_body("require_test/jsx_preprocessor_test.js")
11+
12+
assert_compiled_javascript_includes(require_parent, REQUIRED_JAVASCRIPT)
13+
assert_compiled_javascript_includes(require_parent, REQUIRED_COFFEESCRIPT)
14+
assert_compiled_javascript_includes(require_parent, REQUIRED_JSX)
15+
assert_compiled_javascript_includes(require_parent, OWN_JSX)
1416
end
1517
end
1618
end

test/test_helper.rb

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -114,13 +114,18 @@ def when_sprockets_available
114114
end
115115
end
116116

117-
class ActionDispatch::IntegrationTest
117+
def fetch_asset_body(asset_logical_path)
118+
Rails.application.assets[asset_logical_path].to_s
119+
end
118120

119121
# Different processors may generate slightly different outputs,
120122
# as some version inserts an extra "\n" at the beginning.
121123
# Because appraisal is used, multiple versions of coffee-script are treated
122124
# together. Remove all spaces to make test pass.
123-
def assert_compiled_javascript_matches(javascript, expectation)
124-
assert_equal expectation.gsub(/\s/, ''), javascript.gsub(/\s/, '')
125-
end
126-
end
125+
def assert_compiled_javascript_matches(javascript, expectation)
126+
assert_equal expectation.gsub(/\s/, ''), javascript.gsub(/\s/, '')
127+
end
128+
129+
def assert_compiled_javascript_includes(javascript, expected_part)
130+
assert_includes javascript.gsub(/\s/, ''), expected_part.gsub(/\s/, '')
131+
end

0 commit comments

Comments
 (0)