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] Basic Streaming Suspense Support #17285

Merged
merged 6 commits into from Nov 6, 2019
Merged

Conversation

@sebmarkbage
Copy link
Member

sebmarkbage commented Nov 6, 2019

This adds basic Suspense support to Flight by streaming the response.

First it sends one line with the root JSON model. Within the model holes are replaced with "$" followed by a hex ID. E.g. "$12AB3".

Subsequent lines begin with "J" followed by a hex ID.

So an example response may look something like:

{"some":{"json":"$1"},data:["$1","$2"]}
J1:{"more":"data"}
J2:{"even":"more"}

The client suspends if you try to access an unresolved value. Once a new line comes in it unsuspends that part of the model.

Currently this suspending is implemented as a getter but it could also be a Proxy. However, more likely is that we'll hide this behind an explicit API that unwraps both components and its data in the future.

Errors

If the server errors while rendering one of the models that error is encoded with an "E" prefix:

{"bad":"$1","good":"$2"}
E1:{"message":"An error happened","stack": "\n..."}
J2:{"this":"worked"}

When this happens, the previously suspended part of the model now resolves and starts throwing an error on the client. This will then be caught by an error boundary on the client. Unrelated parts of the response can still continue rendering though.

If the connection dies, then all remaining pending promises resolve and start throwing an error which are caught by error boundaries. Previously resolved parts don't error though.

There's a prioritization scheme so errors are emitted at lower priority in the stream than models.

Future Additions

I added a comment describing the protocol. The protocol also includes space for a few other types of data.

  • URL: This can be used to emit URL rows at higher priority than models and can be used to preload other resources without waiting for or even parsing the JSON models yet.
  • Blob: Traditionally sending binary data is a PITA in existing protocol. We should just have this built-in. It's especially efficient with modern stream APIs. This is important in data heavy use cases like data viz.
  • HTML: Instead of encoding HTML inside JSON we can just send it as raw HTML for faster parsing and more efficient size. We can also encode that we generated this HTML (using React SSR with proper data structures) in the encoding. So we can by-pass dangerouslySetInnerHTML and just provide a React element that can be rendered directly.
@codesandbox

This comment has been minimized.

Copy link

codesandbox bot commented Nov 6, 2019

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

Latest deployment of this branch, based on commit 387c233:

Sandbox Source
flamboyant-snow-w1vb7 Configuration
@sizebot

This comment has been minimized.

Copy link

sizebot commented Nov 6, 2019

Size changes (stable)

ReactDOM: size: 🔺+62.2%, gzip: 🔺+58.2%

Details of bundled changes.

Comparing: 62ef250...387c233

react-dom

