You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
So I haven't given much credence to this, beyond listing some of the stuff we could possibly use with this. I will try to find some concrete examples of how this can make Hapi better.
The first is that "Top-Level await" will enable simpler code examples in docs and tutorials, as any time the framework needs to be initialized, a wrapper method is currently used to encapsulate the async logic. Eg. the example function here:
"Optional chaining" can simplify existing code wherever we use the pattern object && object.property. This can in most cases be rewritten as the more succinct object?.property. Eg. here:
"Private class methods" allows us to hide methods from public objects in a simple to use manner.
This means we can better control the public API and plugins can no longer use such private APIs. Eg. we don't risk the private response._header() being called outside of our control.
"Nullish coalescing" is especially useful when extracting default values from passed options and can often work better than the || operator that is frequently used for this.
Eg. here is an obvious example, where it would actually fix a weird inconsistency when the timeout is 0:
options.timeout=options.timeout||5000;// Default timeout to 5 seconds
=>
options.timeout=options.timeout??5000;
But this is a tricky change, as the "" and false values would no longer use the default value, but be passed on as-is. This should not be a problem when called from Typescript, but regular JS user might (inadvertently) rely on it.
Btw, the above can be even better written as this, where it would completely skip the assignment when there is a value supplied:
options.timeout??=5000;
This is a minor optimization, and potentially avoids a thrown exception when the supplied value is not writable.
I believe Eran already used private class methods somewhere in the org already.
No, only private instance fields, which is supported in node 12 but was still not fully part of ES spec when we started using it.
Btw, I would guess that private class methods can allow (slightly) more efficient interpretation / compiled code, since V8 can rely on that the methods never changes.
No, only private instance fields, which is supported in node 12 but was still not fully part of ES spec when we started using it.
Yeah you're right, my bad. I read your initial comment too fast. 😅
Btw, I would guess that private class methods can allow (slightly) more efficient interpretation / compiled code, since V8 can rely on that the methods never changes.
I added AbortSignal to the list. It seems like a promising way to simplify / unify aborting async code.
This is not only interesting for simplifying internal processing, but also to extend the hapi API itself. Eg. h could include a new aborted property, which a handler can pass along to node API calls:
Then if a client closes the request before the payload has been fully delivered, hapi can trigger the h.aborted signal, and automatically cause the read to immediately stop (rather than pointlessly continuing to completion).
Reacted by Devin Stewart, devin ivy, Jonas Pauthier and Jonathan Samines
I did not mention ESM modules. While I think hapi should definitely support these (for user plugins, when imported, and for testing in Lab), I don't think there is an advantage to convert all the implementation to use it.
The place where it makes most sense, is for modules that are likely to be used browsers. It would enable eg. much of Hoek to be imported directly without transpiling.
We should however consider how to best interoperate with it. Eg. by removing default exports in public API's.
I believe ESM may merit a thread of its own. But I personally would like to see hapi provide proper ESM support, and also would like to see it remain written in CJS.
Most of this can be converted internally without any user-facing changes and essentially only require an updated minimum version of node. Then the actual implementation can be sorted along the way.
There are however a few of the features that could require breaking changes to implement, and would therefore best be included in the release that changes to require node 14. These are:
ESM (revising exports from public APIs).
Private class methods (technically it shouldn't, but there are likely code that depends on the current semi-private methods).
AbortSignal support (depending on whether it makes sense to break existing APIs).
As such, any work on this should probably focus on the above.
Activity
kanongil commentedon Aug 28, 2021
So I haven't given much credence to this, beyond listing some of the stuff we could possibly use with this. I will try to find some concrete examples of how this can make Hapi better.
The first is that "Top-Level
await" will enable simpler code examples in docs and tutorials, as any time the framework needs to be initialized, a wrapper method is currently used to encapsulate theasynclogic. Eg. theexamplefunction here:hapi/API.md
Lines 1365 to 1390 in c2107e9
With top-Level
await, this wrapper can be removed, making the code easier to follow.Feel free to come up with other examples where the new features can help.
kanongil commentedon Aug 28, 2021
"Optional chaining" can simplify existing code wherever we use the pattern
object && object.property. This can in most cases be rewritten as the more succinctobject?.property. Eg. here:hapi/lib/core.js
Line 607 in c2107e9
kanongil commentedon Aug 28, 2021
"Private class methods" allows us to hide methods from public objects in a simple to use manner.
This means we can better control the public API and plugins can no longer use such private APIs. Eg. we don't risk the private
response._header()being called outside of our control.kanongil commentedon Aug 28, 2021
"Nullish coalescing" is especially useful when extracting default values from passed options and can often work better than the
||operator that is frequently used for this.Eg. here is an obvious example, where it would actually fix a weird inconsistency when the timeout is
0:hapi/lib/core.js
Line 395 in c2107e9
=>
But this is a tricky change, as the
""andfalsevalues would no longer use the default value, but be passed on as-is. This should not be a problem when called from Typescript, but regular JS user might (inadvertently) rely on it.Btw, the above can be even better written as this, where it would completely skip the assignment when there is a value supplied:This is a minor optimization, and potentially avoids a thrown exception when the supplied value is not writable.Edit: The ??= syntax requires node v16.
kanongil commentedon Aug 28, 2021
stream.pipeline()could probably be used to simplify the custom pipelining code here:hapi/lib/transmit.js
Lines 359 to 377 in c2107e9
Edit: while it can make the code simpler, it will also require extra processing since
stream.pipeline()is very complex and support lots of use-cases.Nargonath commentedon Aug 28, 2021
Thanks for the examples Gil.
I believe Eran already used private class methods somewhere in the org already.
kanongil commentedon Aug 28, 2021
No, only private instance fields, which is supported in node 12 but was still not fully part of ES spec when we started using it.
Btw, I would guess that private class methods can allow (slightly) more efficient interpretation / compiled code, since V8 can rely on that the methods never changes.
Nargonath commentedon Aug 30, 2021
Yeah you're right, my bad. I read your initial comment too fast. 😅
That would make sense indeed.
kanongil commentedon Sep 20, 2021
I added
AbortSignalto the list. It seems like a promising way to simplify / unify aborting async code.This is not only interesting for simplifying internal processing, but also to extend the hapi API itself. Eg.
hcould include a newabortedproperty, which a handler can pass along to node API calls:Then if a client closes the request before the payload has been fully delivered, hapi can trigger the
h.abortedsignal, and automatically cause the read to immediately stop (rather than pointlessly continuing to completion).devinivy commentedon Sep 20, 2021
Very cool, thanks for surfacing this.
devinivy commentedon Oct 8, 2021
Another one: we should move to checking
res.writableEndedrather thanres.finished.kanongil commentedon Oct 8, 2021
I did not mention ESM modules. While I think hapi should definitely support these (for user plugins, when imported, and for testing in Lab), I don't think there is an advantage to convert all the implementation to use it.
The place where it makes most sense, is for modules that are likely to be used browsers. It would enable eg. much of Hoek to be imported directly without transpiling.
We should however consider how to best interoperate with it. Eg. by removing default exports in public API's.
devinivy commentedon Oct 8, 2021
I believe ESM may merit a thread of its own. But I personally would like to see hapi provide proper ESM support, and also would like to see it remain written in CJS.
kanongil commentedon Oct 8, 2021
So how to tackle this?
Most of this can be converted internally without any user-facing changes and essentially only require an updated minimum version of node. Then the actual implementation can be sorted along the way.
There are however a few of the features that could require breaking changes to implement, and would therefore best be included in the release that changes to require node 14. These are:
As such, any work on this should probably focus on the above.
devinivy commentedon Nov 7, 2022
Resolved with v21 #4386