diff --git a/lib/react/server_rendering/sprockets_renderer.rb b/lib/react/server_rendering/sprockets_renderer.rb index 0f628a284..47e904138 100644 --- a/lib/react/server_rendering/sprockets_renderer.rb +++ b/lib/react/server_rendering/sprockets_renderer.rb @@ -12,11 +12,13 @@ class SprocketsRenderer < ExecJSRenderer # Reimplement console methods for replaying on the client CONSOLE_POLYFILL = File.read(File.join(File.dirname(__FILE__), "sprockets_renderer/console_polyfill.js")) CONSOLE_REPLAY = File.read(File.join(File.dirname(__FILE__), "sprockets_renderer/console_replay.js")) + TIMEOUT_POLYFILL = File.read(File.join(File.dirname(__FILE__), "sprockets_renderer/timeout_polyfill.js")) def initialize(options={}) @replay_console = options.fetch(:replay_console, true) filenames = options.fetch(:files, ["react-server.js", "components.js"]) js_code = CONSOLE_POLYFILL.dup + js_code << TIMEOUT_POLYFILL.dup js_code << options.fetch(:code, '') filenames.each do |filename| diff --git a/lib/react/server_rendering/sprockets_renderer/timeout_polyfill.js b/lib/react/server_rendering/sprockets_renderer/timeout_polyfill.js new file mode 100644 index 000000000..ca6a756ec --- /dev/null +++ b/lib/react/server_rendering/sprockets_renderer/timeout_polyfill.js @@ -0,0 +1,26 @@ +function getStackTrace() { + var stack; + try { + throw new Error(''); + } + catch (error) { + stack = error.stack || ''; + } + stack = stack.split('\\n').map(function (line) { + return line.trim(); + }); + return stack.splice(stack[0] == 'Error' ? 2 : 1); +}; + +function printError(functionName){ + console.error(functionName + ' is not defined for execJS. See https://github.com/sstephenson/execjs#faq. Note babel-polyfill may call this.'); + console.error(getStackTrace().join('\\n')); +}; + +function setTimeout() { + printError('setTimeout'); +}; + +function clearTimeout() { + printError('clearTimeout'); +}; diff --git a/test/dummy/app/assets/javascripts/components/WithSetTimeout.js.jsx b/test/dummy/app/assets/javascripts/components/WithSetTimeout.js.jsx new file mode 100644 index 000000000..16bf957c4 --- /dev/null +++ b/test/dummy/app/assets/javascripts/components/WithSetTimeout.js.jsx @@ -0,0 +1,9 @@ +WithSetTimeout = React.createClass({ + componentWillMount: function () { + setTimeout(function () {}, 1000) + clearTimeout(0) + }, + render: function () { + return I am rendered! + } +}) diff --git a/test/react/server_rendering/sprockets_renderer_test.rb b/test/react/server_rendering/sprockets_renderer_test.rb index 301aa8a8d..b602dd7dd 100644 --- a/test/react/server_rendering/sprockets_renderer_test.rb +++ b/test/react/server_rendering/sprockets_renderer_test.rb @@ -48,6 +48,16 @@ class SprocketsRendererTest < ActiveSupport::TestCase assert_match(/\n/, err.to_s, "it includes the multi-line backtrace") end + test '#render polyfills setTimeout and clearTimeout and warn about it' do + result = @renderer.render("WithSetTimeout", {}, nil) + + assert_match(/I am rendered!<\/span>/, result) + + message = "is not defined for execJS. See https://github.com/sstephenson/execjs#faq. Note babel-polyfill may call this." + assert_match(/console.error.apply\(console, \["clearTimeout #{message}"\]\);$/, result) + assert_match(/console.error.apply\(console, \["setTimeout #{message}"\]\);$/, result) + end + test '.new accepts additional code to add to the JS context' do additional_code = File.read(File.expand_path("../../../helper_files/WithoutSprockets.js", __FILE__))