File Filesize Diff Gzip Diff Prev Size Current Size Prev Gzip Current Gzip ENV
react-dom-unstable-flight-server.browser.production.min.js 🔺+136.3% 🔺+89.4% 1.12 KB 2.64 KB 679 B 1.26 KB NODE_PROD
react-dom-unstable-flight-client.development.js +80.3% +62.4% 4.83 KB 8.7 KB 1.59 KB 2.59 KB UMD_DEV
react-dom-unstable-flight-client.production.min.js 🔺+62.2% 🔺+58.2% 1.78 KB 2.88 KB 866 B 1.34 KB UMD_PROD
react-dom-unstable-flight-server.node.development.js +112.9% +76.9% 4.49 KB 9.57 KB 1.77 KB 3.14 KB NODE_DEV
react-dom.development.js 0.0% 0.0% 951.42 KB 951.42 KB 215 KB 215 KB UMD_DEV
react-dom-server.browser.production.min.js 0.0% 0.0% 19.85 KB 19.85 KB 7.38 KB 7.38 KB NODE_PROD
react-dom-unstable-fizz.browser.development.js 0.0% -0.1% 3.87 KB 3.87 KB 1.54 KB 1.54 KB UMD_DEV
react-dom-unstable-flight-server.node.production.min.js 🔺+128.4% 🔺+80.8% 1.18 KB 2.71 KB 712 B 1.26 KB NODE_PROD
react-dom.production.min.js 0.0% 0.0% 116.16 KB 116.16 KB 37.43 KB 37.43 KB UMD_PROD
react-dom-unstable-fizz.browser.production.min.js 0.0% 🔺+0.1% 1.2 KB 1.2 KB 703 B 704 B UMD_PROD
react-dom.profiling.min.js 0.0% 0.0% 119.73 KB 119.73 KB 38.49 KB 38.5 KB UMD_PROFILING
react-dom.development.js 0.0% 0.0% 945.53 KB 945.53 KB 213.41 KB 213.41 KB NODE_DEV
react-dom-unstable-native-dependencies.development.js 0.0% 0.0% 60.13 KB 60.13 KB 15.79 KB 15.79 KB UMD_DEV
react-dom-unstable-fizz.browser.production.min.js 0.0% 🔺+0.2% 1.04 KB 1.04 KB 634 B 635 B NODE_PROD
react-dom-unstable-flight-server.browser.development.js +110.1% +71.0% 4.44 KB 9.32 KB 1.79 KB 3.06 KB UMD_DEV
react-dom-unstable-flight-server.browser.production.min.js 🔺+115.0% 🔺+78.6% 1.32 KB 2.83 KB 761 B 1.33 KB UMD_PROD
react-dom-unstable-flight-server.browser.development.js +115.4% +73.8% 4.23 KB 9.12 KB 1.73 KB 3.01 KB NODE_DEV
react-dom-server.node.development.js 0.0% 0.0% 137.39 KB 137.39 KB 36.09 KB 36.09 KB NODE_DEV
react-dom-unstable-flight-client.development.js +83.3% +64.9% 4.65 KB 8.53 KB 1.54 KB 2.55 KB NODE_DEV
react-dom-server.node.production.min.js 0.0% 0.0% 20.26 KB 20.26 KB 7.53 KB 7.53 KB NODE_PROD
react-dom-unstable-flight-client.production.min.js 🔺+68.0% 🔺+65.0% 1.61 KB 2.71 KB 792 B 1.28 KB NODE_PROD
react-dom-test-utils.production.min.js 0.0% 0.0% 11.17 KB 11.17 KB 4.14 KB 4.14 KB UMD_PROD
react-dom-test-utils.development.js 0.0% 0.0% 54.53 KB 54.53 KB 15.24 KB 15.24 KB NODE_DEV
react-dom-unstable-fizz.node.development.js -0.2% -0.4% 3.96 KB 3.95 KB 1.52 KB 1.52 KB NODE_DEV
react-dom-server.browser.production.min.js 0.0% -0.0% 19.93 KB 19.93 KB 7.39 KB 7.38 KB UMD_PROD

react-server

File Filesize Diff Gzip Diff Prev Size Current Size Prev Gzip Current Gzip ENV
react-server-flight.development.js +96.8% +71.5% 5.24 KB 10.31 KB 1.92 KB 3.3 KB NODE_DEV
react-server-flight.production.min.js 🔺+105.7% 🔺+75.1% 1.39 KB 2.85 KB 751 B 1.28 KB NODE_PROD
react-server.development.js -0.3% -0.7% 4.83 KB 4.82 KB 1.77 KB 1.76 KB NODE_DEV
react-server.production.min.js 0.0% 🔺+0.2% 1.2 KB 1.2 KB 664 B 665 B NODE_PROD

react-flight

File Filesize Diff Gzip Diff Prev Size Current Size Prev Gzip Current Gzip ENV
react-flight.development.js +91.4% +60.7% 4.25 KB 8.13 KB 1.66 KB 2.67 KB NODE_DEV
react-flight.production.min.js 🔺+77.0% 🔺+71.3% 1.41 KB 2.49 KB 701 B 1.17 KB NODE_PROD

Generated by 🚫 dangerJS against 387c233

@sizebot

This comment has been minimized.

Copy link

sizebot commented Nov 6, 2019

Size changes (experimental)

ReactDOM: size: 0.0%, gzip: -0.0%

Details of bundled changes.

Comparing: 62ef250...387c233

react-dom

