Skip to content

Commit 0024710

Browse files
committed
Update on "[compiler] Option to only compile component syntax"
Summary: Projects which have heavily adopted Flow component syntax may wish to enable the compiler only for components and hooks that use the syntax, rather than trying to guess which functions are components and hooks. This provides that option. [ghstack-poisoned]
2 parents 12998f4 + a5237cd commit 0024710

File tree

12 files changed

+274
-161
lines changed

12 files changed

+274
-161
lines changed

compiler/.vscode/settings.json

Lines changed: 0 additions & 8 deletions
This file was deleted.

packages/react-client/src/ReactFlightClient.js

Lines changed: 41 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1136,46 +1136,65 @@ function missingCall() {
11361136
);
11371137
}
11381138

1139-
export function createResponse(
1139+
function ResponseInstance(
1140+
this: $FlowFixMe,
11401141
bundlerConfig: SSRModuleMap,
11411142
moduleLoading: ModuleLoading,
11421143
callServer: void | CallServerCallback,
11431144
encodeFormAction: void | EncodeFormActionCallback,
11441145
nonce: void | string,
11451146
temporaryReferences: void | TemporaryReferenceSet,
11461147
findSourceMapURL: void | FindSourceMapURLCallback,
1147-
): Response {
1148+
) {
11481149
const chunks: Map<number, SomeChunk<any>> = new Map();
1149-
const response: Response = {
1150-
_bundlerConfig: bundlerConfig,
1151-
_moduleLoading: moduleLoading,
1152-
_callServer: callServer !== undefined ? callServer : missingCall,
1153-
_encodeFormAction: encodeFormAction,
1154-
_nonce: nonce,
1155-
_chunks: chunks,
1156-
_stringDecoder: createStringDecoder(),
1157-
_fromJSON: (null: any),
1158-
_rowState: 0,
1159-
_rowID: 0,
1160-
_rowTag: 0,
1161-
_rowLength: 0,
1162-
_buffer: [],
1163-
_tempRefs: temporaryReferences,
1164-
};
1150+
this._bundlerConfig = bundlerConfig;
1151+
this._moduleLoading = moduleLoading;
1152+
this._callServer = callServer !== undefined ? callServer : missingCall;
1153+
this._encodeFormAction = encodeFormAction;
1154+
this._nonce = nonce;
1155+
this._chunks = chunks;
1156+
this._stringDecoder = createStringDecoder();
1157+
this._fromJSON = (null: any);
1158+
this._rowState = 0;
1159+
this._rowID = 0;
1160+
this._rowTag = 0;
1161+
this._rowLength = 0;
1162+
this._buffer = [];
1163+
this._tempRefs = temporaryReferences;
11651164
if (supportsCreateTask) {
11661165
// Any stacks that appear on the server need to be rooted somehow on the client
11671166
// so we create a root Task for this response which will be the root owner for any
11681167
// elements created by the server. We use the "use server" string to indicate that
11691168
// this is where we enter the server from the client.
11701169
// TODO: Make this string configurable.
1171-
response._debugRootTask = (console: any).createTask('"use server"');
1170+
this._debugRootTask = (console: any).createTask('"use server"');
11721171
}
11731172
if (__DEV__) {
1174-
response._debugFindSourceMapURL = findSourceMapURL;
1173+
this._debugFindSourceMapURL = findSourceMapURL;
11751174
}
11761175
// Don't inline this call because it causes closure to outline the call above.
1177-
response._fromJSON = createFromJSONCallback(response);
1178-
return response;
1176+
this._fromJSON = createFromJSONCallback(this);
1177+
}
1178+
1179+
export function createResponse(
1180+
bundlerConfig: SSRModuleMap,
1181+
moduleLoading: ModuleLoading,
1182+
callServer: void | CallServerCallback,
1183+
encodeFormAction: void | EncodeFormActionCallback,
1184+
nonce: void | string,
1185+
temporaryReferences: void | TemporaryReferenceSet,
1186+
findSourceMapURL: void | FindSourceMapURLCallback,
1187+
): Response {
1188+
// $FlowFixMe[invalid-constructor]: the shapes are exact here but Flow doesn't like constructors
1189+
return new ResponseInstance(
1190+
bundlerConfig,
1191+
moduleLoading,
1192+
callServer,
1193+
encodeFormAction,
1194+
nonce,
1195+
temporaryReferences,
1196+
findSourceMapURL,
1197+
);
11791198
}
11801199

11811200
function resolveModel(

packages/react-client/src/__tests__/ReactFlight-test.js

Lines changed: 23 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -964,67 +964,47 @@ describe('ReactFlight', () => {
964964
const testCases = (
965965
<>
966966
<ClientErrorBoundary expectedMessage="This is a real Error.">
967-
<div>
968-
<Throw value={new TypeError('This is a real Error.')} />
969-
</div>
967+
<Throw value={new TypeError('This is a real Error.')} />
970968
</ClientErrorBoundary>
971969
<ClientErrorBoundary expectedMessage="This is a string error.">
972-
<div>
973-
<Throw value="This is a string error." />
974-
</div>
970+
<Throw value="This is a string error." />
975971
</ClientErrorBoundary>
976972
<ClientErrorBoundary expectedMessage="{message: ..., extra: ..., nested: ...}">
977-
<div>
978-
<Throw
979-
value={{
980-
message: 'This is a long message',
981-
extra: 'properties',
982-
nested: {more: 'prop'},
983-
}}
984-
/>
985-
</div>
973+
<Throw
974+
value={{
975+
message: 'This is a long message',
976+
extra: 'properties',
977+
nested: {more: 'prop'},
978+
}}
979+
/>
986980
</ClientErrorBoundary>
987981
<ClientErrorBoundary
988982
expectedMessage={'{message: "Short", extra: ..., nested: ...}'}>
989-
<div>
990-
<Throw
991-
value={{
992-
message: 'Short',
993-
extra: 'properties',
994-
nested: {more: 'prop'},
995-
}}
996-
/>
997-
</div>
983+
<Throw
984+
value={{
985+
message: 'Short',
986+
extra: 'properties',
987+
nested: {more: 'prop'},
988+
}}
989+
/>
998990
</ClientErrorBoundary>
999991
<ClientErrorBoundary expectedMessage="Symbol(hello)">
1000-
<div>
1001-
<Throw value={Symbol('hello')} />
1002-
</div>
992+
<Throw value={Symbol('hello')} />
1003993
</ClientErrorBoundary>
1004994
<ClientErrorBoundary expectedMessage="123">
1005-
<div>
1006-
<Throw value={123} />
1007-
</div>
995+
<Throw value={123} />
1008996
</ClientErrorBoundary>
1009997
<ClientErrorBoundary expectedMessage="undefined">
1010-
<div>
1011-
<Throw value={undefined} />
1012-
</div>
998+
<Throw value={undefined} />
1013999
</ClientErrorBoundary>
10141000
<ClientErrorBoundary expectedMessage="<div/>">
1015-
<div>
1016-
<Throw value={<div />} />
1017-
</div>
1001+
<Throw value={<div />} />
10181002
</ClientErrorBoundary>
10191003
<ClientErrorBoundary expectedMessage="function Foo() {}">
1020-
<div>
1021-
<Throw value={function Foo() {}} />
1022-
</div>
1004+
<Throw value={function Foo() {}} />
10231005
</ClientErrorBoundary>
10241006
<ClientErrorBoundary expectedMessage={'["array"]'}>
1025-
<div>
1026-
<Throw value={['array']} />
1027-
</div>
1007+
<Throw value={['array']} />
10281008
</ClientErrorBoundary>
10291009
<ClientErrorBoundary
10301010
expectedMessage={
@@ -1034,9 +1014,7 @@ describe('ReactFlight', () => {
10341014
'- A library pre-bundled an old copy of "react" or "react/jsx-runtime".\n' +
10351015
'- A compiler tries to "inline" JSX instead of using the runtime.'
10361016
}>
1037-
<div>
1038-
<LazyInlined />
1039-
</div>
1017+
<LazyInlined />
10401018
</ClientErrorBoundary>
10411019
</>
10421020
);

packages/react-devtools-shared/src/backend/renderer.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,7 @@ export function getInternalReactConstants(version: string): {
268268
TracingMarkerComponent: 25, // Experimental - This is technically in 18 but we don't
269269
// want to fork again so we're adding it here instead
270270
YieldComponent: -1, // Removed
271+
Throw: 29,
271272
};
272273
} else if (gte(version, '17.0.0-alpha')) {
273274
ReactTypeOfWork = {
@@ -302,6 +303,7 @@ export function getInternalReactConstants(version: string): {
302303
SuspenseListComponent: 19, // Experimental
303304
TracingMarkerComponent: -1, // Doesn't exist yet
304305
YieldComponent: -1, // Removed
306+
Throw: -1, // Doesn't exist yet
305307
};
306308
} else if (gte(version, '16.6.0-beta.0')) {
307309
ReactTypeOfWork = {
@@ -336,6 +338,7 @@ export function getInternalReactConstants(version: string): {
336338
SuspenseListComponent: 19, // Experimental
337339
TracingMarkerComponent: -1, // Doesn't exist yet
338340
YieldComponent: -1, // Removed
341+
Throw: -1, // Doesn't exist yet
339342
};
340343
} else if (gte(version, '16.4.3-alpha')) {
341344
ReactTypeOfWork = {
@@ -370,6 +373,7 @@ export function getInternalReactConstants(version: string): {
370373
SuspenseListComponent: -1, // Doesn't exist yet
371374
TracingMarkerComponent: -1, // Doesn't exist yet
372375
YieldComponent: -1, // Removed
376+
Throw: -1, // Doesn't exist yet
373377
};
374378
} else {
375379
ReactTypeOfWork = {
@@ -404,6 +408,7 @@ export function getInternalReactConstants(version: string): {
404408
SuspenseListComponent: -1, // Doesn't exist yet
405409
TracingMarkerComponent: -1, // Doesn't exist yet
406410
YieldComponent: 9,
411+
Throw: -1, // Doesn't exist yet
407412
};
408413
}
409414
// **********************************************************
@@ -445,6 +450,7 @@ export function getInternalReactConstants(version: string): {
445450
SuspenseComponent,
446451
SuspenseListComponent,
447452
TracingMarkerComponent,
453+
Throw,
448454
} = ReactTypeOfWork;
449455

450456
function resolveFiberType(type: any): $FlowFixMe {
@@ -551,6 +557,9 @@ export function getInternalReactConstants(version: string): {
551557
return 'Profiler';
552558
case TracingMarkerComponent:
553559
return 'TracingMarker';
560+
case Throw:
561+
// This should really never be visible.
562+
return 'Error';
554563
default:
555564
const typeSymbol = getTypeSymbol(type);
556565

@@ -672,6 +681,7 @@ export function attach(
672681
SuspenseComponent,
673682
SuspenseListComponent,
674683
TracingMarkerComponent,
684+
Throw,
675685
} = ReactTypeOfWork;
676686
const {
677687
ImmediatePriority,
@@ -1036,6 +1046,7 @@ export function attach(
10361046
case HostText:
10371047
case LegacyHiddenComponent:
10381048
case OffscreenComponent:
1049+
case Throw:
10391050
return true;
10401051
case HostRoot:
10411052
// It is never valid to filter the root element.

packages/react-devtools-shared/src/backend/types.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ export type WorkTagMap = {
7272
SuspenseListComponent: WorkTag,
7373
TracingMarkerComponent: WorkTag,
7474
YieldComponent: WorkTag,
75+
Throw: WorkTag,
7576
};
7677

7778
// TODO: If it's useful for the frontend to know which types of data an Element has

packages/react-reconciler/src/ReactChildFiber.js

Lines changed: 47 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import {
2525
Forked,
2626
PlacementDEV,
2727
} from './ReactFiberFlags';
28+
import {NoMode, ConcurrentMode} from './ReactTypeOfMode';
2829
import {
2930
getIteratorFn,
3031
ASYNC_ITERATOR,
@@ -46,6 +47,7 @@ import isArray from 'shared/isArray';
4647
import {
4748
enableRefAsProp,
4849
enableAsyncIterableChildren,
50+
disableLegacyMode,
4951
} from 'shared/ReactFeatureFlags';
5052

5153
import {
@@ -55,11 +57,16 @@ import {
5557
createFiberFromFragment,
5658
createFiberFromText,
5759
createFiberFromPortal,
60+
createFiberFromThrow,
5861
} from './ReactFiber';
5962
import {isCompatibleFamilyForHotReloading} from './ReactFiberHotReloading';
6063
import {getIsHydrating} from './ReactFiberHydrationContext';
6164
import {pushTreeFork} from './ReactFiberTreeContext';
62-
import {createThenableState, trackUsedThenable} from './ReactFiberThenable';
65+
import {
66+
SuspenseException,
67+
createThenableState,
68+
trackUsedThenable,
69+
} from './ReactFiberThenable';
6370
import {readContextDuringReconciliation} from './ReactFiberNewContext';
6471
import {callLazyInitInDEV} from './ReactFiberCallUserSpace';
6572

@@ -1919,20 +1926,45 @@ function createChildReconciler(
19191926
newChild: any,
19201927
lanes: Lanes,
19211928
): Fiber | null {
1922-
// This indirection only exists so we can reset `thenableState` at the end.
1923-
// It should get inlined by Closure.
1924-
thenableIndexCounter = 0;
1925-
const firstChildFiber = reconcileChildFibersImpl(
1926-
returnFiber,
1927-
currentFirstChild,
1928-
newChild,
1929-
lanes,
1930-
null, // debugInfo
1931-
);
1932-
thenableState = null;
1933-
// Don't bother to reset `thenableIndexCounter` to 0 because it always gets
1934-
// set at the beginning.
1935-
return firstChildFiber;
1929+
try {
1930+
// This indirection only exists so we can reset `thenableState` at the end.
1931+
// It should get inlined by Closure.
1932+
thenableIndexCounter = 0;
1933+
const firstChildFiber = reconcileChildFibersImpl(
1934+
returnFiber,
1935+
currentFirstChild,
1936+
newChild,
1937+
lanes,
1938+
null, // debugInfo
1939+
);
1940+
thenableState = null;
1941+
// Don't bother to reset `thenableIndexCounter` to 0 because it always gets
1942+
// set at the beginning.
1943+
return firstChildFiber;
1944+
} catch (x) {
1945+
if (
1946+
x === SuspenseException ||
1947+
(!disableLegacyMode &&
1948+
(returnFiber.mode & ConcurrentMode) === NoMode &&
1949+
typeof x === 'object' &&
1950+
x !== null &&
1951+
typeof x.then === 'function')
1952+
) {
1953+
// Suspense exceptions need to read the current suspended state before
1954+
// yielding and replay it using the same sequence so this trick doesn't
1955+
// work here.
1956+
// Suspending in legacy mode actually mounts so if we let the child
1957+
// mount then we delete its state in an update.
1958+
throw x;
1959+
}
1960+
// Something errored during reconciliation but it's conceptually a child that
1961+
// errored and not the current component itself so we create a virtual child
1962+
// that throws in its begin phase. That way the current component can handle
1963+
// the error or suspending if needed.
1964+
const throwFiber = createFiberFromThrow(x, returnFiber.mode, lanes);
1965+
throwFiber.return = returnFiber;
1966+
return throwFiber;
1967+
}
19361968
}
19371969

19381970
return reconcileChildFibers;

packages/react-reconciler/src/ReactFiber.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ import {
6767
OffscreenComponent,
6868
LegacyHiddenComponent,
6969
TracingMarkerComponent,
70+
Throw,
7071
} from './ReactWorkTags';
7172
import {OffscreenVisible} from './ReactFiberActivityComponent';
7273
import {getComponentNameFromOwner} from 'react-reconciler/src/getComponentNameFromFiber';
@@ -879,3 +880,13 @@ export function createFiberFromPortal(
879880
};
880881
return fiber;
881882
}
883+
884+
export function createFiberFromThrow(
885+
error: mixed,
886+
mode: TypeOfMode,
887+
lanes: Lanes,
888+
): Fiber {
889+
const fiber = createFiber(Throw, error, null, mode);
890+
fiber.lanes = lanes;
891+
return fiber;
892+
}

0 commit comments

Comments
 (0)