Skip to content

Commit 54bd813

Browse files
committedJun 27, 2024·
Add new package with renderToMarkup export (#30105)
Name of the package is tbd (straw: `react-html`). It's a new package separate from `react-dom` though and can be used as a standalone package - e.g. also from a React Native app. ```js import {renderToMarkup} from '...'; const html = await renderToMarkup(<Component />); ``` The idea is that this is a helper for rendering HTML that is not intended to be hydrated. It's primarily intended to support a subset of HTML that can be used as embedding and not served as HTML documents from HTTP. For example as e-mails or in RSS/Atom feeds or other distributions. It's a successor to `renderToStaticMarkup`. A few differences: - This doesn't support "Client Components". It can only use the Server Components subset. No useEffect, no useState etc. since it will never be hydrated. Use of those are errors. - You also can't pass Client References so you can't use components marked with `"use client"`. - Unlike `renderToStaticMarkup` this does support async so you can suspend and use data from these components. - Unlike `renderToReadableStream` this does not support streaming or Suspense boundaries and any error rejects the promise. Since there's no feasible way to "client render" or patch up the document. - Form Actions are not supported since in an embedded environment there's no place to post back to across versions. You can render plain forms with fixed URLs though. - You can't use any resource preloading like `preload()` from `react-dom`. ## Implementation This first version in this PR only supports Server Components since that's the thing that doesn't have an existing API. Might add a Client Components version later that errors. We don't want to maintain a completely separate implementation for this use case so this uses the `dom-legacy` build dimension to wire up a build that encapsulates a Flight Server -> Flight Client -> Fizz stream to render Server Components that then get SSR:ed. There's no problem to use a Flight Client in a Server Component environment since it's already supported for Server-to-Server. Both of these use a bundler config that just errors for Client References though since we don't need any bundling integration and this is just a standalone package. Running Fizz in a Server Component environment is a problem though because it depends on "react" and it needs the client version. Therefore, for this build we embed the client version of "react" shared internals into the build. It doesn't need anything to be able to use those APIs since you can't call the client APIs anyway. One unfortunate thing though is that since Flight currently needs to go to binary and back, we need TextEncoder/TextDecoder to be available but this shouldn't really be necessary. Also since we use the legacy stream config, large strings that use byteLengthOfChunk errors atm. This needs to be fixed before shipping. I'm not sure what would be the best layering though that isn't unnecessarily burdensome to maintain. Maybe some kind of pass-through protocol that would also be useful in general - e.g. when Fizz and Flight are in the same process. --------- Co-authored-by: Sebastian Silbermann <[email protected]> DiffTrain build for commit ffec9ec.
1 parent 76e5823 commit 54bd813

File tree

14 files changed

+144
-100
lines changed

14 files changed

+144
-100
lines changed
 

Diff for: ‎compiled-rn/VERSION_NATIVE_FB

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
19.0.0-native-fb-ef0f44ecff-20240626
1+
19.0.0-native-fb-ffec9ec5b5-20240627

Diff for: ‎compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react/react-test-renderer/cjs/ReactTestRenderer-dev.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* @noflow
88
* @nolint
99
* @preventMunge
10-
* @generated SignedSource<<8e0b5ef521249935e03c766c90de416e>>
10+
* @generated SignedSource<<44d1ab19516f0dc7115b3084b1b6983a>>
1111
*/
1212

1313
"use strict";
@@ -15070,14 +15070,14 @@ __DEV__ &&
1507015070
scheduleRoot: scheduleRoot,
1507115071
setRefreshHandler: setRefreshHandler,
1507215072
getCurrentFiber: getCurrentFiberForDevTools,
15073-
reconcilerVersion: "19.0.0-native-fb-ef0f44ecff-20240626"
15073+
reconcilerVersion: "19.0.0-native-fb-ffec9ec5b5-20240627"
1507415074
});
1507515075
})({
1507615076
findFiberByHostInstance: function () {
1507715077
throw Error("TestRenderer does not support findFiberByHostInstance()");
1507815078
},
1507915079
bundleType: 1,
15080-
version: "19.0.0-native-fb-ef0f44ecff-20240626",
15080+
version: "19.0.0-native-fb-ffec9ec5b5-20240627",
1508115081
rendererPackageName: "react-test-renderer"
1508215082
});
1508315083
exports._Scheduler = Scheduler;

Diff for: ‎compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react/react-test-renderer/cjs/ReactTestRenderer-prod.js

