From 8b110afef50fb41012520de32b7a083b6190d76c Mon Sep 17 00:00:00 2001 From: Jakub Malinowski Date: Sun, 15 Sep 2013 16:56:03 +0200 Subject: [PATCH 01/11] Allow react.js and jsxtransformer.js to be overriden by user --- lib/react/rails/railtie.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/react/rails/railtie.rb b/lib/react/rails/railtie.rb index e29ff92c5..ffad436fd 100644 --- a/lib/react/rails/railtie.rb +++ b/lib/react/rails/railtie.rb @@ -5,7 +5,9 @@ module Rails class Railtie < ::Rails::Railtie config.react = ActiveSupport::OrderedOptions.new - initializer "react_rails.setup_vendor", :after => "sprockets.environment" do |app| + # run after all initializers to allow sprockets to pick up react.js and + # jsxtransformer.js from end-user to override ours if needed + config.after_initialize do |app| variant = app.config.react.variant # Mimic behavior of ember-rails... From 59dcec4e8ffd8e3fbd38d9b5364efaaeefd3ec71 Mon Sep 17 00:00:00 2001 From: Jakub Malinowski Date: Sun, 15 Sep 2013 17:38:01 +0200 Subject: [PATCH 02/11] Allow user to override jsxtransformer used for .jsx files --- lib/react/jsx.rb | 2 ++ lib/react/jsx/template.rb | 2 +- lib/react/rails/engine.rb | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/react/jsx.rb b/lib/react/jsx.rb index c9cfa24c1..693299169 100644 --- a/lib/react/jsx.rb +++ b/lib/react/jsx.rb @@ -1,9 +1,11 @@ require 'execjs' require 'react/source' require 'react/jsx/template' +require 'rails' module React module JSX + # lazily loaded during first request def self.context # TODO: create React::Source::contents_for contents = diff --git a/lib/react/jsx/template.rb b/lib/react/jsx/template.rb index 3118b5fb8..18316748c 100644 --- a/lib/react/jsx/template.rb +++ b/lib/react/jsx/template.rb @@ -9,7 +9,7 @@ class Template < Tilt::Template def prepare end - def evaluate(scopre, locals, &block) + def evaluate(scope, locals, &block) @output ||= JSX::transform(data) end end diff --git a/lib/react/rails/engine.rb b/lib/react/rails/engine.rb index c6afcc8f1..7af1f8c54 100644 --- a/lib/react/rails/engine.rb +++ b/lib/react/rails/engine.rb @@ -1,7 +1,7 @@ module React module Rails class Engine < ::Rails::Engine - initializer "react_rails.setup_engine", :after => "sprockets.environment", :group => :all do |app| + initializer "react_rails.setup_engine", :group => :all do |app| app.assets.register_engine '.jsx', React::JSX::Template end end From aca329433e64a184214b85d89837357d13240a17 Mon Sep 17 00:00:00 2001 From: Jakub Malinowski Date: Sun, 15 Sep 2013 22:30:04 +0200 Subject: [PATCH 03/11] Document manual react and JSXTransformer version changing --- README.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/README.md b/README.md index 32a3d3e7a..fbee2886b 100644 --- a/README.md +++ b/README.md @@ -129,3 +129,25 @@ Component = React.createClass `` ``` +### Changing react.js and JSXTransformer.js versions + +Major, minor, and patch versions of this gem are based on react's version, e.g. +`0.4.1.1` means that react has version `0.4.1`. There may be fixes or improvements +introduced in say `0.5.0.0`, but you will still need react in version `0.4.1`. +If you needed to change JSXTransformer version it's possible too. + +#### How to + +Just put another version of react or JSXTransformer in your assets. Any place +you would put a javascript file will be fine, probably +`/vendor/javascripts/react.js` and `/vendor/javascripts/JSXTransformer.js` +would be best. (You don't have to replace both) + +#### Things to remember + +If you replace `JSXTransformer.js`, you have to restart your rails instance, +because the jsx compiler context is cached, name of the file is case-sensitive. + +We provide different variants of `react.js` based on environment, but you will +need to provide the same file called `react.js` which will be used for both +production and development. From d5c47179d11b82997505b04195718653589f2e15 Mon Sep 17 00:00:00 2001 From: Jakub Malinowski Date: Fri, 20 Sep 2013 01:19:18 +0200 Subject: [PATCH 04/11] Allow for drop-in replacement using recommended files structure --- lib/react/jsx.rb | 21 +++++++----- lib/react/rails/railtie.rb | 12 +++++-- .../app/assets/javascripts/example2.js.jsx | 2 ++ test/dummy/config/environments/test.rb | 8 ++++- .../vendor/assets/react/JSXTransformer__.js | 7 ++++ .../dummy/vendor/assets/react/test/react__.js | 1 + test/jsxtransform_test.rb | 16 ++++++++- test/react_test.rb | 33 +++++++++++++++++++ test/test_helper.rb | 3 ++ 9 files changed, 91 insertions(+), 12 deletions(-) create mode 100644 test/dummy/app/assets/javascripts/example2.js.jsx create mode 100644 test/dummy/vendor/assets/react/JSXTransformer__.js create mode 100644 test/dummy/vendor/assets/react/test/react__.js create mode 100644 test/react_test.rb diff --git a/lib/react/jsx.rb b/lib/react/jsx.rb index 693299169..8ce4b8bf9 100644 --- a/lib/react/jsx.rb +++ b/lib/react/jsx.rb @@ -5,15 +5,20 @@ module React module JSX - # lazily loaded during first request def self.context - # TODO: create React::Source::contents_for - contents = - # If execjs uses therubyracer, there is no 'global'. Make sure - # we have it so JSX script can work properly. - 'var global = global || this;' + - File.read(React::Source.bundled_path_for('JSXTransformer.js')) - @context ||= ExecJS.compile(contents) + # lazily loaded during first request and reloaded every time when in dev or test + unless @context && ::Rails.env.production? + + # TODO: create React::Source::contents_for + contents = + # If execjs uses therubyracer, there is no 'global'. Make sure + # we have it so JSX script can work properly. + 'var global = global || this;' + + File.read(React::Source.bundled_path_for('JSXTransformer.js')) + @context = ExecJS.compile(contents) + end + + @context end def self.transform(code) diff --git a/lib/react/rails/railtie.rb b/lib/react/rails/railtie.rb index ffad436fd..ee62e5610 100644 --- a/lib/react/rails/railtie.rb +++ b/lib/react/rails/railtie.rb @@ -28,9 +28,17 @@ class Railtie < ::Rails::Railtie tmp_path.join('react.js')) FileUtils.cp(::React::Source.bundled_path_for('JSXTransformer.js'), tmp_path.join('JSXTransformer.js')) + app.assets.prepend_path tmp_path - # Make sure it can be found - app.assets.append_path(tmp_path) + # Allow overriding react files that are not based on environment + # e.g. /vendor/react/JSXTransformer.js + dropin_path = app.root.join("vendor/assets/react") + app.assets.prepend_path dropin_path if dropin_path.exist? + + # Allow overriding react files that are based on environment + # e.g. /vendor/react/react.js + dropin_path_env = app.root.join("vendor/assets/react/#{variant}") + app.assets.prepend_path dropin_path_env if dropin_path_env.exist? end end end diff --git a/test/dummy/app/assets/javascripts/example2.js.jsx b/test/dummy/app/assets/javascripts/example2.js.jsx new file mode 100644 index 000000000..2611211ae --- /dev/null +++ b/test/dummy/app/assets/javascripts/example2.js.jsx @@ -0,0 +1,2 @@ +/** @jsx React.DOM */ +
; diff --git a/test/dummy/config/environments/test.rb b/test/dummy/config/environments/test.rb index afbc0ae77..cff2ea781 100644 --- a/test/dummy/config/environments/test.rb +++ b/test/dummy/config/environments/test.rb @@ -5,7 +5,11 @@ # test suite. You never need to work with it otherwise. Remember that # your test database is "scratch space" for the test suite and is wiped # and recreated between test runs. Don't rely on the data there! - config.cache_classes = true + + # we need this to reload the jsx transformer when different version is dropped in + config.cache_classes = false + config.reload_plugins = true + config.assets.cache_store = :null_store # Do not eager load code on boot. This avoids loading your whole application # just for the purpose of running a single test. If you are using a tool that @@ -33,4 +37,6 @@ # Print deprecation notices to the stderr. config.active_support.deprecation = :stderr + + config.react.variant = :test end diff --git a/test/dummy/vendor/assets/react/JSXTransformer__.js b/test/dummy/vendor/assets/react/JSXTransformer__.js new file mode 100644 index 000000000..3eba809e7 --- /dev/null +++ b/test/dummy/vendor/assets/react/JSXTransformer__.js @@ -0,0 +1,7 @@ +var JSXTransformer = { + transform: function () { + return { + code: 'test_confirmation_token_jsx_transformed;' + }; + } +}; diff --git a/test/dummy/vendor/assets/react/test/react__.js b/test/dummy/vendor/assets/react/test/react__.js new file mode 100644 index 000000000..0860b7de4 --- /dev/null +++ b/test/dummy/vendor/assets/react/test/react__.js @@ -0,0 +1 @@ +'test_confirmation_token_react_content'; \ No newline at end of file diff --git a/test/jsxtransform_test.rb b/test/jsxtransform_test.rb index 973344aad..883f945d6 100644 --- a/test/jsxtransform_test.rb +++ b/test/jsxtransform_test.rb @@ -1,6 +1,7 @@ require 'test_helper' +require 'fileutils' -# The transformer is inserting a newline after the docblock for some reason... +# Sprockets is inserting a newline after the docblock for some reason... EXPECTED_JS = < Date: Thu, 26 Sep 2013 00:35:22 +0200 Subject: [PATCH 05/11] Updated docs with right information on changing react's version --- README.md | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index fbee2886b..524a37fea 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,8 @@ As with all gem dependencies, we strongly recommend adding `react-rails` to your gem 'react-rails', '~> 0.8.0.0' ``` +Starting with `0.4.1` there is a fix, which alows execjs to transforms jsx files, so if you need a version lower than +`0.4.1` you will have to replace JSXTransformer.js, see below on how to do it. ## Usage @@ -131,23 +133,20 @@ Component = React.createClass ### Changing react.js and JSXTransformer.js versions -Major, minor, and patch versions of this gem are based on react's version, e.g. -`0.4.1.1` means that react has version `0.4.1`. There may be fixes or improvements -introduced in say `0.5.0.0`, but you will still need react in version `0.4.1`. -If you needed to change JSXTransformer version it's possible too. +This gem's version is independent from actual react's version, that's why you need declarations for both `react-rails` +and `react-source` in your `Gemfile`. However, in some cases you may want to have your `react.js` and `JSXTransformer.js` +files come from different releases. To achieve that, you have to manually replace either of them in your app. -#### How to +#### Instructions -Just put another version of react or JSXTransformer in your assets. Any place -you would put a javascript file will be fine, probably -`/vendor/javascripts/react.js` and `/vendor/javascripts/JSXTransformer.js` -would be best. (You don't have to replace both) +Just put another version of `react.js` or `JSXTransformer.js` under `/vendor/assets/react` directory. +If you need different versions of `react.js` for production and development, then use a subdirectory named +after `config.react.variant`, e.g. you set `config.react.variant = :development` so for this environment +`react.js` is expected to be in `/vendor/assets/react/development` #### Things to remember If you replace `JSXTransformer.js`, you have to restart your rails instance, -because the jsx compiler context is cached, name of the file is case-sensitive. +because the jsx compiler context is cached. -We provide different variants of `react.js` based on environment, but you will -need to provide the same file called `react.js` which will be used for both -production and development. +Name of the `JSXTransformer.js` file *is case-sensitive*. From 10cf76676c0713cbe7d9de751f7b023b267f0698 Mon Sep 17 00:00:00 2001 From: Jakub Malinowski Date: Thu, 26 Sep 2013 00:36:44 +0200 Subject: [PATCH 06/11] Fixed react.js-replacing paths in comments --- lib/react/rails/railtie.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/react/rails/railtie.rb b/lib/react/rails/railtie.rb index ee62e5610..5f1b7fcee 100644 --- a/lib/react/rails/railtie.rb +++ b/lib/react/rails/railtie.rb @@ -31,12 +31,12 @@ class Railtie < ::Rails::Railtie app.assets.prepend_path tmp_path # Allow overriding react files that are not based on environment - # e.g. /vendor/react/JSXTransformer.js + # e.g. /vendor/assets/react/JSXTransformer.js dropin_path = app.root.join("vendor/assets/react") app.assets.prepend_path dropin_path if dropin_path.exist? # Allow overriding react files that are based on environment - # e.g. /vendor/react/react.js + # e.g. /vendor/assets/react/react.js dropin_path_env = app.root.join("vendor/assets/react/#{variant}") app.assets.prepend_path dropin_path_env if dropin_path_env.exist? end From 20801366998912f6c1f67a74dbff91c03ebfae10 Mon Sep 17 00:00:00 2001 From: Jakub Malinowski Date: Sun, 1 Dec 2013 16:26:25 +0100 Subject: [PATCH 07/11] Rename test asset files due to collisions --- .../{example2.js.jsx => example3.js.jsx} | 0 test/jsxtransform_test.rb | 23 +++++++++---------- 2 files changed, 11 insertions(+), 12 deletions(-) rename test/dummy/app/assets/javascripts/{example2.js.jsx => example3.js.jsx} (100%) diff --git a/test/dummy/app/assets/javascripts/example2.js.jsx b/test/dummy/app/assets/javascripts/example3.js.jsx similarity index 100% rename from test/dummy/app/assets/javascripts/example2.js.jsx rename to test/dummy/app/assets/javascripts/example3.js.jsx diff --git a/test/jsxtransform_test.rb b/test/jsxtransform_test.rb index 883f945d6..8a28f9884 100644 --- a/test/jsxtransform_test.rb +++ b/test/jsxtransform_test.rb @@ -32,18 +32,6 @@ class JSXTransformTest < ActionDispatch::IntegrationTest FileUtils.rm_r CACHE_PATH if CACHE_PATH.exist? end - test 'can use dropped in version of JSX transformer' do - hidden_path = File.expand_path("../dummy/vendor/assets/react/JSXTransformer__.js", __FILE__) - replacing_path = File.expand_path("../dummy/vendor/assets/react/JSXTransformer.js", __FILE__) - - FileUtils.mv hidden_path, replacing_path - get 'assets/example2.js' - assert_response :success - assert_equal 'test_confirmation_token_jsx_transformed;', @response.body - FileUtils.mv replacing_path, hidden_path - FileUtils.rm_r CACHE_PATH if CACHE_PATH.exist? - end - test 'asset pipeline should transform JSX + Coffeescript' do get 'assets/example2.js' assert_response :success @@ -56,4 +44,15 @@ class JSXTransformTest < ActionDispatch::IntegrationTest assert_equal EXPECTED_JS_2.gsub(/\s/, ''), @response.body.gsub(/\s/, '') end + test 'can use dropped in version of JSX transformer' do + hidden_path = File.expand_path("../dummy/vendor/assets/react/JSXTransformer__.js", __FILE__) + replacing_path = File.expand_path("../dummy/vendor/assets/react/JSXTransformer.js", __FILE__) + + FileUtils.mv hidden_path, replacing_path + get 'assets/example3.js' + assert_response :success + assert_equal 'test_confirmation_token_jsx_transformed;', @response.body + FileUtils.mv replacing_path, hidden_path + FileUtils.rm_r CACHE_PATH if CACHE_PATH.exist? + end end From bc91781704a2a3040202066416581330e2249d4c Mon Sep 17 00:00:00 2001 From: Jakub Malinowski Date: Mon, 9 Dec 2013 22:49:36 +0100 Subject: [PATCH 08/11] Iron out problems left uncaught during rebase --- lib/react/jsx.rb | 8 +++++--- lib/react/rails/railtie.rb | 2 -- test/jsxtransform_test.rb | 8 +++++--- test/react_test.rb | 11 +++++++---- 4 files changed, 17 insertions(+), 12 deletions(-) diff --git a/lib/react/jsx.rb b/lib/react/jsx.rb index 8ce4b8bf9..f58d00a36 100644 --- a/lib/react/jsx.rb +++ b/lib/react/jsx.rb @@ -8,13 +8,15 @@ module JSX def self.context # lazily loaded during first request and reloaded every time when in dev or test unless @context && ::Rails.env.production? - - # TODO: create React::Source::contents_for contents = # If execjs uses therubyracer, there is no 'global'. Make sure # we have it so JSX script can work properly. 'var global = global || this;' + - File.read(React::Source.bundled_path_for('JSXTransformer.js')) + + # search for transformer file using sprockets - allows user to override + # this file in his own application + File.read(::Rails.application.assets.resolve('JSXTransformer.js')) + @context = ExecJS.compile(contents) end diff --git a/lib/react/rails/railtie.rb b/lib/react/rails/railtie.rb index 5f1b7fcee..3dfbf5af6 100644 --- a/lib/react/rails/railtie.rb +++ b/lib/react/rails/railtie.rb @@ -8,8 +8,6 @@ class Railtie < ::Rails::Railtie # run after all initializers to allow sprockets to pick up react.js and # jsxtransformer.js from end-user to override ours if needed config.after_initialize do |app| - variant = app.config.react.variant - # Mimic behavior of ember-rails... # We want to include different files in dev/prod. The unminified builds # contain console logging for invariants and logging to help catch diff --git a/test/jsxtransform_test.rb b/test/jsxtransform_test.rb index 8a28f9884..7a9a820a5 100644 --- a/test/jsxtransform_test.rb +++ b/test/jsxtransform_test.rb @@ -27,9 +27,9 @@ class JSXTransformTest < ActionDispatch::IntegrationTest test 'asset pipeline should transform JSX' do get 'assets/example.js' + FileUtils.rm_r CACHE_PATH if CACHE_PATH.exist? assert_response :success assert_equal EXPECTED_JS, @response.body - FileUtils.rm_r CACHE_PATH if CACHE_PATH.exist? end test 'asset pipeline should transform JSX + Coffeescript' do @@ -50,9 +50,11 @@ class JSXTransformTest < ActionDispatch::IntegrationTest FileUtils.mv hidden_path, replacing_path get 'assets/example3.js' - assert_response :success - assert_equal 'test_confirmation_token_jsx_transformed;', @response.body + FileUtils.mv replacing_path, hidden_path FileUtils.rm_r CACHE_PATH if CACHE_PATH.exist? + + assert_response :success + assert_equal 'test_confirmation_token_jsx_transformed;', @response.body end end diff --git a/test/react_test.rb b/test/react_test.rb index f8c5d4cc3..c78243e69 100644 --- a/test/react_test.rb +++ b/test/react_test.rb @@ -11,11 +11,12 @@ class ReactTest < ActionDispatch::IntegrationTest File.open(actual_react_file_path, 'w') {|f| f.write react_file_token} get 'assets/react.js' - assert_response :success - assert_equal react_file_token, @response.body File.open(actual_react_file_path, 'w') {|f| f.write actual_react_file_content} FileUtils.rm_r CACHE_PATH if CACHE_PATH.exist? + + assert_response :success + assert_equal react_file_token, @response.body end test 'asset pipeline should deliver drop-in react file replacement' do @@ -24,10 +25,12 @@ class ReactTest < ActionDispatch::IntegrationTest FileUtils.mv hidden_path, replacing_path get 'assets/react.js' - assert_response :success - assert_equal "'test_confirmation_token_react_content';\n", @response.body + FileUtils.mv replacing_path, hidden_path FileUtils.rm_r CACHE_PATH if CACHE_PATH.exist? + + assert_response :success + assert_equal "'test_confirmation_token_react_content';\n", @response.body end end From 14b4df73fde0aa2c772871b2f7de33f90b480c7a Mon Sep 17 00:00:00 2001 From: Jakub Malinowski Date: Mon, 9 Dec 2013 22:50:47 +0100 Subject: [PATCH 09/11] Bump up version to stop being dependent on react versioning --- lib/react/rails/version.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/react/rails/version.rb b/lib/react/rails/version.rb index 80f4182ff..1c1ffc401 100644 --- a/lib/react/rails/version.rb +++ b/lib/react/rails/version.rb @@ -2,7 +2,6 @@ module React module Rails # Version numbers will track react-source, but we'll add another level so # that we can increment, but have some amount of stability. - VERSION = '0.8.0.0' + VERSION = '1.0.0.beta1' end end - From ae2dee4404f9a1e2f552cbb864cef897b3a65952 Mon Sep 17 00:00:00 2001 From: Jakub Malinowski Date: Tue, 7 Jan 2014 12:32:05 +0100 Subject: [PATCH 10/11] Updated info about drop-in feature in README --- README.md | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 524a37fea..a868f2371 100644 --- a/README.md +++ b/README.md @@ -17,17 +17,14 @@ As with all gem dependencies, we strongly recommend adding `react-rails` to your ```ruby # Gemfile -gem 'react-rails', '~> 0.8.0.0' +gem 'react-rails', '~> 1.0.0' ``` -Starting with `0.4.1` there is a fix, which alows execjs to transforms jsx files, so if you need a version lower than -`0.4.1` you will have to replace JSXTransformer.js, see below on how to do it. - ## Usage ### react.js -In order to use React client-side in your application, you must make sure the browser requests it. One way to do that is to drop `react.js` into `app/assets/javascript/` and by default your application manifest will pick it up. There are downsides to this approach, so we made it even easier. Once you have `react-rails` installed, you can just add a line into your config file (see Configuring) and require react directly in your manifest: +In order to use React client-side in your application, you must make sure the browser requests it. One way to do that is to drop `react.js` into `vendor/assets/javascript/` and by default your application manifest will pick it up. There are downsides to this approach, so we made it even easier. Once you have `react-rails` installed, you can just add a line into your config file (see Configuring) and require react directly in your manifest: You can `require` it in your manifest: @@ -133,9 +130,7 @@ Component = React.createClass ### Changing react.js and JSXTransformer.js versions -This gem's version is independent from actual react's version, that's why you need declarations for both `react-rails` -and `react-source` in your `Gemfile`. However, in some cases you may want to have your `react.js` and `JSXTransformer.js` -files come from different releases. To achieve that, you have to manually replace either of them in your app. +In some cases you may want to have your `react.js` and `JSXTransformer.js` files come from a different release than the one, that is specified in the `react-rails.gemspec`. To achieve that, you have to manually replace them in your app. #### Instructions From 1f0d8ce67a7039f041f0572fa50e0e5404a6081a Mon Sep 17 00:00:00 2001 From: Jakub Malinowski Date: Sun, 9 Feb 2014 23:46:38 +0100 Subject: [PATCH 11/11] readme: fixed info about restarting to bust transformer context cache --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a868f2371..3355843a8 100644 --- a/README.md +++ b/README.md @@ -141,7 +141,7 @@ after `config.react.variant`, e.g. you set `config.react.variant = :development` #### Things to remember -If you replace `JSXTransformer.js`, you have to restart your rails instance, +If you replace `JSXTransformer.js` in production environment, you have to restart your rails instance, because the jsx compiler context is cached. Name of the `JSXTransformer.js` file *is case-sensitive*.