File Filesize Diff Gzip Diff Prev Size Current Size Prev Gzip Current Gzip ENV
react-dom.profiling.min.js 0.0% 0.0% 123.54 KB 123.54 KB 38.79 KB 38.79 KB NODE_PROFILING
react-dom-server.browser.development.js 0.0% 0.0% 140.37 KB 140.37 KB 36.87 KB 36.87 KB UMD_DEV
react-dom-unstable-flight-server.browser.development.js +109.8% +71.0% 4.45 KB 9.34 KB 1.79 KB 3.07 KB UMD_DEV
react-dom-server.browser.production.min.js 0.0% -0.0% 20.39 KB 20.39 KB 7.48 KB 7.48 KB UMD_PROD
react-dom-unstable-flight-server.browser.production.min.js 🔺+114.0% 🔺+77.5% 1.33 KB 2.85 KB 770 B 1.33 KB UMD_PROD
react-dom-test-utils.development.js 0.0% 0.0% 56.27 KB 56.27 KB 15.58 KB 15.58 KB UMD_DEV
react-dom-unstable-fizz.browser.development.js 0.0% -0.1% 3.88 KB 3.88 KB 1.55 KB 1.55 KB UMD_DEV
react-dom-unstable-flight-client.development.js +80.1% +62.2% 4.84 KB 8.72 KB 1.6 KB 2.6 KB UMD_DEV
react-dom-test-utils.production.min.js 0.0% 0.0% 11.18 KB 11.18 KB 4.15 KB 4.15 KB UMD_PROD
react-dom-unstable-flight-client.production.min.js 🔺+61.7% 🔺+57.4% 1.79 KB 2.89 KB 875 B 1.34 KB UMD_PROD
ReactDOMServer-dev.js 0.0% 0.0% 139.64 KB 139.64 KB 35.41 KB 35.41 KB FB_WWW_DEV
react-dom-unstable-fizz.browser.development.js 0.0% -0.1% 3.71 KB 3.71 KB 1.5 KB 1.5 KB NODE_DEV
react-dom-unstable-flight-client.development.js +83.1% +64.4% 4.67 KB 8.54 KB 1.55 KB 2.55 KB NODE_DEV
react-dom-test-utils.production.min.js 0.0% 0.0% 10.95 KB 10.95 KB 4.09 KB 4.09 KB NODE_PROD
react-dom-unstable-fizz.browser.production.min.js 0.0% 🔺+0.2% 1.05 KB 1.05 KB 642 B 643 B NODE_PROD
react-dom-unstable-flight-client.production.min.js 🔺+67.5% 🔺+64.1% 1.63 KB 2.72 KB 802 B 1.29 KB NODE_PROD
react-dom.development.js 0.0% 0.0% 951.45 KB 951.45 KB 215.02 KB 215.02 KB UMD_DEV
react-dom.production.min.js 0.0% 0.0% 119.57 KB 119.57 KB 38.35 KB 38.35 KB UMD_PROD
react-dom.profiling.min.js 0.0% 0.0% 123.25 KB 123.25 KB 39.45 KB 39.45 KB UMD_PROFILING
ReactDOMFizzServer-dev.js -0.2% -0.7% 3.92 KB 3.91 KB 1.5 KB 1.49 KB FB_WWW_DEV
react-dom.development.js 0.0% 0.0% 945.55 KB 945.55 KB 213.43 KB 213.43 KB NODE_DEV
react-dom-server.node.development.js 0.0% -0.0% 137.41 KB 137.41 KB 36.09 KB 36.09 KB NODE_DEV
react-dom-unstable-flight-server.node.development.js +112.6% +76.4% 4.51 KB 9.58 KB 1.79 KB 3.15 KB NODE_DEV
react-dom-unstable-flight-server.node.production.min.js 🔺+127.1% 🔺+79.5% 1.2 KB 2.72 KB 722 B 1.27 KB NODE_PROD
ReactFlightDOMClient-dev.js +81.9% +63.7% 4.64 KB 8.45 KB 1.54 KB 2.51 KB FB_WWW_DEV
react-dom-unstable-flight-server.browser.development.js +115.1% +73.5% 4.25 KB 9.13 KB 1.74 KB 3.02 KB NODE_DEV
ReactFlightDOMClient-prod.js 🔺+95.2% 🔺+77.3% 3.26 KB 6.36 KB 1.04 KB 1.84 KB FB_WWW_PROD
react-dom-server.browser.production.min.js 0.0% 0.0% 20.31 KB 20.31 KB 7.46 KB 7.46 KB NODE_PROD
react-dom-unstable-flight-server.browser.production.min.js 🔺+134.8% 🔺+88.2% 1.13 KB 2.65 KB 688 B 1.26 KB NODE_PROD
react-dom-unstable-native-dependencies.development.js 0.0% 0.0% 60.14 KB 60.14 KB 15.8 KB 15.8 KB UMD_DEV
ReactDOM-dev.js 0.0% 0.0% 973.77 KB 973.77 KB 215.92 KB 215.92 KB FB_WWW_DEV
ReactFlightDOMServer-dev.js +115.0% +79.3% 4.44 KB 9.55 KB 1.75 KB 3.13 KB FB_WWW_DEV
react-dom-unstable-fizz.node.development.js -0.2% -0.4% 3.97 KB 3.96 KB 1.53 KB 1.53 KB NODE_DEV
ReactFlightDOMServer-prod.js 🔺+147.7% 🔺+88.2% 2.32 KB 5.73 KB 940 B 1.73 KB FB_WWW_PROD
ReactDOM-profiling.js 0.0% 0.0% 402.33 KB 402.33 KB 73.42 KB 73.42 KB FB_WWW_PROFILING
react-dom-unstable-native-dependencies.production.min.js 0.0% 0.0% 10.48 KB 10.48 KB 3.58 KB 3.58 KB NODE_PROD
react-dom-unstable-fizz.node.production.min.js 0.0% 🔺+0.1% 1.12 KB 1.12 KB 676 B 677 B NODE_PROD