+58-36
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* @noflow
88
* @nolint
99
* @preventMunge
10-
* @generated SignedSource<<662c488eb64cb9fca6226af34d92f742>>
10+
* @generated SignedSource<<718ff5e34ce4342f80f8cd32c0855485>>
1111
*/
1212

1313
"use strict";
@@ -3065,24 +3065,26 @@ function updateMemo(nextCreate, deps) {
30653065
hook.memoizedState = [prevState, deps];
30663066
return prevState;
30673067
}
3068-
function updateDeferredValueImpl(hook, prevValue, value) {
3068+
function mountDeferredValueImpl(hook, value, initialValue) {
3069+
if (void 0 === initialValue || 0 !== (renderLanes & 1073741824))
3070+
return (hook.memoizedState = value);
3071+
hook.memoizedState = initialValue;
3072+
hook = requestDeferredLane();
3073+
currentlyRenderingFiber$1.lanes |= hook;
3074+
workInProgressRootSkippedLanes |= hook;
3075+
return initialValue;
3076+
}
3077+
function updateDeferredValueImpl(hook, prevValue, value, initialValue) {
30693078
if (objectIs(value, prevValue)) return value;
30703079
if (null !== currentTreeHiddenStackCursor.current)
30713080
return (
3072-
(hook.memoizedState = value),
3073-
objectIs(value, prevValue) || (didReceiveUpdate = !0),
3074-
value
3081+
(hook = mountDeferredValueImpl(hook, value, initialValue)),
3082+
objectIs(hook, prevValue) || (didReceiveUpdate = !0),
3083+
hook
30753084
);
30763085
if (0 === (renderLanes & 42))
30773086
return (didReceiveUpdate = !0), (hook.memoizedState = value);
3078-
0 === workInProgressDeferredLane &&
3079-
(workInProgressDeferredLane =
3080-
0 !== (workInProgressRootRenderLanes & 536870912)
3081-
? 536870912
3082-
: claimNextTransitionLane());
3083-
hook = suspenseHandlerStackCursor.current;
3084-
null !== hook && (hook.flags |= 32);
3085-
hook = workInProgressDeferredLane;
3087+
hook = requestDeferredLane();
30863088
currentlyRenderingFiber$1.lanes |= hook;
30873089
workInProgressRootSkippedLanes |= hook;
30883090
return prevValue;
@@ -3346,9 +3348,9 @@ var HooksDispatcherOnMount = {
33463348
return [initialState.memoizedState, dispatch];
33473349
},
33483350
useDebugValue: mountDebugValue,
3349-
useDeferredValue: function (value) {
3350-
mountWorkInProgressHook().memoizedState = value;
3351-
return value;
3351+
useDeferredValue: function (value, initialValue) {
3352+
var hook = mountWorkInProgressHook();
3353+
return mountDeferredValueImpl(hook, value, initialValue);
33523354
},
33533355
useTransition: function () {
33543356
var stateHook = mountStateImpl(!1);
@@ -3443,9 +3445,14 @@ var HooksDispatcherOnUpdate = {
34433445
return updateReducer(basicStateReducer);
34443446
},
34453447
useDebugValue: mountDebugValue,
3446-
useDeferredValue: function (value) {
3448+
useDeferredValue: function (value, initialValue) {
34473449
var hook = updateWorkInProgressHook();
3448-
return updateDeferredValueImpl(hook, currentHook.memoizedState, value);
3450+
return updateDeferredValueImpl(
3451+
hook,
3452+
currentHook.memoizedState,
3453+
value,
3454+
initialValue
3455+
);
34493456
},
34503457
useTransition: function () {
34513458
var booleanOrThenable = updateReducer(basicStateReducer)[0],
@@ -3485,11 +3492,16 @@ var HooksDispatcherOnRerender = {
34853492
return rerenderReducer(basicStateReducer);
34863493
},
34873494
useDebugValue: mountDebugValue,
3488-
useDeferredValue: function (value) {
3495+
useDeferredValue: function (value, initialValue) {
34893496
var hook = updateWorkInProgressHook();
34903497
return null === currentHook
3491-
? ((hook.memoizedState = value), value)
3492-
: updateDeferredValueImpl(hook, currentHook.memoizedState, value);
3498+
? mountDeferredValueImpl(hook, value, initialValue)
3499+
: updateDeferredValueImpl(
3500+
hook,
3501+
currentHook.memoizedState,
3502+
value,
3503+
initialValue
3504+
);
34933505
},
34943506
useTransition: function () {
34953507
var booleanOrThenable = rerenderReducer(basicStateReducer)[0],
@@ -7626,6 +7638,16 @@ function requestUpdateLane(fiber) {
76267638
fiber = 0 !== currentUpdatePriority ? currentUpdatePriority : 32;
76277639
return fiber;
76287640
}
7641+
function requestDeferredLane() {
7642+
0 === workInProgressDeferredLane &&
7643+
(workInProgressDeferredLane =
7644+
0 !== (workInProgressRootRenderLanes & 536870912)
7645+
? 536870912
7646+
: claimNextTransitionLane());
7647+
var suspenseHandler = suspenseHandlerStackCursor.current;
7648+
null !== suspenseHandler && (suspenseHandler.flags |= 32);
7649+
return workInProgressDeferredLane;
7650+
}
76297651
function scheduleUpdateOnFiber(root, fiber, lane) {
76307652
if (
76317653
(root === workInProgressRoot && 2 === workInProgressSuspendedReason) ||
@@ -9370,19 +9392,19 @@ function wrapFiber(fiber) {
93709392
fiberToWrapper.set(fiber, wrapper));
93719393
return wrapper;
93729394
}
9373-
var devToolsConfig$jscomp$inline_1053 = {
9395+
var devToolsConfig$jscomp$inline_1034 = {
93749396
findFiberByHostInstance: function () {
93759397
throw Error("TestRenderer does not support findFiberByHostInstance()");
93769398
},
93779399
bundleType: 0,
9378-
version: "19.0.0-native-fb-ef0f44ecff-20240626",
9400+
version: "19.0.0-native-fb-ffec9ec5b5-20240627",
93799401
rendererPackageName: "react-test-renderer"
93809402
};
9381-
var internals$jscomp$inline_1240 = {
9382-
bundleType: devToolsConfig$jscomp$inline_1053.bundleType,
9383-
version: devToolsConfig$jscomp$inline_1053.version,
9384-
rendererPackageName: devToolsConfig$jscomp$inline_1053.rendererPackageName,
9385-
rendererConfig: devToolsConfig$jscomp$inline_1053.rendererConfig,
9403+
var internals$jscomp$inline_1223 = {
9404+
bundleType: devToolsConfig$jscomp$inline_1034.bundleType,
9405+
version: devToolsConfig$jscomp$inline_1034.version,
9406+
rendererPackageName: devToolsConfig$jscomp$inline_1034.rendererPackageName,
9407+
rendererConfig: devToolsConfig$jscomp$inline_1034.rendererConfig,
93869408
overrideHookState: null,
93879409
overrideHookStateDeletePath: null,
93889410
overrideHookStateRenamePath: null,
@@ -9399,26 +9421,26 @@ var internals$jscomp$inline_1240 = {
93999421
return null === fiber ? null : fiber.stateNode;
94009422
},
94019423
findFiberByHostInstance:
9402-
devToolsConfig$jscomp$inline_1053.findFiberByHostInstance ||
9424+
devToolsConfig$jscomp$inline_1034.findFiberByHostInstance ||
94039425
emptyFindFiberByHostInstance,
94049426
findHostInstancesForRefresh: null,
94059427
scheduleRefresh: null,
94069428
scheduleRoot: null,
94079429
setRefreshHandler: null,
94089430
getCurrentFiber: null,
9409-
reconcilerVersion: "19.0.0-native-fb-ef0f44ecff-20240626"
9431+
reconcilerVersion: "19.0.0-native-fb-ffec9ec5b5-20240627"
94109432
};
94119433
if ("undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) {
9412-
var hook$jscomp$inline_1241 = __REACT_DEVTOOLS_GLOBAL_HOOK__;
9434+
var hook$jscomp$inline_1224 = __REACT_DEVTOOLS_GLOBAL_HOOK__;
94139435
if (
9414-
!hook$jscomp$inline_1241.isDisabled &&
9415-
hook$jscomp$inline_1241.supportsFiber
9436+
!hook$jscomp$inline_1224.isDisabled &&
9437+
hook$jscomp$inline_1224.supportsFiber
94169438
)
94179439
try {
9418-
(rendererID = hook$jscomp$inline_1241.inject(
9419-
internals$jscomp$inline_1240
9440+
(rendererID = hook$jscomp$inline_1224.inject(
9441+
internals$jscomp$inline_1223
94209442
)),
9421-
(injectedHook = hook$jscomp$inline_1241);
9443+
(injectedHook = hook$jscomp$inline_1224);
94229444
} catch (err) {}
94239445
}
94249446
exports._Scheduler = Scheduler;

Diff for: ‎compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react/react-test-renderer/cjs/ReactTestRenderer-profiling.js

+51-29
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* @noflow
88
* @nolint
99
* @preventMunge
10-
* @generated SignedSource<<44b110765ad32ba787de678da6257de3>>
10+
* @generated SignedSource<<c46fe24487d3b639d3f58189945d6b49>>
1111
*/
1212

1313
"use strict";
@@ -3153,24 +3153,26 @@ function updateMemo(nextCreate, deps) {
31533153
hook.memoizedState = [prevState, deps];
31543154
return prevState;
31553155
}
3156-
function updateDeferredValueImpl(hook, prevValue, value) {
3156+
function mountDeferredValueImpl(hook, value, initialValue) {
3157+
if (void 0 === initialValue || 0 !== (renderLanes & 1073741824))
3158+
return (hook.memoizedState = value);
3159+
hook.memoizedState = initialValue;
3160+
hook = requestDeferredLane();
3161+
currentlyRenderingFiber$1.lanes |= hook;
3162+
workInProgressRootSkippedLanes |= hook;
3163+
return initialValue;
3164+
}
3165+
function updateDeferredValueImpl(hook, prevValue, value, initialValue) {
31573166
if (objectIs(value, prevValue)) return value;
31583167
if (null !== currentTreeHiddenStackCursor.current)
31593168
return (
3160-
(hook.memoizedState = value),
3161-
objectIs(value, prevValue) || (didReceiveUpdate = !0),
3162-
value
3169+
(hook = mountDeferredValueImpl(hook, value, initialValue)),
3170+
objectIs(hook, prevValue) || (didReceiveUpdate = !0),
3171+
hook
31633172
);
31643173
if (0 === (renderLanes & 42))
31653174
return (didReceiveUpdate = !0), (hook.memoizedState = value);
3166-
0 === workInProgressDeferredLane &&
3167-
(workInProgressDeferredLane =
3168-
0 !== (workInProgressRootRenderLanes & 536870912)
3169-
? 536870912
3170-
: claimNextTransitionLane());
3171-
hook = suspenseHandlerStackCursor.current;
3172-
null !== hook && (hook.flags |= 32);
3173-
hook = workInProgressDeferredLane;
3175+
hook = requestDeferredLane();
31743176
currentlyRenderingFiber$1.lanes |= hook;
31753177
workInProgressRootSkippedLanes |= hook;
31763178
return prevValue;
@@ -3437,9 +3439,9 @@ var HooksDispatcherOnMount = {
34373439
return [initialState.memoizedState, dispatch];
34383440
},
34393441
useDebugValue: mountDebugValue,
3440-
useDeferredValue: function (value) {
3441-
mountWorkInProgressHook().memoizedState = value;
3442-
return value;
3442+
useDeferredValue: function (value, initialValue) {
3443+
var hook = mountWorkInProgressHook();
3444+
return mountDeferredValueImpl(hook, value, initialValue);
34433445
},
34443446
useTransition: function () {
34453447
var stateHook = mountStateImpl(!1);
@@ -3534,9 +3536,14 @@ var HooksDispatcherOnUpdate = {
35343536
return updateReducer(basicStateReducer);
35353537
},
35363538
useDebugValue: mountDebugValue,
3537-
useDeferredValue: function (value) {
3539+
useDeferredValue: function (value, initialValue) {
35383540
var hook = updateWorkInProgressHook();
3539-
return updateDeferredValueImpl(hook, currentHook.memoizedState, value);
3541+
return updateDeferredValueImpl(
3542+
hook,
3543+
currentHook.memoizedState,
3544+
value,
3545+
initialValue
3546+
);
35403547
},
35413548
useTransition: function () {
35423549
var booleanOrThenable = updateReducer(basicStateReducer)[0],
@@ -3576,11 +3583,16 @@ var HooksDispatcherOnRerender = {
35763583
return rerenderReducer(basicStateReducer);
35773584
},
35783585
useDebugValue: mountDebugValue,
3579-
useDeferredValue: function (value) {
3586+
useDeferredValue: function (value, initialValue) {
35803587
var hook = updateWorkInProgressHook();
35813588
return null === currentHook
3582-
? ((hook.memoizedState = value), value)
3583-
: updateDeferredValueImpl(hook, currentHook.memoizedState, value);
3589+
? mountDeferredValueImpl(hook, value, initialValue)
3590+
: updateDeferredValueImpl(
3591+
hook,
3592+
currentHook.memoizedState,
3593+
value,
3594+
initialValue
3595+
);
35843596
},
35853597
useTransition: function () {
35863598
var booleanOrThenable = rerenderReducer(basicStateReducer)[0],
@@ -8097,6 +8109,16 @@ function requestUpdateLane(fiber) {
80978109
fiber = 0 !== currentUpdatePriority ? currentUpdatePriority : 32;
80988110
return fiber;
80998111
}
8112+
function requestDeferredLane() {
8113+
0 === workInProgressDeferredLane &&
8114+
(workInProgressDeferredLane =
8115+
0 !== (workInProgressRootRenderLanes & 536870912)
8116+
? 536870912
8117+
: claimNextTransitionLane());
8118+
var suspenseHandler = suspenseHandlerStackCursor.current;
8119+
null !== suspenseHandler && (suspenseHandler.flags |= 32);
8120+
return workInProgressDeferredLane;
8121+
}
81008122
function scheduleUpdateOnFiber(root, fiber, lane) {
81018123
if (
81028124
(root === workInProgressRoot && 2 === workInProgressSuspendedReason) ||
@@ -9990,12 +10012,12 @@ function wrapFiber(fiber) {
999010012
fiberToWrapper.set(fiber, wrapper));
999110013
return wrapper;
999210014
}
9993-
var devToolsConfig$jscomp$inline_1136 = {
10015+
var devToolsConfig$jscomp$inline_1117 = {
999410016
findFiberByHostInstance: function () {
999510017
throw Error("TestRenderer does not support findFiberByHostInstance()");
999610018
},
999710019
bundleType: 0,
9998-
version: "19.0.0-native-fb-ef0f44ecff-20240626",
10020+
version: "19.0.0-native-fb-ffec9ec5b5-20240627",
999910021
rendererPackageName: "react-test-renderer"
1000010022
};
1000110023
(function (internals) {
@@ -10012,10 +10034,10 @@ var devToolsConfig$jscomp$inline_1136 = {
1001210034
} catch (err) {}
1001310035
return hook.checkDCE ? !0 : !1;
1001410036
})({
10015-
bundleType: devToolsConfig$jscomp$inline_1136.bundleType,
10016-
version: devToolsConfig$jscomp$inline_1136.version,
10017-
rendererPackageName: devToolsConfig$jscomp$inline_1136.rendererPackageName,
10018-
rendererConfig: devToolsConfig$jscomp$inline_1136.rendererConfig,
10037+
bundleType: devToolsConfig$jscomp$inline_1117.bundleType,
10038+
version: devToolsConfig$jscomp$inline_1117.version,
10039+
rendererPackageName: devToolsConfig$jscomp$inline_1117.rendererPackageName,
10040+
rendererConfig: devToolsConfig$jscomp$inline_1117.rendererConfig,
1001910041
overrideHookState: null,
1002010042
overrideHookStateDeletePath: null,
1002110043
overrideHookStateRenamePath: null,
@@ -10032,14 +10054,14 @@ var devToolsConfig$jscomp$inline_1136 = {
1003210054
return null === fiber ? null : fiber.stateNode;
1003310055
},
1003410056
findFiberByHostInstance:
10035-
devToolsConfig$jscomp$inline_1136.findFiberByHostInstance ||
10057+
devToolsConfig$jscomp$inline_1117.findFiberByHostInstance ||
1003610058
emptyFindFiberByHostInstance,
1003710059
findHostInstancesForRefresh: null,
1003810060
scheduleRefresh: null,
1003910061
scheduleRoot: null,
1004010062
setRefreshHandler: null,
1004110063
getCurrentFiber: null,
10042-
reconcilerVersion: "19.0.0-native-fb-ef0f44ecff-20240626"
10064+
reconcilerVersion: "19.0.0-native-fb-ffec9ec5b5-20240627"
1004310065
});
1004410066
exports._Scheduler = Scheduler;
1004510067
exports.act = act;

Diff for: ‎compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react/react/cjs/React-dev.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* @noflow
88
* @nolint
99
* @preventMunge
10-
* @generated SignedSource<<5a86cb63301afae4ae8ebe0e5c4d6245>>
10+
* @generated SignedSource<<fe33295fc61cdcf79ee85f36a7be4698>>
1111
*/
1212

1313
"use strict";
@@ -1741,7 +1741,7 @@ __DEV__ &&
17411741
exports.useTransition = function () {
17421742
return resolveDispatcher().useTransition();
17431743
};
1744-
exports.version = "19.0.0-native-fb-ef0f44ecff-20240626";
1744+
exports.version = "19.0.0-native-fb-ffec9ec5b5-20240627";
17451745
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
17461746
"function" ===
17471747
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&

0 commit comments

Comments
 (0)
Please sign in to comment.