Skip to content

Commit 67a216c

Browse files
authored
Merge pull request #29 from rookLab/stream_async
Stream async
2 parents 24439f9 + 28179a9 commit 67a216c

File tree

4 files changed

+73
-39
lines changed

4 files changed

+73
-39
lines changed

SSRtest/ModifiedReact.js

Lines changed: 55 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import { lstat } from 'fs';
2+
import { Transform } from "stream";
3+
import { create } from "domain";
24

35
/** @license React v16.2.0
46
* react-dom-server.node.development.js
@@ -2387,7 +2389,6 @@ var ReactDOMServerRenderer = function () {
23872389
out += outCopy.substring(bookmark, outCopy.length);
23882390
}
23892391
} else {
2390-
// console.log(out.length, streamingStart);
23912392
streamingStart.sliceStartCount += out.length;
23922393
}
23932394
return out;
@@ -2650,7 +2651,7 @@ var ReactDOMServerRenderer = function () {
26502651
async function renderToString(element, cache, memLife=0) {
26512652
// If and only if using memcached, pass the lifetime of your cache entry (in seconds) into 'memLife'.
26522653
var renderer = new ReactDOMServerRenderer(element, false);
2653-
var markup = await renderer.read(Infinity, cache, memLife);
2654+
var markup = await renderer.read(Infinity, cache, false, null, memLife);
26542655
return markup;
26552656
}
26562657

@@ -2659,9 +2660,9 @@ async function renderToString(element, cache, memLife=0) {
26592660
* such as data-react-id that React uses internally.
26602661
* See https://reactjs.org/docs/react-dom-server.html#rendertostaticmarkup
26612662
*/
2662-
function renderToStaticMarkup(element, cache) {
2663+
function renderToStaticMarkup(element, cache, memLife=0) {
26632664
var renderer = new ReactDOMServerRenderer(element, true);
2664-
var markup = renderer.read(Infinity, cache);
2665+
var markup = renderer.read(Infinity, cache, false, null, memLife);
26652666
return markup;
26662667
}
26672668

@@ -2698,15 +2699,6 @@ var ReactMarkupReadableStream = function (_Readable) {
26982699
this.streamingStart,
26992700
this.memLife);
27002701
this.push(readOutput);
2701-
// this.push(
2702-
// this.partialRenderer.read(
2703-
// size,
2704-
// this.cache,
2705-
// true,
2706-
// this.streamingStart,
2707-
// this.memLife
2708-
// )
2709-
// );
27102702
} catch (err) {
27112703
this.emit('error', err);
27122704
}
@@ -2736,10 +2728,57 @@ function renderToNodeStream(element, cache, streamingStart, memLife=0) {
27362728
* such as data-react-id that React uses internally.
27372729
* See https://reactjs.org/docs/react-dom-stream.html#rendertostaticnodestream
27382730
*/
2739-
function renderToStaticNodeStream(element) {
2740-
return new ReactMarkupReadableStream(element, true);
2731+
function renderToStaticNodeStream(element, cache, streamingStart, memLife=0) {
2732+
return new ReactMarkupReadableStream(element, true, cache, streamingStart, memLife);
27412733
}
27422734

2735+
function createCacheStream(cache, streamingStart, memLife=0) {
2736+
const bufferedChunks = [];
2737+
return new Transform({
2738+
// transform() is called with each chunk of data
2739+
transform(data, enc, cb) {
2740+
// We store the chunk of data (which is a Buffer) in memory
2741+
bufferedChunks.push(data);
2742+
// Then pass the data unchanged onwards to the next stream
2743+
cb(null, data);
2744+
},
2745+
2746+
// flush() is called when everything is done
2747+
flush(cb) {
2748+
// We concatenate all the buffered chunks of HTML to get the full HTML, then cache it at "key"
2749+
let html = bufferedChunks.join("");
2750+
delete streamingStart.sliceStartCount;
2751+
2752+
for (let component in streamingStart) {
2753+
let tagStack = [];
2754+
let tagStart;
2755+
let tagEnd;
2756+
2757+
do {
2758+
if (!tagStart) tagStart = streamingStart[component];
2759+
else tagStart = (html[tagEnd] === '<') ? tagEnd : html.indexOf('<', tagEnd);
2760+
tagEnd = html.indexOf('>', tagStart) + 1;
2761+
// Skip stack logic for void/self-closing elements and HTML comments
2762+
if (html[tagEnd - 2] !== '/' && html[tagStart + 1] !== '!') {
2763+
// Push opening tags onto stack; pop closing tags off of stack
2764+
if (html[tagStart + 1] !== '/') tagStack.push(html.slice(tagStart, tagEnd));
2765+
else tagStack.pop();
2766+
}
2767+
} while (tagStack.length !== 0);
2768+
// cache component by slicing 'html'
2769+
if (memLife) {
2770+
cache.set(component, html.slice(streamingStart[component], tagEnd), memLife, (err) => {
2771+
if(err) console.log(err)
2772+
});
2773+
} else {
2774+
cache.set(component, html.slice(streamingStart[component], tagEnd));
2775+
}
2776+
}
2777+
cb();
2778+
}
2779+
});
2780+
};
2781+
27432782
class ComponentCache {
27442783
constructor(config = {}) {
27452784

@@ -2775,6 +2814,7 @@ var ReactDOMServerNode = {
27752814
renderToNodeStream: renderToNodeStream,
27762815
renderToStaticNodeStream: renderToStaticNodeStream,
27772816
ComponentCache: ComponentCache,
2817+
createCacheStream: createCacheStream,
27782818
version: ReactVersion
27792819
};
27802820

SSRtest/src/server/cacheStream.js

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { Transform } from "stream";
22
import { create } from "domain";
33
import { lstat } from "fs";
44

5-
const createCacheStream = (cache, streamingStart) => {
5+
const createCacheStream = (cache, streamingStart, memLife=0) => {
66
const bufferedChunks = [];
77
return new Transform({
88
// transform() is called with each chunk of data
@@ -15,14 +15,7 @@ const createCacheStream = (cache, streamingStart) => {
1515

1616
// flush() is called when everything is done
1717
flush(cb) {
18-
// We concatenate all the buffered chunks of HTML to get the full HTML
19-
// then cache it at "key"
20-
21-
// console.log(cache);
22-
// console.log(bufferedChunks.join());
23-
// cache.set(key, Buffer.concat(bufferedChunks));
24-
// console.log("final", streamingStart.finalSliceStart);
25-
//joinedChunks = bufferedChunks.join("");
18+
// We concatenate all the buffered chunks of HTML to get the full HTML, then cache it at "key"
2619
let html = bufferedChunks.join("");
2720
delete streamingStart.sliceStartCount;
2821

@@ -36,18 +29,21 @@ const createCacheStream = (cache, streamingStart) => {
3629
else tagStart = (html[tagEnd] === '<') ? tagEnd : html.indexOf('<', tagEnd);
3730
tagEnd = html.indexOf('>', tagStart) + 1;
3831
// Skip stack logic for void/self-closing elements and HTML comments
39-
// Note: Does not account for tags inside HTML comments
4032
if (html[tagEnd - 2] !== '/' && html[tagStart + 1] !== '!') {
4133
// Push opening tags onto stack; pop closing tags off of stack
4234
if (html[tagStart + 1] !== '/') tagStack.push(html.slice(tagStart, tagEnd));
4335
else tagStack.pop();
4436
}
4537
} while (tagStack.length !== 0);
46-
//console.log(html.slice(streamingStart[component], tagEnd));
4738
// cache component by slicing 'html'
48-
cache.set(component, html.slice(streamingStart[component], tagEnd));
39+
if (memLife) {
40+
cache.set(component, html.slice(streamingStart[component], tagEnd), memLife, (err) => {
41+
if(err) console.log(err)
42+
});
43+
} else {
44+
cache.set(component, html.slice(streamingStart[component], tagEnd));
45+
}
4946
}
50-
//console.log("to be saved:", bufferedChunks.join(""));
5147
cb();
5248
}
5349
});

SSRtest/src/server/index.js

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,12 @@ import flushChunks from 'webpack-flush-chunks';
77

88
import App from '../shared/App';
99

10-
import createCacheStream from "./cacheStream";
1110
// can pass in max-size, otherwise defaults to 1 million
12-
// const cache = new ReactCC.ComponentCache();
11+
const cache = new ReactCC.ComponentCache();
1312
// import redis from 'redis';
1413
// const cache = redis.createClient();
15-
import memcached from 'memcached';
16-
const cache = new memcached('localhost:11211');
14+
// import memcached from 'memcached';
15+
// const cache = new memcached('localhost:11211');
1716

1817
// Force NodeStream
1918

@@ -29,24 +28,23 @@ const streamingStart = {
2928
* @param clientStats Parameter passed by hot server middleware
3029
*/
3130
export default ({ clientStats }) => async (req, res) => {
32-
console.log(cache);
3331
// Need To Come back To If Statement
34-
if(true){
35-
const cacheStream = createCacheStream(cache, streamingStart);
32+
if(false){
33+
const cacheStream = ReactCC.createCacheStream(cache, streamingStart);
3634
cacheStream.pipe(res);
3735
cacheStream.write(htmlStart);
3836

39-
const stream = ReactCC.renderToNodeStream(<App />, cache, streamingStart, 30);
37+
const stream = ReactCC.renderToNodeStream(<App />, cache, streamingStart);
4038
stream.pipe(cacheStream, { end: false });
4139
stream.on("end", () => {
4240
cacheStream.end(htmlEnd);
4341
});
4442
}
45-
else{
43+
else if (true){
4644
const app = <App />;
4745
const start_cached = process.hrtime();
4846

49-
const appString = await ReactCC.renderToString(app, cache);
47+
const appString = await ReactCC.renderToString(app, cache, 30);
5048
const end_cached = process.hrtime(start_cached);
5149
console.info(
5250
"Cached render time: %ds %dms",

SSRtest/src/shared/List.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export default class List extends Component {
1212
let bunchOfProducts = [];
1313
const templatizedProps = ["name", "description", "price"];
1414
for (let i=0; i<100; i++) {
15-
bunchOfProducts.push(<ProductInfo key={i} name={`Thing ${i}`} description="This product is awesome!" price={i * 10} nonTemplatized="THIS TEXT SHOULD NEVER CHANGE" cache />);
15+
bunchOfProducts.push(<ProductInfo key={i} name={`Thing ${i}`} description="This product is awesome!" price={i * 10} nonTemplatized="THIS TEXT SHOULD NEVER CHANGE" cache templatized={templatizedProps}/>);
1616
}
1717
return (
1818
<div>

0 commit comments

Comments
 (0)