Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Flight] Let environmentName vary over time by making it a function of string #29867

Merged
merged 3 commits into from
Jun 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions packages/react-client/src/__tests__/ReactFlight-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2565,6 +2565,50 @@ describe('ReactFlight', () => {
);
});

it('can change the environment name inside a component', async () => {
let env = 'A';
function Component(props) {
env = 'B';
return <div>hi</div>;
}

const transport = ReactNoopFlightServer.render(
{
greeting: <Component />,
},
{
environmentName() {
return env;
},
},
);

await act(async () => {
const rootModel = await ReactNoopFlightClient.read(transport);
const greeting = rootModel.greeting;
expect(getDebugInfo(greeting)).toEqual(
__DEV__
? [
{
name: 'Component',
env: 'A',
owner: null,
stack: gate(flag => flag.enableOwnerStacks)
? ' in Object.<anonymous> (at **)'
: undefined,
},
{
env: 'B',
},
]
: undefined,
);
ReactNoop.render(greeting);
});

expect(ReactNoop).toMatchRenderedOutput(<div>hi</div>);
});

// @gate enableServerComponentLogs && __DEV__
it('replays logs, but not onError logs', async () => {
function foo() {
Expand Down
2 changes: 1 addition & 1 deletion packages/react-noop-renderer/src/ReactNoopFlightServer.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ const ReactNoopFlightServer = ReactFlightServer({
});

type Options = {
environmentName?: string,
environmentName?: string | (() => string),
identifierPrefix?: string,
onError?: (error: mixed) => void,
onPostpone?: (reason: string) => void,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ function createCancelHandler(request: Request, reason: string) {
}

type Options = {
environmentName?: string,
environmentName?: string | (() => string),
onError?: (error: mixed) => void,
onPostpone?: (reason: string) => void,
identifierPrefix?: string,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export {createTemporaryReferenceSet} from 'react-server/src/ReactFlightServerTem
export type {TemporaryReferenceSet};

type Options = {
environmentName?: string,
environmentName?: string | (() => string),
identifierPrefix?: string,
signal?: AbortSignal,
temporaryReferences?: TemporaryReferenceSet,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export {createTemporaryReferenceSet} from 'react-server/src/ReactFlightServerTem
export type {TemporaryReferenceSet};

type Options = {
environmentName?: string,
environmentName?: string | (() => string),
identifierPrefix?: string,
signal?: AbortSignal,
temporaryReferences?: TemporaryReferenceSet,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ function createCancelHandler(request: Request, reason: string) {
}

type Options = {
environmentName?: string,
environmentName?: string | (() => string),
onError?: (error: mixed) => void,
onPostpone?: (reason: string) => void,
identifierPrefix?: string,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export {createTemporaryReferenceSet} from 'react-server/src/ReactFlightServerTem
export type {TemporaryReferenceSet};

type Options = {
environmentName?: string,
environmentName?: string | (() => string),
identifierPrefix?: string,
signal?: AbortSignal,
temporaryReferences?: TemporaryReferenceSet,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export {createTemporaryReferenceSet} from 'react-server/src/ReactFlightServerTem
export type {TemporaryReferenceSet};

type Options = {
environmentName?: string,
environmentName?: string | (() => string),
identifierPrefix?: string,
signal?: AbortSignal,
temporaryReferences?: TemporaryReferenceSet,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ function createCancelHandler(request: Request, reason: string) {
}

type Options = {
environmentName?: string,
environmentName?: string | (() => string),
onError?: (error: mixed) => void,
onPostpone?: (reason: string) => void,
identifierPrefix?: string,
Expand Down
50 changes: 40 additions & 10 deletions packages/react-server/src/ReactFlightServer.js
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,7 @@ type Task = {
keyPath: null | string, // parent server component keys
implicitSlot: boolean, // true if the root server component of this sequence had a null key
thenableState: ThenableState | null,
environmentName: string, // DEV-only. Used to track if the environment for this task changed.
};

interface Reference {}
Expand Down Expand Up @@ -425,7 +426,7 @@ export type Request = {
onError: (error: mixed) => ?string,
onPostpone: (reason: string) => void,
// DEV-only
environmentName: string,
environmentName: () => string,
didWarnForKey: null | WeakSet<ReactComponentInfo>,
};

Expand Down Expand Up @@ -481,7 +482,7 @@ function RequestInstance(
onError: void | ((error: mixed) => ?string),
identifierPrefix?: string,
onPostpone: void | ((reason: string) => void),
environmentName: void | string,
environmentName: void | string | (() => string),
temporaryReferences: void | TemporaryReferenceSet,
) {
if (
Expand Down Expand Up @@ -531,7 +532,11 @@ function RequestInstance(

if (__DEV__) {
this.environmentName =
environmentName === undefined ? 'Server' : environmentName;
environmentName === undefined
? () => 'Server'
: typeof environmentName !== 'function'
? () => environmentName
: environmentName;
this.didWarnForKey = null;
}
const rootTask = createTask(this, model, null, false, abortSet);
Expand All @@ -544,7 +549,7 @@ export function createRequest(
onError: void | ((error: mixed) => ?string),
identifierPrefix?: string,
onPostpone: void | ((reason: string) => void),
environmentName: void | string,
environmentName: void | string | (() => string),
temporaryReferences: void | TemporaryReferenceSet,
): Request {
// $FlowFixMe[invalid-constructor]: the shapes are exact here but Flow doesn't like constructors
Expand Down Expand Up @@ -1049,14 +1054,14 @@ function renderFunctionComponent<Props>(
componentDebugInfo = (prevThenableState: any)._componentDebugInfo;
} else {
// This is a new component in the same task so we can emit more debug info.
const componentDebugID = debugID;
const componentName =
(Component: any).displayName || Component.name || '';
const componentEnv = request.environmentName();
request.pendingChunks++;

const componentDebugID = debugID;
componentDebugInfo = ({
name: componentName,
env: request.environmentName,
env: componentEnv,
owner: owner,
}: ReactComponentInfo);
if (enableOwnerStacks) {
Expand All @@ -1069,6 +1074,9 @@ function renderFunctionComponent<Props>(
outlineModel(request, componentDebugInfo);
emitDebugChunk(request, componentDebugID, componentDebugInfo);

// We've emitted the latest environment for this task so we track that.
task.environmentName = componentEnv;

if (enableOwnerStacks) {
warnForMissingKey(request, key, validated, componentDebugInfo);
}
Expand Down Expand Up @@ -1644,7 +1652,7 @@ function createTask(
request.writtenObjects.set(model, serializeByValueID(id));
}
}
const task: Task = {
const task: Task = (({
id,
status: PENDING,
model,
Expand Down Expand Up @@ -1697,7 +1705,10 @@ function createTask(
return renderModel(request, task, parent, parentPropertyName, value);
},
thenableState: null,
};
}: Omit<Task, 'environmentName'>): any);
if (__DEV__) {
task.environmentName = request.environmentName();
}
abortSet.add(task);
return task;
}
Expand Down Expand Up @@ -3252,7 +3263,7 @@ function emitConsoleChunk(
}

// TODO: Don't double badge if this log came from another Flight Client.
const env = request.environmentName;
const env = request.environmentName();
const payload = [methodName, stackTrace, owner, env];
// $FlowFixMe[method-unbinding]
payload.push.apply(payload, args);
Expand Down Expand Up @@ -3420,6 +3431,15 @@ function retryTask(request: Request, task: Task): void {
// any future references.
request.writtenObjects.set(resolvedModel, serializeByValueID(task.id));

if (__DEV__) {
const currentEnv = request.environmentName();
if (currentEnv !== task.environmentName) {
// The environment changed since we last emitted any debug information for this
// task. We emit an entry that just includes the environment name change.
emitDebugChunk(request, task.id, {env: currentEnv});
}
}

// Object might contain unresolved values like additional elements.
// This is simulating what the JSON loop would do if this was part of it.
emitChunk(request, task, resolvedModel);
Expand All @@ -3428,6 +3448,16 @@ function retryTask(request: Request, task: Task): void {
// We don't need to escape it again so it's not passed the toJSON replacer.
// $FlowFixMe[incompatible-type] stringify can return null for undefined but we never do
const json: string = stringify(resolvedModel);

if (__DEV__) {
const currentEnv = request.environmentName();
if (currentEnv !== task.environmentName) {
// The environment changed since we last emitted any debug information for this
// task. We emit an entry that just includes the environment name change.
emitDebugChunk(request, task.id, {env: currentEnv});
}
}

emitModelChunk(request, task.id, json);
}

Expand Down