@samitouri / QOS-React / commits / 1b4776f319

In SSR, Store Elements of Composites on the Stack for Warnings (#10187)

In DEV mode this keeps an additional sub-stack within the stack of the server renderer. This substack keeps track of all the elements that we resolved to get to to the next processing frame. This lets us recreate the full composite component stack for warnings. Normally the stack only contains host components. We reset this every time we're going to resolve another sibling.

Sebastian Markbåge committed Jul 19, 2017 at 10:36 UTC 1b4776f31974ff6ad256380deacb4e2f69703750
1 file changed +39 -24
src/renderers/shared/server/ReactPartialRenderer.js
+39 -24
@@ -47,17 +47,7 @@ if (__DEV__) {
47 };
48
49 var describeComponentFrame = require('describeComponentFrame');
50 - var describeStackFrame = function(
51 - frame: {
52 - tag?: string,
53 - children: Array<*>,
54 - childIndex: number,
55 - },
56 - ): string {
57 - var element = frame.children[frame.childIndex - 1];
58 - if (!element) {
59 - return '';
60 - }
50 + var describeStackFrame = function(element): string {
51 var source = element._source;
52 var type = element.type;
53 var name = typeof type === 'string'
@@ -69,11 +59,21 @@ if (__DEV__) {
59
60 var {ReactDebugCurrentFrame} = require('ReactGlobalSharedState');
61 var currentDebugStack = null;
62 + var currentDebugElementStack = null;
63 var setCurrentDebugStack = function(stack) {
64 + currentDebugElementStack = stack[stack.length - 1].debugElementStack;
65 + // We are about to enter a new composite stack, reset the array.
66 + currentDebugElementStack.length = 0;
67 currentDebugStack = stack;
68 ReactDebugCurrentFrame.getCurrentStack = getStackAddendum;
69 };
70 + var pushElementToDebugStack = function(element) {
71 + if (currentDebugElementStack !== null) {
72 + currentDebugElementStack.push(element);
73 + }
74 + };
75 var resetCurrentDebugStack = function() {
76 + currentDebugElementStack = null;
77 currentDebugStack = null;
78 ReactDebugCurrentFrame.getCurrentStack = null;
79 };
@@ -84,7 +84,10 @@ if (__DEV__) {
84 let stack = '';
85 let debugStack = currentDebugStack;
86 for (let i = debugStack.length - 1; i >= 0; i--) {
87 - stack += describeStackFrame(debugStack[i]);
87 + let debugElementStack = debugStack[i].debugElementStack;
88 + for (let ii = debugElementStack.length - 1; ii >= 0; ii--) {
89 + stack += describeStackFrame(debugElementStack[ii]);
90 + }
91 }
92 return stack;
93 };
@@ -306,10 +309,15 @@ function createOpenTagMarkup(
309 function resolve(child, context) {
310 // TODO: We'll need to support Arrays (and strings) after Fiber is rolled out
311 invariant(!Array.isArray(child), 'Did not expect to receive an Array child');
309 - while (React.isValidElement(child) && typeof child.type === 'function') {
312 + while (React.isValidElement(child)) {
313 + if (__DEV__) {
314 + pushElementToDebugStack(child);
315 + }
316 var Component = child.type;
317 + if (typeof Component !== 'function') {
318 + break;
319 + }
320 var publicContext = processContext(Component, context);
312 -
321 var inst;
322 var queue = [];
323 var replace = false;
@@ -407,14 +415,16 @@ function resolve(child, context) {
415
416 class ReactDOMServerRenderer {
417 constructor(element, makeStaticMarkup) {
410 - this.stack = [
411 - {
412 - children: [element],
413 - childIndex: 0,
414 - context: emptyObject,
415 - footer: '',
416 - },
417 - ];
418 + var topFrame = {
419 + children: [element],
420 + childIndex: 0,
421 + context: emptyObject,
422 + footer: '',
423 + };
424 + if (__DEV__) {
425 + topFrame.debugElementStack = [];
426 + }
427 + this.stack = [topFrame];
428 this.exhausted = false;
429 this.currentSelectValue = null;
430 this.previousWasTextNode = false;
@@ -448,6 +458,7 @@ class ReactDOMServerRenderer {
458 }
459 out += this.render(child, frame.context);
460 if (__DEV__) {
461 + // TODO: Handle reentrant server render calls. This doesn't.
462 resetCurrentDebugStack();
463 }
464 }
@@ -747,13 +758,17 @@ class ReactDOMServerRenderer {
758 } else {
759 children = toArray(props.children);
760 }
750 - this.stack.push({
761 + var frame = {
762 tag,
763 children,
764 childIndex: 0,
765 context: context,
766 footer: footer,
756 - });
767 + };
768 + if (__DEV__) {
769 + frame.debugElementStack = [];
770 + }
771 + this.stack.push(frame);
772 return out;
773 }
774 }