diff --git a/src/renderers/dom/server/ReactServerAsyncRendering.js b/src/renderers/dom/server/ReactServerAsyncRendering.js index 549bacb692a92..cf9608ad0e717 100644 --- a/src/renderers/dom/server/ReactServerAsyncRendering.js +++ b/src/renderers/dom/server/ReactServerAsyncRendering.js @@ -89,31 +89,60 @@ function renderToStringStream(element, stream, options) { 'renderToStringStream(): You must pass a valid ReactElement.' ); + var usingV1 = false; + // deprecation warning for version 2. The v1 API allowed you to pass in a stream and returned + // a Promise of a hash ; the v2 API returns a stream with a .hash property. + // v1 also allowed an options hash, which v2 will not. + if (stream) { + usingV1 = true; + console.error( + "You are using v1.x of the renderToString API, which is deprecated. " + + "Instead of accepting a stream parameter and returning a Promise of a hash, the API " + + "now returns a stream with a hash Promise property. " + + "Support for this version of the API will be removed in the 3.0.0 version of react-dom-stream. " + + "Please update your code, and for more info, check out (TODO: add URL here)." + ); + } else { + stream = require("stream").PassThrough(); + } + var bufferSize = 10000; if (options && options.bufferSize) { + console.error( + "The options hash and bufferSize arguments have been deprecated and will be removed in " + + "the v3.0.0 of react-dom-stream. " + + "Please update your code, and for more info, check out (TODO: add URL here)." + ); bufferSize = options.bufferSize; } - var transaction; - try { - ReactUpdates.injection.injectBatchingStrategy(ReactServerBatchingStrategy); - - var id = ReactInstanceHandles.createReactRootID(); - transaction = ReactServerRenderingTransaction.getPooled(false); - - stream = bufferedStream(stream, bufferSize); - stream = hashedStream(stream); - var hash = transaction.perform(function() { - var componentInstance = instantiateReactComponent(element, null); - componentInstance.mountComponentAsync(id, transaction, emptyObject, stream); - stream.flush(); - return stream.hash(); - }, null); - return Promise.resolve(hash); - } finally { - ReactServerRenderingTransaction.release(transaction); - // Revert to the DOM batching strategy since these two renderers - // currently share these stateful modules. - ReactUpdates.injection.injectBatchingStrategy(ReactDefaultBatchingStrategy); + var hashPromise = new Promise(function(resolve, reject) { + var transaction; + try { + ReactUpdates.injection.injectBatchingStrategy(ReactServerBatchingStrategy); + + var id = ReactInstanceHandles.createReactRootID(); + transaction = ReactServerRenderingTransaction.getPooled(false); + + var wrappedStream = hashedStream(bufferedStream(stream, bufferSize)); + transaction.perform(function() { + var componentInstance = instantiateReactComponent(element, null); + componentInstance.mountComponentAsync(id, transaction, emptyObject, wrappedStream); + wrappedStream.flush(); + resolve(wrappedStream.hash()); + }, null); + } finally { + ReactServerRenderingTransaction.release(transaction); + // Revert to the DOM batching strategy since these two renderers + // currently share these stateful modules. + ReactUpdates.injection.injectBatchingStrategy(ReactDefaultBatchingStrategy); + } + }); + + if (usingV1) { + return hashPromise; + } else { + stream.hash = hashPromise; + return stream; } } @@ -129,30 +158,59 @@ function renderToStaticMarkupStream(element, stream, options) { 'renderToStaticMarkupStream(): You must pass a valid ReactElement.' ); + var usingV1 = false; + // deprecation warning for version 2. The v1 API allowed you to pass in a stream and returned + // a Promise of a hash ; the v2 API returns a stream with a .hash property. + // v1 also allowed an options hash, which v2 will not. + if (stream) { + usingV1 = true; + console.error( + "You are using v1.x of the renderToMarkupStream API, which is deprecated. " + + "Instead of accepting a stream parameter and returning a Promise, the API now just returns a stream. " + + "Support for this version of the API will be removed in the 3.0.0 version of react-dom-stream. " + + "Please update your code, and for more info, check out (TODO: add URL here)." + ); + } else { + stream = require("stream").PassThrough(); + } + var bufferSize = 10000; if (options && options.bufferSize) { + console.error( + "The options hash and bufferSize arguments have been deprecated and will be removed in " + + "the v3.0.0 of react-dom-stream. " + + "Please update your code, and for more info, check out (TODO: add URL here)." + ); bufferSize = options.bufferSize; } - var transaction; - try { - ReactUpdates.injection.injectBatchingStrategy(ReactServerBatchingStrategy); - - var id = ReactInstanceHandles.createReactRootID(); - transaction = ReactServerRenderingTransaction.getPooled(true); - - stream = bufferedStream(stream, bufferSize); - transaction.perform(function() { - var componentInstance = instantiateReactComponent(element, null); - componentInstance.mountComponentAsync(id, transaction, emptyObject, stream); - stream.flush(); - }, null); - - return Promise.resolve(null); - } finally { - ReactServerRenderingTransaction.release(transaction); - // Revert to the DOM batching strategy since these two renderers - // currently share these stateful modules. - ReactUpdates.injection.injectBatchingStrategy(ReactDefaultBatchingStrategy); + var promise = new Promise(function(resolve, reject) { + var transaction; + try { + ReactUpdates.injection.injectBatchingStrategy(ReactServerBatchingStrategy); + + var id = ReactInstanceHandles.createReactRootID(); + transaction = ReactServerRenderingTransaction.getPooled(true); + + var wrappedStream = bufferedStream(stream, bufferSize); + transaction.perform(function() { + var componentInstance = instantiateReactComponent(element, null); + componentInstance.mountComponentAsync(id, transaction, emptyObject, wrappedStream); + wrappedStream.flush(); + }, null); + + return Promise.resolve(null); + } finally { + ReactServerRenderingTransaction.release(transaction); + // Revert to the DOM batching strategy since these two renderers + // currently share these stateful modules. + ReactUpdates.injection.injectBatchingStrategy(ReactDefaultBatchingStrategy); + } + }); + + if (usingV1) { + return promise; + } else { + return stream; } } diff --git a/src/renderers/dom/server/__tests__/ReactServerAsyncRendering-test.js b/src/renderers/dom/server/__tests__/ReactServerAsyncRendering-test.js index d76ff53e87d04..de21618c8501f 100644 --- a/src/renderers/dom/server/__tests__/ReactServerAsyncRendering-test.js +++ b/src/renderers/dom/server/__tests__/ReactServerAsyncRendering-test.js @@ -54,11 +54,8 @@ describe('ReactServerAsyncRendering', function() { }); ReactServerAsyncRendering.renderToStringStream( - hello world, - stream - ); - - stream.end(); + hello world + ).pipe(stream); }); it('should generate simple markup for self-closing tags', function() { @@ -69,11 +66,8 @@ describe('ReactServerAsyncRendering', function() { }); ReactServerAsyncRendering.renderToStringStream( - , - stream - ); - - stream.end(); + + ).pipe(stream); }); it('should generate simple markup for attribute with `>` symbol', function() { @@ -82,12 +76,9 @@ describe('ReactServerAsyncRendering', function() { '' ); }); - var response = ReactServerAsyncRendering.renderToStringStream( - , - stream - ); - - stream.end(); + ReactServerAsyncRendering.renderToStringStream( + + ).pipe(stream); }); it('should not register event listeners', function() { @@ -96,10 +87,9 @@ describe('ReactServerAsyncRendering', function() { var cb = mocks.getMockFunction(); ReactServerAsyncRendering.renderToStringStream( - hello world, - stream - ); - stream.end(); + hello world + ).pipe(stream); + expect(EventPluginHub.__getListenerBank()).toEqual({}); }); @@ -124,11 +114,9 @@ describe('ReactServerAsyncRendering', function() { return My name is {this.props.name}; }, }); - var response = ReactServerAsyncRendering.renderToStringStream( - , stream - ); - - stream.end(); + ReactServerAsyncRendering.renderToStringStream( + + ).pipe(stream); }); it('should only execute certain lifecycle methods', function() { @@ -174,11 +162,9 @@ describe('ReactServerAsyncRendering', function() { }, }); - var response = ReactServerAsyncRendering.renderToStringStream( - , stream - ); - - stream.end(); + ReactServerAsyncRendering.renderToStringStream( + + ).pipe(stream); expect(lifecycle).toEqual( ['getInitialState', 'componentWillMount', 'render'] @@ -267,9 +253,13 @@ describe('ReactServerAsyncRendering', function() { }); var hash; - ReactServerAsyncRendering.renderToStringStream( - , stream - ).then(function(hashValue) { + var renderedStream = ReactServerAsyncRendering.renderToStringStream( + + ); + + renderedStream.pipe(stream, {end:false}); + + renderedStream.hash.then(function(hashValue) { hash = hashValue; stream.end(); }) @@ -306,11 +296,9 @@ describe('ReactServerAsyncRendering', function() { }, }); - var response = ReactServerAsyncRendering.renderToStaticMarkupStream( - , stream - ); - - stream.end(); + ReactServerAsyncRendering.renderToStaticMarkupStream( + + ).pipe(stream); }); it('should not put checksum and React ID on text components', function() { @@ -323,11 +311,9 @@ describe('ReactServerAsyncRendering', function() { }, }); - var response = ReactServerAsyncRendering.renderToStaticMarkupStream( - , stream - ); - - stream.end(); + ReactServerAsyncRendering.renderToStaticMarkupStream( + + ).pipe(stream); }); it('should not register event listeners', function() { @@ -335,9 +321,9 @@ describe('ReactServerAsyncRendering', function() { var cb = mocks.getMockFunction(); ReactServerAsyncRendering.renderToStringStream( - hello world, - concatStream({encoding: "string"}, function(result) {}) - ); + hello world) + .pipe(concatStream({encoding: "string"}, function(result) {})); + expect(EventPluginHub.__getListenerBank()).toEqual({}); }); @@ -380,11 +366,10 @@ describe('ReactServerAsyncRendering', function() { expect(result).toBe('Component name: TestComponent'); }); - var response = ReactServerAsyncRendering.renderToStaticMarkupStream( - , stream - ); + ReactServerAsyncRendering.renderToStaticMarkupStream( + + ).pipe(stream); - stream.end(); expect(lifecycle).toEqual( ['getInitialState', 'componentWillMount', 'render'] ); @@ -429,10 +414,8 @@ describe('ReactServerAsyncRendering', function() { throw new Error('Browser reconcile transaction should not be used'); }; ReactServerAsyncRendering.renderToStringStream( - , stream - ); - - stream.end(); + + ).pipe(stream); }); }); });