@@ -255,6 +255,7 @@ export type Response = {
255255 _debugRootTask?: null | ConsoleTask, // DEV-only
256256 _debugFindSourceMapURL?: void | FindSourceMapURLCallback, // DEV-only
257257 _replayConsole: boolean, // DEV-only
258+ _rootEnvironmentName: string, // DEV-only, the requested environment name.
258259};
259260
260261function readChunk<T>(chunk: SomeChunk<T>): T {
@@ -692,7 +693,7 @@ function createElement(
692693 writable: true,
693694 value: null,
694695 });
695- let env = '' ;
696+ let env = response._rootEnvironmentName ;
696697 if (enableOwnerStacks) {
697698 if (owner !== null && owner.env != null) {
698699 // Interestingly we don't actually have the environment name of where
@@ -737,7 +738,7 @@ function createElement(
737738 // This owner should ideally have already been initialized to avoid getting
738739 // user stack frames on the stack.
739740 const ownerTask =
740- owner === null ? null : initializeFakeTask ( response , owner ) ;
741+ owner === null ? null : initializeFakeTask(response, owner, env );
741742 if (ownerTask === null) {
742743 const rootTask = response._debugRootTask;
743744 if (rootTask != null) {
@@ -1355,6 +1356,7 @@ function ResponseInstance(
13551356 temporaryReferences: void | TemporaryReferenceSet,
13561357 findSourceMapURL: void | FindSourceMapURLCallback,
13571358 replayConsole: boolean,
1359+ environmentName: void | string,
13581360) {
13591361 const chunks: Map<number, SomeChunk<any>> = new Map();
13601362 this._bundlerConfig = bundlerConfig;
@@ -1371,17 +1373,21 @@ function ResponseInstance(
13711373 this._rowLength = 0;
13721374 this._buffer = [];
13731375 this._tempRefs = temporaryReferences;
1374- if ( supportsCreateTask ) {
1375- // Any stacks that appear on the server need to be rooted somehow on the client
1376- // so we create a root Task for this response which will be the root owner for any
1377- // elements created by the server. We use the "use server" string to indicate that
1378- // this is where we enter the server from the client.
1379- // TODO: Make this string configurable.
1380- this . _debugRootTask = ( console : any ) . createTask ( '"use server"' ) ;
1381- }
13821376 if (__DEV__) {
1377+ const rootEnv = environmentName === undefined ? 'Server' : environmentName;
1378+ if (supportsCreateTask) {
1379+ // Any stacks that appear on the server need to be rooted somehow on the client
1380+ // so we create a root Task for this response which will be the root owner for any
1381+ // elements created by the server. We use the "use server" string to indicate that
1382+ // this is where we enter the server from the client.
1383+ // TODO: Make this string configurable.
1384+ this._debugRootTask = (console: any).createTask(
1385+ '"use ' + rootEnv.toLowerCase() + '"',
1386+ );
1387+ }
13831388 this._debugFindSourceMapURL = findSourceMapURL;
13841389 this._replayConsole = replayConsole;
1390+ this._rootEnvironmentName = rootEnv;
13851391 }
13861392 // Don't inline this call because it causes closure to outline the call above.
13871393 this._fromJSON = createFromJSONCallback(this);
@@ -1396,6 +1402,7 @@ export function createResponse(
13961402 temporaryReferences: void | TemporaryReferenceSet,
13971403 findSourceMapURL: void | FindSourceMapURLCallback,
13981404 replayConsole: boolean,
1405+ environmentName: void | string,
13991406): Response {
14001407 // $FlowFixMe[invalid-constructor]: the shapes are exact here but Flow doesn't like constructors
14011408 return new ResponseInstance(
@@ -1407,6 +1414,7 @@ export function createResponse(
14071414 temporaryReferences,
14081415 findSourceMapURL,
14091416 replayConsole,
1417+ environmentName,
14101418 );
14111419}
14121420
@@ -1864,7 +1872,7 @@ function resolveErrorDev(
18641872 'An error occurred in the Server Components render but no message was provided',
18651873 ),
18661874 );
1867- const rootTask = response . _debugRootTask ;
1875+ const rootTask = getRootTask( response, env) ;
18681876 if (rootTask != null) {
18691877 error = rootTask.run(callStack);
18701878 } else {
@@ -2098,52 +2106,99 @@ function buildFakeCallStack<T>(
20982106 return callStack;
20992107}
21002108
2109+ function getRootTask(
2110+ response: Response,
2111+ childEnvironmentName: string,
2112+ ): null | ConsoleTask {
2113+ const rootTask = response._debugRootTask;
2114+ if (!rootTask) {
2115+ return null;
2116+ }
2117+ if (response._rootEnvironmentName !== childEnvironmentName) {
2118+ // If the root most owner component is itself in a different environment than the requested
2119+ // environment then we create an extra task to indicate that we're transitioning into it.
2120+ // Like if one environment just requests another environment.
2121+ const createTaskFn = (console: any).createTask.bind(
2122+ console,
2123+ '"use ' + childEnvironmentName.toLowerCase() + '"',
2124+ );
2125+ return rootTask.run(createTaskFn);
2126+ }
2127+ return rootTask;
2128+ }
2129+
21012130function initializeFakeTask(
21022131 response: Response,
21032132 debugInfo: ReactComponentInfo | ReactAsyncInfo,
2133+ childEnvironmentName: string,
21042134): null | ConsoleTask {
21052135 if (!supportsCreateTask) {
21062136 return null;
21072137 }
21082138 const componentInfo: ReactComponentInfo = (debugInfo: any); // Refined
2109- const cachedEntry = componentInfo.debugTask;
2110- if (cachedEntry !== undefined) {
2111- return cachedEntry ;
2112- }
2113-
21142139 if (debugInfo.stack == null) {
21152140 // If this is an error, we should've really already initialized the task.
21162141 // If it's null, we can't initialize a task.
21172142 return null;
21182143 }
2119-
21202144 const stack = debugInfo.stack;
2121- const env = componentInfo.env == null ? '' : componentInfo.env;
2122- const ownerTask =
2123- componentInfo.owner == null
2124- ? null
2125- : initializeFakeTask(response, componentInfo.owner);
2126-
2127- const createTaskFn = (console: any).createTask.bind(
2128- console,
2129- getServerComponentTaskName(componentInfo),
2130- );
2131- const callStack = buildFakeCallStack(response, stack, env, createTaskFn);
2145+ const env: string =
2146+ componentInfo.env == null
2147+ ? response._rootEnvironmentName
2148+ : componentInfo.env;
2149+ if (env !== childEnvironmentName) {
2150+ // This is the boundary between two environments so we'll annotate the task name.
2151+ // That is unusual so we don't cache it.
2152+ const ownerTask =
2153+ componentInfo.owner == null
2154+ ? null
2155+ : initializeFakeTask(response, componentInfo.owner, env);
2156+ return buildFakeTask(
2157+ response,
2158+ ownerTask,
2159+ stack,
2160+ '"use ' + childEnvironmentName.toLowerCase() + '"',
2161+ env,
2162+ );
2163+ } else {
2164+ const cachedEntry = componentInfo.debugTask;
2165+ if (cachedEntry !== undefined) {
2166+ return cachedEntry;
2167+ }
2168+ const ownerTask =
2169+ componentInfo.owner == null
2170+ ? null
2171+ : initializeFakeTask(response, componentInfo.owner, env);
2172+ // $FlowFixMe[cannot-write]: We consider this part of initialization.
2173+ return (componentInfo.debugTask = buildFakeTask(
2174+ response,
2175+ ownerTask,
2176+ stack,
2177+ getServerComponentTaskName(componentInfo),
2178+ env,
2179+ ));
2180+ }
2181+ }
21322182
2133- let componentTask;
2183+ function buildFakeTask(
2184+ response: Response,
2185+ ownerTask: null | ConsoleTask,
2186+ stack: ReactStackTrace,
2187+ taskName: string,
2188+ env: string,
2189+ ): ConsoleTask {
2190+ const createTaskFn = (console: any).createTask.bind(console, taskName);
2191+ const callStack = buildFakeCallStack(response, stack, env, createTaskFn);
21342192 if (ownerTask === null) {
2135- const rootTask = response . _debugRootTask ;
2193+ const rootTask = getRootTask( response, env) ;
21362194 if (rootTask != null) {
2137- componentTask = rootTask . run ( callStack ) ;
2195+ return rootTask.run(callStack);
21382196 } else {
2139- componentTask = callStack ( ) ;
2197+ return callStack();
21402198 }
21412199 } else {
2142- componentTask = ownerTask . run ( callStack ) ;
2200+ return ownerTask.run(callStack);
21432201 }
2144- // $FlowFixMe[cannot-write]: We consider this part of initialization.
2145- componentInfo.debugTask = componentTask;
2146- return componentTask;
21472202}
21482203
21492204const createFakeJSXCallStack = {
@@ -2216,7 +2271,9 @@ function resolveDebugInfo(
22162271 // We eagerly initialize the fake task because this resolving happens outside any
22172272 // render phase so we're not inside a user space stack at this point. If we waited
22182273 // to initialize it when we need it, we might be inside user code.
2219- initializeFakeTask ( response , debugInfo ) ;
2274+ const env =
2275+ debugInfo.env === undefined ? response._rootEnvironmentName : debugInfo.env;
2276+ initializeFakeTask(response, debugInfo, env);
22202277 initializeFakeStack(response, debugInfo);
22212278
22222279 const chunk = getChunk(response, id);
@@ -2266,7 +2323,7 @@ function resolveConsoleEntry(
22662323 printToConsole.bind(null, methodName, args, env),
22672324 );
22682325 if (owner != null) {
2269- const task = initializeFakeTask ( response , owner ) ;
2326+ const task = initializeFakeTask(response, owner, env );
22702327 initializeFakeStack(response, owner);
22712328 if (task !== null) {
22722329 task.run(callStack);
@@ -2275,7 +2332,7 @@ function resolveConsoleEntry(
22752332 // TODO: Set the current owner so that captureOwnerStack() adds the component
22762333 // stack during the replay - if needed.
22772334 }
2278- const rootTask = response . _debugRootTask ;
2335+ const rootTask = getRootTask( response, env) ;
22792336 if (rootTask != null) {
22802337 rootTask.run(callStack);
22812338 return;
0 commit comments