Skip to content

Commit f5d3a81

Browse files
committed
Code changes to provide a preliminary implementation of the v2 API, as a result of issue facebook#2. Still TODO: change documentation and do some sanity perf testing to make sure that streaming isn't impacted by the code flow changes.
1 parent 5ef5b4e commit f5d3a81

File tree

2 files changed

+136
-95
lines changed

2 files changed

+136
-95
lines changed

src/renderers/dom/server/ReactServerAsyncRendering.js

Lines changed: 99 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -89,31 +89,60 @@ function renderToStringStream(element, stream, options) {
8989
'renderToStringStream(): You must pass a valid ReactElement.'
9090
);
9191

92+
var usingV1 = false;
93+
// deprecation warning for version 2. The v1 API allowed you to pass in a stream and returned
94+
// a Promise of a hash ; the v2 API returns a stream with a .hash property.
95+
// v1 also allowed an options hash, which v2 will not.
96+
if (stream) {
97+
usingV1 = true;
98+
console.error(
99+
"You are using v1.x of the renderToString API, which is deprecated. " +
100+
"Instead of accepting a stream parameter and returning a Promise of a hash, the API " +
101+
"now returns a stream with a hash Promise property. " +
102+
"Support for this version of the API will be removed in the 3.0.0 version of react-dom-stream. " +
103+
"Please update your code, and for more info, check out (TODO: add URL here)."
104+
);
105+
} else {
106+
stream = require("stream").PassThrough();
107+
}
108+
92109
var bufferSize = 10000;
93110
if (options && options.bufferSize) {
111+
console.error(
112+
"The options hash and bufferSize arguments have been deprecated and will be removed in " +
113+
"the v3.0.0 of react-dom-stream. " +
114+
"Please update your code, and for more info, check out (TODO: add URL here)."
115+
);
94116
bufferSize = options.bufferSize;
95117
}
96-
var transaction;
97-
try {
98-
ReactUpdates.injection.injectBatchingStrategy(ReactServerBatchingStrategy);
99-
100-
var id = ReactInstanceHandles.createReactRootID();
101-
transaction = ReactServerRenderingTransaction.getPooled(false);
102-
103-
stream = bufferedStream(stream, bufferSize);
104-
stream = hashedStream(stream);
105-
var hash = transaction.perform(function() {
106-
var componentInstance = instantiateReactComponent(element, null);
107-
componentInstance.mountComponentAsync(id, transaction, emptyObject, stream);
108-
stream.flush();
109-
return stream.hash();
110-
}, null);
111-
return Promise.resolve(hash);
112-
} finally {
113-
ReactServerRenderingTransaction.release(transaction);
114-
// Revert to the DOM batching strategy since these two renderers
115-
// currently share these stateful modules.
116-
ReactUpdates.injection.injectBatchingStrategy(ReactDefaultBatchingStrategy);
118+
var hashPromise = new Promise(function(resolve, reject) {
119+
var transaction;
120+
try {
121+
ReactUpdates.injection.injectBatchingStrategy(ReactServerBatchingStrategy);
122+
123+
var id = ReactInstanceHandles.createReactRootID();
124+
transaction = ReactServerRenderingTransaction.getPooled(false);
125+
126+
var wrappedStream = hashedStream(bufferedStream(stream, bufferSize));
127+
transaction.perform(function() {
128+
var componentInstance = instantiateReactComponent(element, null);
129+
componentInstance.mountComponentAsync(id, transaction, emptyObject, wrappedStream);
130+
wrappedStream.flush();
131+
resolve(wrappedStream.hash());
132+
}, null);
133+
} finally {
134+
ReactServerRenderingTransaction.release(transaction);
135+
// Revert to the DOM batching strategy since these two renderers
136+
// currently share these stateful modules.
137+
ReactUpdates.injection.injectBatchingStrategy(ReactDefaultBatchingStrategy);
138+
}
139+
});
140+
141+
if (usingV1) {
142+
return hashPromise;
143+
} else {
144+
stream.hash = hashPromise;
145+
return stream;
117146
}
118147
}
119148

@@ -129,30 +158,59 @@ function renderToStaticMarkupStream(element, stream, options) {
129158
'renderToStaticMarkupStream(): You must pass a valid ReactElement.'
130159
);
131160

