From e83564ae448640ab0d1dceb2ff6f3a4b8476b480 Mon Sep 17 00:00:00 2001 From: sebmarkbage Date: Wed, 8 May 2024 01:58:38 +0000 Subject: [PATCH] [Flight Reply] Encode binary streams as a single collapsed Blob (#28986) Based on #28893. For other streams we encode each chunk as a separate form field which is a bit bloated. Especially for binary chunks since they also have an indirection. We need some way to encode the chunks as separate anyway. This way the streaming using busboy actually allows each chunk to stream in over the network one at a time. For binary streams the actual chunking is not important. The chunks can be split and recombined in whatever size chunk makes sense. Since we buffer the entire content anyway we can combine the chunks to be consecutive. This PR does that with binary streams and also combine them into a single Blob. That way there's no extra overhead when passing through a binary stream. Ideally, we'd be able to just use the stream from that one Blob but Node.js doesn't return byob streams from Blob. Additionally, we don't actually stream the content of Blobs due to the layering with busboy atm. We could do that for binary streams in particular by replacing the File layering with a stream and resolving each chunk as it comes in. That could be a follow up. If we stop buffering in the future, this set up still allows us to split them and send other form fields in between while blocked since the protocol is still the same. DiffTrain build for [826bf4e51ecf14904e936ed043392084553ebbaa](https://github.com/facebook/react/commit/826bf4e51ecf14904e936ed043392084553ebbaa) --- compiled/facebook-www/REVISION | 2 +- .../ReactDOMServer-dev.classic.js | 31 +++-------- .../facebook-www/ReactDOMServer-dev.modern.js | 31 +++-------- .../ReactDOMServer-prod.classic.js | 54 ++++++++----------- .../ReactDOMServer-prod.modern.js | 54 ++++++++----------- .../ReactDOMServerStreaming-dev.modern.js | 29 +++------- .../ReactDOMServerStreaming-prod.modern.js | 18 ++----- 7 files changed, 72 insertions(+), 147 deletions(-) diff --git a/compiled/facebook-www/REVISION b/compiled/facebook-www/REVISION index 272b4a9a4fd96..e11f9c7839bc9 100644 --- a/compiled/facebook-www/REVISION +++ b/compiled/facebook-www/REVISION @@ -1 +1 @@ -6bac4f2f31378cd58dffe6181e00639366a6081a +826bf4e51ecf14904e936ed043392084553ebbaa diff --git a/compiled/facebook-www/ReactDOMServer-dev.classic.js b/compiled/facebook-www/ReactDOMServer-dev.classic.js index 2775b030c1368..f4e58b2ca311a 100644 --- a/compiled/facebook-www/ReactDOMServer-dev.classic.js +++ b/compiled/facebook-www/ReactDOMServer-dev.classic.js @@ -19,7 +19,7 @@ if (__DEV__) { var React = require('react'); var ReactDOM = require('react-dom'); -var ReactVersion = '19.0.0-www-classic-b547cfd9'; +var ReactVersion = '19.0.0-www-classic-f3d84129'; // This refers to a WWW module. var warningWWW = require('warning'); @@ -2572,7 +2572,11 @@ var startHiddenInputChunk = stringToPrecomputedChunk('"); } -function validateAdditionalFormField(value) { - if ("string" !== typeof value) throw Error(formatProdErrorMessage(480)); -} function getCustomFormFields(resumableState, formAction) { if ("function" === typeof formAction.$$FORM_ACTION) { var id = resumableState.nextFormID++; resumableState = resumableState.idPrefix + id; try { - var customFields = formAction.$$FORM_ACTION(resumableState); - if (customFields) { - var formData = customFields.data; - null != formData && formData.forEach(validateAdditionalFormField); - } - return customFields; + return formAction.$$FORM_ACTION(resumableState); } catch (x) { if ("object" === typeof x && null !== x && "function" === typeof x.then) throw x; @@ -2635,16 +2627,16 @@ function createRenderState(resumableState, generateStaticMarkup) { "\x3c/script>" ); bootstrapScriptContent = idPrefix + "P:"; - var JSCompiler_object_inline_segmentPrefix_1633 = idPrefix + "S:"; + var JSCompiler_object_inline_segmentPrefix_1631 = idPrefix + "S:"; idPrefix += "B:"; - var JSCompiler_object_inline_preconnects_1647 = new Set(), - JSCompiler_object_inline_fontPreloads_1648 = new Set(), - JSCompiler_object_inline_highImagePreloads_1649 = new Set(), - JSCompiler_object_inline_styles_1650 = new Map(), - JSCompiler_object_inline_bootstrapScripts_1651 = new Set(), - JSCompiler_object_inline_scripts_1652 = new Set(), - JSCompiler_object_inline_bulkPreloads_1653 = new Set(), - JSCompiler_object_inline_preloads_1654 = { + var JSCompiler_object_inline_preconnects_1645 = new Set(), + JSCompiler_object_inline_fontPreloads_1646 = new Set(), + JSCompiler_object_inline_highImagePreloads_1647 = new Set(), + JSCompiler_object_inline_styles_1648 = new Map(), + JSCompiler_object_inline_bootstrapScripts_1649 = new Set(), + JSCompiler_object_inline_scripts_1650 = new Set(), + JSCompiler_object_inline_bulkPreloads_1651 = new Set(), + JSCompiler_object_inline_preloads_1652 = { images: new Map(), stylesheets: new Map(), scripts: new Map(), @@ -2681,7 +2673,7 @@ function createRenderState(resumableState, generateStaticMarkup) { scriptConfig.moduleScriptResources[href] = null; scriptConfig = []; pushLinkImpl(scriptConfig, props); - JSCompiler_object_inline_bootstrapScripts_1651.add(scriptConfig); + JSCompiler_object_inline_bootstrapScripts_1649.add(scriptConfig); bootstrapChunks.push('