diff --git a/lib/react/jsx.rb b/lib/react/jsx.rb index 79b2e3494..135e6cba1 100644 --- a/lib/react/jsx.rb +++ b/lib/react/jsx.rb @@ -3,6 +3,7 @@ require 'react/jsx/template' require 'react/jsx/jsx_transformer' require 'react/jsx/babel_transformer' +require 'react/jsx/sprockets_strategy' require 'rails' module React diff --git a/lib/react/jsx/sprockets_strategy.rb b/lib/react/jsx/sprockets_strategy.rb new file mode 100644 index 000000000..c98c47eef --- /dev/null +++ b/lib/react/jsx/sprockets_strategy.rb @@ -0,0 +1,53 @@ +module React + module JSX + # Depending on the Sprockets version, + # attach JSX transformation the the Sprockets environment. + # + # You can override it with `config.sprockets_strategy` + # @example Specifying a Sprockets strategy + # app.config.react.sprockets_strategy = :register_engine + # + # @example Opting out of any Sprockets strategy + # app.config.react.sprockets_strategy = false + # + module SprocketsStrategy + module_function + + # @param [Sprockets::Environment] the environment to attach JSX to + # @param [Symbol, Nil] A strategy name, or `nil` to detect a strategy + def attach_with_strategy(sprockets_env, strategy_or_nil) + strategy = strategy_or_nil || detect_strategy + self.public_send(strategy, sprockets_env) + end + + # @return [Symbol] based on the environment, return a method name to call with the sprockets environment + def detect_strategy + sprockets_version = Gem::Version.new(Sprockets::VERSION) + if sprockets_version >= Gem::Version.new("4.x") + :register_processors + elsif sprockets_version >= Gem::Version.new("3.0.0") + :register_engine_with_mime_type + else + :register_engine + end + end + + def register_engine(sprockets_env) + sprockets_env.register_engine(".jsx", React::JSX::Template) + end + + def register_engine_with_mime_type(sprockets_env) + sprockets_env.register_engine(".jsx", React::JSX::Processor, mime_type: "application/javascript", silence_deprecation: true) + end + + def register_processors(sprockets_env) + sprockets_env.register_mime_type("application/jsx", extensions: [".jsx", ".js.jsx", ".es.jsx", ".es6.jsx"]) + sprockets_env.register_mime_type("application/jsx+coffee", extensions: [".jsx.coffee", ".js.jsx.coffee"]) + sprockets_env.register_transformer("application/jsx", "application/javascript", React::JSX::Processor) + sprockets_env.register_transformer("application/jsx+coffee", "application/jsx", Sprockets::CoffeeScriptProcessor) + sprockets_env.register_preprocessor("application/jsx", Sprockets::DirectiveProcessor.new(comments: ["//", ["/*", "*/"]])) + sprockets_env.register_preprocessor("application/jsx+coffee", Sprockets::DirectiveProcessor.new(comments: ["#", ["###", "###"]])) + end + end + end +end diff --git a/lib/react/rails/railtie.rb b/lib/react/rails/railtie.rb index 91def52db..817c3aa7a 100644 --- a/lib/react/rails/railtie.rb +++ b/lib/react/rails/railtie.rb @@ -10,6 +10,7 @@ class Railtie < ::Rails::Railtie config.react.jsx_transform_options = {} config.react.jsx_transformer_class = nil # defaults to BabelTransformer config.react.camelize_props = false # pass in an underscored hash but get a camelized hash + config.react.sprockets_strategy = nil # how to attach JSX to the asset pipeline (or `false` for none) # Server rendering: config.react.server_renderer_pool_size = 1 # increase if you're on JRuby @@ -100,19 +101,12 @@ class Railtie < ::Rails::Railtie # Sprockets 3.x expects this in a different place sprockets_env = app.assets || defined?(Sprockets) && Sprockets - if !sprockets_env.nil? - if Gem::Version.new(Sprockets::VERSION) >= Gem::Version.new("3.7.0") - sprockets_env.register_mime_type("application/jsx", extensions: [".jsx", ".js.jsx", ".es.jsx", ".es6.jsx"]) - sprockets_env.register_mime_type("application/jsx+coffee", extensions: [".jsx.coffee", ".js.jsx.coffee"]) - sprockets_env.register_transformer("application/jsx", "application/javascript", React::JSX::Processor) - sprockets_env.register_transformer("application/jsx+coffee", "application/jsx", Sprockets::CoffeeScriptProcessor) - sprockets_env.register_preprocessor("application/jsx", Sprockets::DirectiveProcessor.new(comments: ["//", ["/*", "*/"]])) - sprockets_env.register_preprocessor("application/jsx+coffee", Sprockets::DirectiveProcessor.new(comments: ["#", ["###", "###"]])) - elsif Gem::Version.new(Sprockets::VERSION) >= Gem::Version.new("3.0.0") - sprockets_env.register_engine(".jsx", React::JSX::Processor, mime_type: "application/javascript") - else - sprockets_env.register_engine(".jsx", React::JSX::Template) - end + if app.config.react.sprockets_strategy == false + # pass, Sprockets opt-out + elsif sprockets_env.present? + React::JSX::SprocketsStrategy.attach_with_strategy(sprockets_env, app.config.react.sprockets_strategy) + else + # pass, Sprockets is not preset end end end diff --git a/test/dummy/app/assets/javascripts/require_test/jsx_preprocessor_test.jsx b/test/dummy/app/assets/javascripts/require_test/jsx_preprocessor_test.jsx index 562cc50f6..781cfd119 100644 --- a/test/dummy/app/assets/javascripts/require_test/jsx_preprocessor_test.jsx +++ b/test/dummy/app/assets/javascripts/require_test/jsx_preprocessor_test.jsx @@ -1,3 +1,4 @@ +//= require ./jsx_require_child_jsx //= require ./jsx_require_child_js +//= require ./jsx_require_child_coffee
- diff --git a/test/dummy/app/assets/javascripts/require_test/jsx_require_child_coffee.coffee b/test/dummy/app/assets/javascripts/require_test/jsx_require_child_coffee.coffee new file mode 100644 index 000000000..64ecfc52a --- /dev/null +++ b/test/dummy/app/assets/javascripts/require_test/jsx_require_child_coffee.coffee @@ -0,0 +1 @@ +requireCoffee = true diff --git a/test/dummy/app/assets/javascripts/require_test/jsx_require_child_js.js b/test/dummy/app/assets/javascripts/require_test/jsx_require_child_js.js new file mode 100644 index 000000000..49091c3ab --- /dev/null +++ b/test/dummy/app/assets/javascripts/require_test/jsx_require_child_js.js @@ -0,0 +1 @@ +var requirePlainJavascript = true; diff --git a/test/dummy/app/assets/javascripts/require_test/jsx_require_child_js.jsx b/test/dummy/app/assets/javascripts/require_test/jsx_require_child_js.jsx deleted file mode 100644 index 5e42dbd2a..000000000 --- a/test/dummy/app/assets/javascripts/require_test/jsx_require_child_js.jsx +++ /dev/null @@ -1 +0,0 @@ -
\ No newline at end of file diff --git a/test/dummy/app/assets/javascripts/require_test/jsx_require_child_jsx.jsx b/test/dummy/app/assets/javascripts/require_test/jsx_require_child_jsx.jsx new file mode 100644 index 000000000..e90a236d8 --- /dev/null +++ b/test/dummy/app/assets/javascripts/require_test/jsx_require_child_jsx.jsx @@ -0,0 +1 @@ +
diff --git a/test/react/jsx/jsx_prepocessor_test.rb b/test/react/jsx/jsx_prepocessor_test.rb index 07807b3b5..892cf1059 100644 --- a/test/react/jsx/jsx_prepocessor_test.rb +++ b/test/react/jsx/jsx_prepocessor_test.rb @@ -1,16 +1,18 @@ require 'test_helper' when_sprockets_available do - class JSXPreprocessorTest < ActionDispatch::IntegrationTest - EXPECTED_JS = <