Skip to content

Commit e6bfb3b

Browse files
committed
2 parents 7742450 + 7d24c2b commit e6bfb3b

File tree

10 files changed

+2812
-58
lines changed

10 files changed

+2812
-58
lines changed

SSRtest/ModifiedReact.js

Lines changed: 110 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2204,8 +2204,22 @@ var ReactDOMServerRenderer = function () {
22042204
// TODO: type this more strictly:
22052205

22062206

2207-
ReactDOMServerRenderer.prototype.read = function read(bytes, cache) {
2208-
const start = {};
2207+
ReactDOMServerRenderer.prototype.read = function read(bytes, cache) {
2208+
/*
2209+
--- Component caching variables ---
2210+
start: Tracks start index in output string and templatization data for cached components
2211+
saveTemplates: Tracks templatized components so props can be restored in output string
2212+
restoreProps: Restores actual props to a templatized component
2213+
*/
2214+
const start = {};
2215+
let saveTemplates;
2216+
const restoreProps = (template, props, lookup) => {
2217+
return template.replace(/\{\{[0-9]+\}\}/g, match => props[lookup[match]]);
2218+
};
2219+
2220+
/*
2221+
--- Begin React 16 source code with addition of component caching logic ---
2222+
*/
22092223
if (this.exhausted) {
22102224
return null;
22112225
}
@@ -2233,17 +2247,68 @@ var ReactDOMServerRenderer = function () {
22332247
{
22342248
setCurrentDebugStack(this.stack);
22352249
}
2236-
2237-
// IF THE CHILD HAS A CACHEKEY PROPERTY ON IT
2238-
if(child.props && child.props.cache){
2239-
const cacheKey = child.type.name + JSON.stringify(child.props);
2240-
if (!cache.get(cacheKey)){
2241-
start[cacheKey] = out.length;
2242-
out += this.render(child, frame.context, frame.domNamespace);
2250+
2251+
/*
2252+
--- Component caching logic ---
2253+
*/
2254+
if(child.props && child.props.cache) {
2255+
let cacheKey;
2256+
let isTemplate = child.props.templatized ? true : false;
2257+
let lookup;
2258+
let modifiedChild;
2259+
let realProps;
2260+
2261+
if (isTemplate) {
2262+
// Generate templatized version of props to generate appropriate cache key
2263+
let cacheProps = Object.assign({}, child.props);
2264+
let templatizedProps = child.props.templatized;
2265+
lookup = {};
2266+
2267+
if (typeof templatizedProps === 'string') templatizedProps = [templatizedProps];
2268+
2269+
// Generate template placeholders and lookup object for referencing prop names from placeholders
2270+
templatizedProps.forEach((templatizedProp, index) => {
2271+
const placeholder = `{{${index}}}`;
2272+
cacheProps[templatizedProp] = placeholder;
2273+
lookup[placeholder] = templatizedProp; // Move down to next if statement? (Extra work/space if not generating template)
2274+
});
2275+
2276+
cacheKey = child.type.name + JSON.stringify(cacheProps);
2277+
2278+
// Generate modified child with placeholder props to render template
2279+
if (!start[cacheKey]) {
2280+
modifiedChild = Object.assign({}, child);
2281+
modifiedChild.props = cacheProps;
2282+
realProps = child.props;
2283+
}
22432284
} else {
2244-
out += cache.get(cacheKey);
2285+
// Generate cache key for non-templatized component from its name and props
2286+
cacheKey = child.type.name + JSON.stringify(child.props);
22452287
}
2246-
} else {
2288+
2289+
if (!cache.get(cacheKey)) { // Component not found in cache
2290+
let r;
2291+
2292+
// If templatized component and template hasn't been generated, render a template
2293+
if (!start[cacheKey] && isTemplate) {
2294+
r = this.render(modifiedChild, frame.context, frame.domNamespace);
2295+
start[cacheKey] = { startIndex: out.length, realProps, lookup };
2296+
}
2297+
// Otherwise, render with actual props
2298+
else r = this.render(child, frame.context, frame.domNamespace);
2299+
2300+
// For simple (non-template) caching, save start index of component in output string
2301+
if (!isTemplate) start[cacheKey] = out.length;
2302+
2303+
out += r;
2304+
} else { // Component found in cache
2305+
let r = cache.get(cacheKey);
2306+
let restoredTemplate;
2307+
if (isTemplate) restoredTemplate = restoreProps(r, realProps, lookup);
2308+
out += restoredTemplate ? restoredTemplate : r;
2309+
}
2310+
} else {
2311+
// Normal rendering for non-cached components
22472312
out += this.render(child, frame.context, frame.domNamespace);
22482313
}
22492314
{
@@ -2252,25 +2317,51 @@ var ReactDOMServerRenderer = function () {
22522317
}
22532318
}
22542319

2320+
/*
2321+
--- After initial render of cacheable components, recover from output string and store in cache ---
2322+
*/
22552323
for (let component in start) {
22562324
let tagStack = [];
22572325
let tagStart;
22582326
let tagEnd;
2327+
let componentStart = (typeof start[component] === 'object') ? start[component].startIndex : start[component];
22592328

22602329
do {
2261-
if (!tagStart) tagStart = start[component];
2262-
else tagStart = (out[tagEnd] === '<') ? tagEnd : out.indexOf('<', tagEnd)
2330+
if (!tagStart) tagStart = componentStart;
2331+
else tagStart = (out[tagEnd] === '<') ? tagEnd : out.indexOf('<', tagEnd);
22632332
tagEnd = out.indexOf('>', tagStart) + 1;
2264-
// Skip stack logic for void/self-closing elements
2265-
if (out[tagEnd - 2] !== '/') {
2333+
// Skip stack logic for void/self-closing elements and HTML comments
2334+
// Note: Does not account for tags inside HTML comments
2335+
if (out[tagEnd - 2] !== '/' && out[tagStart + 1] !== '!') {
22662336
// Push opening tags onto stack; pop closing tags off of stack
22672337
if (out[tagStart + 1] !== '/') tagStack.push(out.slice(tagStart, tagEnd));
22682338
else tagStack.pop();
22692339
}
22702340
} while (tagStack.length !== 0);
2271-
2272-
// cache component by slicing 'out'
2273-
cache.set(component, out.slice(start[component], tagEnd));
2341+
// Cache component by slicing 'out'
2342+
const cachedComponent = out.slice(componentStart, tagEnd);
2343+
if (typeof start[component] === 'object') {
2344+
if (!saveTemplates) saveTemplates = [];
2345+
saveTemplates.push(start[component]);
2346+
start[component].endIndex = tagEnd;
2347+
}
2348+
cache.set(component, cachedComponent);
2349+
}
2350+
2351+
// After caching all cacheable components, restore props to templates
2352+
if (saveTemplates) {
2353+
let outCopy = out;
2354+
out = '';
2355+
let bookmark = 0;
2356+
saveTemplates.sort((a, b) => a.startIndex - b.startIndex);
2357+
// Rebuild output string with actual props
2358+
saveTemplates.forEach(savedTemplate => {
2359+
out += outCopy.substring(bookmark, savedTemplate.startIndex)
2360+
bookmark = savedTemplate.endIndex;
2361+
out += restoreProps(outCopy.slice(savedTemplate.startIndex, savedTemplate.endIndex),
2362+
savedTemplate.realProps, savedTemplate.lookup);
2363+
});
2364+
out += outCopy.substring(bookmark, outCopy.length);
22742365
}
22752366
return out;
22762367
};
@@ -2647,4 +2738,4 @@ var server_node = ReactDOMServer['default'] ? ReactDOMServer['default'] : ReactD
26472738

26482739
module.exports = server_node;
26492740
})();
2650-
}
2741+
}

0 commit comments

Comments
 (0)