161+
var usingV1 = false;
162+
// deprecation warning for version 2. The v1 API allowed you to pass in a stream and returned
163+
// a Promise of a hash ; the v2 API returns a stream with a .hash property.
164+
// v1 also allowed an options hash, which v2 will not.
165+
if (stream) {
166+
usingV1 = true;
167+
console.error(
168+
"You are using v1.x of the renderToMarkupStream API, which is deprecated. " +
169+
"Instead of accepting a stream parameter and returning a Promise, the API now just returns a stream. " +
170+
"Support for this version of the API will be removed in the 3.0.0 version of react-dom-stream. " +
171+
"Please update your code, and for more info, check out (TODO: add URL here)."
172+
);
173+
} else {
174+
stream = require("stream").PassThrough();
175+
}
176+
132177
var bufferSize = 10000;
133178
if (options && options.bufferSize) {
179+
console.error(
180+
"The options hash and bufferSize arguments have been deprecated and will be removed in " +
181+
"the v3.0.0 of react-dom-stream. " +
182+
"Please update your code, and for more info, check out (TODO: add URL here)."
183+
);
134184
bufferSize = options.bufferSize;
135185
}
136-
var transaction;
137-
try {
138-
ReactUpdates.injection.injectBatchingStrategy(ReactServerBatchingStrategy);
139-
140-
var id = ReactInstanceHandles.createReactRootID();
141-
transaction = ReactServerRenderingTransaction.getPooled(true);
142-
143-
stream = bufferedStream(stream, bufferSize);
144-
transaction.perform(function() {
145-
var componentInstance = instantiateReactComponent(element, null);
146-
componentInstance.mountComponentAsync(id, transaction, emptyObject, stream);
147-
stream.flush();
148-
}, null);
149-
150-
return Promise.resolve(null);
151-
} finally {
152-
ReactServerRenderingTransaction.release(transaction);
153-
// Revert to the DOM batching strategy since these two renderers
154-
// currently share these stateful modules.
155-
ReactUpdates.injection.injectBatchingStrategy(ReactDefaultBatchingStrategy);
186+
var promise = new Promise(function(resolve, reject) {
187+
var transaction;
188+
try {
189+
ReactUpdates.injection.injectBatchingStrategy(ReactServerBatchingStrategy);
190+
191+
var id = ReactInstanceHandles.createReactRootID();
192+
transaction = ReactServerRenderingTransaction.getPooled(true);
193+
194+
var wrappedStream = bufferedStream(stream, bufferSize);
195+
transaction.perform(function() {
196+
var componentInstance = instantiateReactComponent(element, null);
197+
componentInstance.mountComponentAsync(id, transaction, emptyObject, wrappedStream);
198+
wrappedStream.flush();
199+
}, null);
200+
201+
return Promise.resolve(null);
202+
} finally {
203+
ReactServerRenderingTransaction.release(transaction);
204+
// Revert to the DOM batching strategy since these two renderers
205+
// currently share these stateful modules.
206+
ReactUpdates.injection.injectBatchingStrategy(ReactDefaultBatchingStrategy);
207+
}
208+
});
209+
210+
if (usingV1) {
211+
return promise;
212+
} else {
213+
return stream;
156214
}
157215
}
158216

src/renderers/dom/server/__tests__/ReactServerAsyncRendering-test.js

Lines changed: 37 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,8 @@ describe('ReactServerAsyncRendering', function() {
5454
});
5555

5656
ReactServerAsyncRendering.renderToStringStream(
57-
<span>hello world</span>,
58-
stream
59-
);
60-
61-
stream.end();
57+
<span>hello world</span>
58+
).pipe(stream);
6259
});
6360

6461
it('should generate simple markup for self-closing tags', function() {
@@ -69,11 +66,8 @@ describe('ReactServerAsyncRendering', function() {
6966
});
7067

7168
ReactServerAsyncRendering.renderToStringStream(
72-
<img />,
73-
stream
74-
);
75-
76-
stream.end();
69+
<img />
70+
).pipe(stream);
7771
});
7872

7973
it('should generate simple markup for attribute with `>` symbol', function() {
@@ -82,12 +76,9 @@ describe('ReactServerAsyncRendering', function() {
8276
'<img data-attr="&gt;" ' + ID_ATTRIBUTE_NAME + '="[^"]+"/>'
8377
);
8478
});
85-
var response = ReactServerAsyncRendering.renderToStringStream(
86-
<img data-attr=">" />,
87-
stream
88-
);
89-
90-
stream.end();
79+
ReactServerAsyncRendering.renderToStringStream(
80+
<img data-attr=">" />
81+
).pipe(stream);
9182
});
9283