react-server

File Filesize Diff Gzip Diff Prev Size Current Size Prev Gzip Current Gzip ENV
react-server-flight.development.js +96.6% +71.3% 5.25 KB 10.32 KB 1.93 KB 3.31 KB NODE_DEV
react-server-flight.production.min.js 🔺+104.7% 🔺+74.3% 1.4 KB 2.86 KB 759 B 1.29 KB NODE_PROD
react-server.development.js -0.3% -0.7% 4.85 KB 4.83 KB 1.78 KB 1.77 KB NODE_DEV
react-server.production.min.js 0.0% 🔺+0.1% 1.22 KB 1.22 KB 672 B 673 B NODE_PROD

react-flight

File Filesize Diff Gzip Diff Prev Size Current Size Prev Gzip Current Gzip ENV
react-flight.development.js +91.1% +60.1% 4.26 KB 8.14 KB 1.67 KB 2.68 KB NODE_DEV
react-flight.production.min.js 🔺+76.3% 🔺+70.5% 1.42 KB 2.5 KB 709 B 1.18 KB NODE_PROD

Generated by 🚫 dangerJS against 387c233

@gaearon
gaearon approved these changes Nov 6, 2019
Copy link
Member

gaearon left a comment

Looks good. Want to add tests?

x.then(ping, ping);
return;
} else {
// This errored, we need to serialize this error to the

This comment has been minimized.

Copy link
@gaearon

gaearon Nov 6, 2019

Member

to the...?

This comment has been minimized.

Copy link
@sebmarkbage

sebmarkbage Nov 6, 2019

Author Member

thing

@sebmarkbage sebmarkbage merged commit dee0304 into facebook:master Nov 6, 2019
21 checks passed
21 checks passed
ci/circleci: build Your tests passed on CircleCI!
Details
ci/circleci: build_experimental Your tests passed on CircleCI!
Details
ci/circleci: flow Your tests passed on CircleCI!
Details
ci/circleci: lint Your tests passed on CircleCI!
Details
ci/circleci: lint_build Your tests passed on CircleCI!
Details
ci/circleci: process_artifacts Your tests passed on CircleCI!
Details
ci/circleci: process_artifacts_experimental Your tests passed on CircleCI!
Details
ci/circleci: setup Your tests passed on CircleCI!
Details
ci/circleci: sizebot Your tests passed on CircleCI!
Details
ci/circleci: sizebot_experimental Your tests passed on CircleCI!
Details
ci/circleci: test_build Your tests passed on CircleCI!
Details
ci/circleci: test_build_devtools Your tests passed on CircleCI!
Details
ci/circleci: test_build_experimental Your tests passed on CircleCI!
Details
ci/circleci: test_build_prod Your tests passed on CircleCI!
Details
ci/circleci: test_build_prod_experimental Your tests passed on CircleCI!
Details
ci/circleci: test_dom_fixtures Your tests passed on CircleCI!
Details
ci/circleci: test_source Your tests passed on CircleCI!
Details
ci/circleci: test_source_experimental Your tests passed on CircleCI!
Details
ci/circleci: test_source_persistent Your tests passed on CircleCI!
Details
ci/circleci: test_source_prod Your tests passed on CircleCI!
Details
ci/codesandbox Building packages succeeded.
Details
@gaearon

This comment has been minimized.

Copy link
Member

gaearon commented Nov 6, 2019

If connection dies, how do I implement a Retry button?

@sebmarkbage

This comment has been minimized.

Copy link
Member Author

sebmarkbage commented Nov 6, 2019

Error boundary and do the request from the root again.

@gaearon

This comment has been minimized.

Copy link
Member

gaearon commented Nov 6, 2019

Let me rephrase the tests question. Do you want me to write tests? 😄

@gaearon

This comment has been minimized.

Copy link
Member

gaearon commented Nov 6, 2019

I can also just make an app..

@sebmarkbage

This comment has been minimized.

Copy link
Member Author

sebmarkbage commented Nov 6, 2019

If you want to write tests that would be great. Like the suspending and error cases.

@gaearon

This comment has been minimized.

Copy link
Member

gaearon commented Nov 6, 2019

Cool, I'll do that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
4 participants
You can’t perform that action at this time.