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

fix(ai/rsc): New createStreamableUI implementation #1825

Merged
merged 12 commits into from
Jun 11, 2024
Merged

fix(ai/rsc): New createStreamableUI implementation #1825

merged 12 commits into from
Jun 11, 2024

Conversation

shuding
Copy link
Member

@shuding shuding commented Jun 4, 2024

Instead of using nested Suspense wrappers, I realized that we can just pass a streamable value of the UI into a Client Component and do the update on the client. This has a lot of advantages, and the major one is that we no longer need to express the UI update logic declaratively via JSX, and React will be able to correctly reconcile the component updates.

Since createStreamableUI also powers streamUI, that API will benefit from this too.

Also moved unit tests of streamUI to E2E tests.

Closes #1850.

@shuding shuding changed the title WIP: New createStreamableUI impl fix(ai/rsc): New createStreamableUI implementation Jun 11, 2024
@shuding shuding marked this pull request as ready for review June 11, 2024 13:49
currentPatchValue = undefined;
currentValue = value;
} else {
throw new Error(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have introduced dedicated errors so we can have error pages for troubleshooting, e.g. https://sdk.vercel.ai/docs/troubleshooting/ai-sdk-errors/ai-invalid-data-content-error

do you think it's worth adding dedicated errors here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes! We should convert all the common errors to dedicated error codes, with clear example and explanation.

Comment on lines 385 to 398
} else if (isValidElement(currentValue)) {
if (typeof value === 'string' || isValidElement(value)) {
currentPatchValue = [1, value];
(currentValue as ReactElement) = (
<>
{currentValue}
{value}
</>
);
} else {
throw new Error(
`.append(): The value type can't be appended to the stream. Received: ${typeof value}`,
);
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the check for !(string | validelement) is duplicated 3 times. you could invert the if-else and pull it out

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah part of it is to bypass TS checks as it's not that intelligent to handle the branching if typeof value is stored as a variable.

export async function streamableUI() {
const streamable = createStreamableUI();
(async () => {
await sleep();
await sleep(10);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how stable is the test with this low timeout?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Quite stable. Ran this many times on local/CI and the result is consistent. Here it could be sleep(0) and it will still work, but decided to add a small delay just in case one layer (Next.js, RSC, React, browser) batches the chunks.

@shuding shuding merged commit 3cabf07 into main Jun 11, 2024
7 checks passed
@shuding shuding deleted the shu/ciuo branch June 11, 2024 16:14
@gaetansnl
Copy link

@shuding @lgrammel Hello, is it expected to change the behavior of createStreamableUI ? Seems that mixing append and update doesn't work anymore, Update override the appended elements ?

@shuding
Copy link
Member Author

shuding commented Jun 12, 2024

@gaetansnl That sounds like a bug to me and I'll take a look!

@lgrammel
Copy link
Collaborator

Reverted because of #1933 and #1969

@salmenus
Copy link

Perfect timing ! I need it for my RSC / gen ui library 🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Client Component in streamUI keeps re-mounting
5 participants