9384
it('should not register event listeners', function() {
@@ -96,10 +87,9 @@ describe('ReactServerAsyncRendering', function() {
9687
var cb = mocks.getMockFunction();
9788

9889
ReactServerAsyncRendering.renderToStringStream(
99-
<span onClick={cb}>hello world</span>,
100-
stream
101-
);
102-
stream.end();
90+
<span onClick={cb}>hello world</span>
91+
).pipe(stream);
92+
10393
expect(EventPluginHub.__getListenerBank()).toEqual({});
10494
});
10595

@@ -124,11 +114,9 @@ describe('ReactServerAsyncRendering', function() {
124114
return <span>My name is {this.props.name}</span>;
125115
},
126116
});
127-
var response = ReactServerAsyncRendering.renderToStringStream(
128-
<Parent />, stream
129-
);
130-
131-
stream.end();
117+
ReactServerAsyncRendering.renderToStringStream(
118+
<Parent />
119+
).pipe(stream);
132120
});
133121

134122
it('should only execute certain lifecycle methods', function() {
@@ -174,11 +162,9 @@ describe('ReactServerAsyncRendering', function() {
174162
},
175163
});
176164

177-
var response = ReactServerAsyncRendering.renderToStringStream(
178-
<TestComponent />, stream
179-
);
180-
181-
stream.end();
165+
ReactServerAsyncRendering.renderToStringStream(
166+
<TestComponent />
167+
).pipe(stream);
182168

183169
expect(lifecycle).toEqual(
184170
['getInitialState', 'componentWillMount', 'render']
@@ -267,9 +253,13 @@ describe('ReactServerAsyncRendering', function() {
267253
});
268254

269255
var hash;
270-
ReactServerAsyncRendering.renderToStringStream(
271-
<TestComponent name="x" />, stream
272-
).then(function(hashValue) {
256+
var renderedStream = ReactServerAsyncRendering.renderToStringStream(
257+
<TestComponent name="x" />
258+
);
259+
260+
renderedStream.pipe(stream, {end:false});
261+
262+
renderedStream.hash.then(function(hashValue) {
273263
hash = hashValue;
274264
stream.end();
275265
})
@@ -306,11 +296,9 @@ describe('ReactServerAsyncRendering', function() {
306296
},
307297
});
308298

309-
var response = ReactServerAsyncRendering.renderToStaticMarkupStream(
310-
<TestComponent />, stream
311-
);
312-
313-
stream.end();
299+
ReactServerAsyncRendering.renderToStaticMarkupStream(
300+
<TestComponent />
301+
).pipe(stream);
314302
});
315303

316304
it('should not put checksum and React ID on text components', function() {
@@ -323,21 +311,19 @@ describe('ReactServerAsyncRendering', function() {
323311
},
324312
});
325313

326-
var response = ReactServerAsyncRendering.renderToStaticMarkupStream(
327-
<TestComponent />, stream
328-
);
329-
330-
stream.end();
314+
ReactServerAsyncRendering.renderToStaticMarkupStream(
315+
<TestComponent />
316+
).pipe(stream);
331317
});
332318

333319
it('should not register event listeners', function() {
334320
var EventPluginHub = require('EventPluginHub');
335321
var cb = mocks.getMockFunction();
336322

337323
ReactServerAsyncRendering.renderToStringStream(
338-
<span onClick={cb}>hello world</span>,
339-
concatStream({encoding: "string"}, function(result) {})
340-
);
324+
<span onClick={cb}>hello world</span>)
325+
.pipe(concatStream({encoding: "string"}, function(result) {}));
326+
341327
expect(EventPluginHub.__getListenerBank()).toEqual({});
342328
});
343329

@@ -380,11 +366,10 @@ describe('ReactServerAsyncRendering', function() {
380366
expect(result).toBe('<span>Component name: TestComponent</span>');
381367
});
382368

383-
var response = ReactServerAsyncRendering.renderToStaticMarkupStream(
384-
<TestComponent />, stream
385-
);
369+
ReactServerAsyncRendering.renderToStaticMarkupStream(
370+
<TestComponent />
371+
).pipe(stream);
386372

387-
stream.end();
388373
expect(lifecycle).toEqual(
389374
['getInitialState', 'componentWillMount', 'render']
390375
);
@@ -429,10 +414,8 @@ describe('ReactServerAsyncRendering', function() {
429414
throw new Error('Browser reconcile transaction should not be used');
430415
};
431416
ReactServerAsyncRendering.renderToStringStream(
432-
<Component />, stream
433-
);
434-
435-
stream.end();
417+
<Component />
418+
).pipe(stream);
436419
});
437420
});
438421
});

0 commit comments

Comments
 (0)