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: use ReadableStream for response object if deno #10495

Merged
merged 11 commits into from Apr 1, 2024

Conversation

satyarohith
Copy link
Contributor

@satyarohith satyarohith commented Mar 19, 2024

This patch allows astro to run in node-compat mode in Deno. Deno doesn't support construction of response from async iterables in node-compat mode so we need to fallback to use ReadableStream.

Copy link

changeset-bot bot commented Mar 19, 2024

🦋 Changeset detected

Latest commit: d2538dc

The changes in this PR will be included in the next version bump.

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions github-actions bot added the pkg: astro Related to the core `astro` package (scope) label Mar 19, 2024
@satyarohith satyarohith marked this pull request as ready for review March 19, 2024 15:50
satyarohith and others added 2 commits March 19, 2024 21:22
Co-authored-by: Divy Srivastava <dj.srivastava23@gmail.com>
@Princesseuh
Copy link
Member

Is there an upstream issue on Deno for supporting the initial feature? I don't necessarily feel super good about having a hack for it when it's really a missing feature on their end.

@lucacasonato
Copy link
Contributor

@Princesseuh This is not a missing feature in Deno. This is a spec deviation from Node (and now Bun), that has no specified behaviour in the Fetch spec. The feature that Astro uses would not work in browsers for example - because it is a non standard extension of Fetch. Deno is spec compliant in not accepting async iterables as body arguments to Request/Response.

There is discussion about if this behaviour should be removed from Node in lieu of a spec: nodejs/node#49551. This is the issue discussing possible addition of this behaviour to the Fetch spec whatwg/fetch#1291, but it has not had any traction.

@Princesseuh
Copy link
Member

Princesseuh commented Mar 19, 2024

@Princesseuh This is not a missing feature in Deno. This is a spec deviation from Node (and now Bun), that has no specified behaviour in the Fetch spec. The feature that Astro uses would not work in browsers for example - because it is a non standard extension of Fetch. Deno is spec compliant in not accepting async iterables as body arguments to Request/Response.

There is discussion about if this behaviour should be removed from Node in lieu of a spec: nodejs/node#49551. This is the issue discussing possible addition of this behaviour to the Fetch spec whatwg/fetch#1291, but it has not had any traction.

Oh, interesting. Apologies, I didn't know the context, figured that since it worked in Node and Bun added it for compatibility with it, it was a standard thing, should've known better.

Is there anything Astro could do to better respect the spec and at the same time not regress to the previous state? We added that code for performance reasons previously, as ReadableStream is slow in Node. cc @matthewp

@lucacasonato
Copy link
Contributor

@Princesseuh No worries at all - I suggest you feature test for this specific behaviour, like so: #10495 (comment). You are then shielded from Node un-shipping this behaviour, and if it is added to the spec in the future, this will also just work in runtimes that support this behaviour. If you want to clean up the code here, you can always create the async iterator, and then pass it to Response directly if the feature check succeeds, and if not pass ReadableStream.from(asyncIterator) instead.

@satyarohith satyarohith changed the title fix: use ReadableStream for response object if deno fix: fallback to ReadableStream if asyncIterator is not supported in Response Mar 20, 2024
Copy link
Member

@bluwy bluwy left a comment

Choose a reason for hiding this comment

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

The reason we use async iterables for node is because we're suggested that it's faster in node (#9614). We're not using it because the platform supports it. Is it faster in Deno too?

Otherwise I think the original plan that checks for Deno globally to avoid it in Deno is more correct, but it is unfortunate that we can't check if we're really really running in node.

@matthewp
Copy link
Contributor

Love that this uses feature detection, thanks! Just need a changeset pnpm changeset, a patch seems appropriate here.

@matthewp
Copy link
Contributor

@bluwy I don't understand, what problem do you see with the feature detection mechanism in this PR?

@bluwy
Copy link
Member

bluwy commented Mar 21, 2024

I think it isn't the intention we use async iterables in the first place. It's non-standard for node, so we'd only allow to use it there. We wouldn't want to start using async iterables if other runtimes also implement this IMO. The feature detection also has a slightly higher startup cost.

@satyarohith
Copy link
Contributor Author

@bluwy I'm happy to revert back to Deno specific check if you prefer it.

@bluwy
Copy link
Member

bluwy commented Mar 21, 2024

I'd wait for Matthew to respond first before doing that 😅 Maybe I'm missing something from his point of view and we could iron that out first.

@lucacasonato
Copy link
Contributor

You could also always wrap the async iterable using ReadableStream.from() before passing it to Response. According to Matteo from the Node project, this has identical performance characteristics: nodejs/node#49551 (comment)

@bluwy
Copy link
Member

bluwy commented Mar 21, 2024

Thanks for the link, I remember Matteo (on Twitter) suggested using async iterables because it was faster, but if it's not, then maybe we should remove the async iterable code altogether 🤔

About ReadableStream.from(), since we already have a renderToReadableStream method, I think it would be better to use that directly instead. We could keep the async iterable code and use ReadableStream.from(), but we don't have a use for async iterators then.

@lucacasonato
Copy link
Contributor

I'm not saying a ReadableStream with custom "start" and "pull" hooks is identical in performance to the new Response(asyncIterable). I'm saying Matteo suggests that new Response(asyncIterable) is identical in performance to new Response(ReadableStream.from(asyncIterable)). Doing the latter is additionally spec compliant.

@matthewp
Copy link
Contributor

I'd wait for Matthew to respond first before doing that 😅 Maybe I'm missing something from his point of view and we could iron that out first.

No, I understand your point of view. Basically let's not assume that it's always better to use AsyncIterator and be very deliberate about it. +1 from me on that idea.

@lilnasy
Copy link
Contributor

lilnasy commented Mar 21, 2024

Doing the latter is additionally spec compliant.

It is also exactly what undici does with the async iterable in the Response constructor - it gets turned into a ReadableStream first order of business. I would expect performance on node to be identical.

@bluwy
Copy link
Member

bluwy commented Mar 22, 2024

In that case, let's stick with the explicit deno check for now then. It looks like ReadableSteam.from is only supported from node 20.6 so we can't quite use it yet.

We could check if the API exists and use it, so renderToAsyncIterable + ReadableStream.from where possible, but I don't think we have to implement it in this PR (but I don't mind if we do).

@satyarohith satyarohith changed the title fix: fallback to ReadableStream if asyncIterator is not supported in Response fix: use ReadableStream for response object if deno Mar 22, 2024
@satyarohith satyarohith requested a review from bluwy March 22, 2024 04:20
@satyarohith
Copy link
Contributor Author

@bluwy I appreciate if you can review the PR. I reverted back to the original Deno check.

@satyarohith
Copy link
Contributor Author

@bluwy are there any issues blocking this PR? I'm happy to address them. It would be great if we can land this PR :)

Copy link
Member

@bluwy bluwy left a comment

Choose a reason for hiding this comment

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

Sorry I've been away last week. LGTM 👍

@bluwy bluwy merged commit 046d69d into withastro:main Apr 1, 2024
13 checks passed
@astrobot-houston astrobot-houston mentioned this pull request Apr 1, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
pkg: astro Related to the core `astro` package (scope)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

7 participants