-
-
Notifications
You must be signed in to change notification settings - Fork 87
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
feat: viewAsync reply decorator #420
Conversation
The README after changes: https://github.com/mweberxyz/point-of-view/blob/feat/view-async/README.md |
e8e6dbe
to
28d001c
Compare
The only difference between |
28d001c
to
76e703b
Compare
c3f2905
to
112d60c
Compare
Closes fastify#394 Closes fastify#412
112d60c
to
4007699
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm
Signed-off-by: Matteo Collina <hello@matteocollina.com>
This has been sitting for awhile - anything needed to get it merged? It's semver-minor due to purely additive functionality. |
index.js
Outdated
const fakeRequest = { | ||
getHeader: () => true | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why a fake request?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's what this
is bound to in the call to asyncRender
by the old viewDecorator
on line 140 -- because viewDecorator does not have this
set to a request.
index.js
Outdated
if (minify) { | ||
promise = promise.then((result) => minify(result, globalOptions.htmlMinifierOptions)) | ||
} | ||
const promise = asyncRender.apply(fakeRequest, args) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is no need for a fakeRequest, you can use a real one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is no request in scope, it's the crux of #394 -- this is fastify.view
not reply.view
.
If it seems hacky, I can drop it and add the conditional into the calls to this.getHeader()
on line 121?
My intent here was to avoid adding a branch into the critical path of the plugin to avoid performance regression.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or I could just construct thisArg
on every request like used to happen here: 235f588#diff-e727e4bdf3657fd1d798edcd6b099d6e092f8573cba266154583a746bba0f346L857 if that's more clear/maintainable.
Same intent: avoid creating object unnecessarily in critical path for performance reasons, though in this case it would be less impactful as this would only in the critical path of fastify.view
as opposed to everything. lmk what you all prefer.
index.js
Outdated
if (!this.getHeader('Content-Type')) { | ||
this.header('Content-Type', 'text/html; charset=' + charset) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh I get what you mean now, seems a little hacky but performant I guess :)
Can you please try this instead of fakeRequest to see if it impacts performance? It could maybe have an impact if we call this method multiple times
if (!this.getHeader('Content-Type')) { | |
this.header('Content-Type', 'text/html; charset=' + charset) | |
} | |
this.header?.('Content-Type', 'text/html; charset=' + charset) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can't do that exactly because existing logic/tests ensure header is only set if not already set. Pushed something along these lines after confirming no regression is benchmarks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see, thanks for the change, it is easier to understand for me
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm
@@ -44,6 +46,7 @@ declare namespace fastifyView { | |||
root?: string; | |||
viewExt?: string; | |||
propertyName?: string; | |||
asyncPropertyName?: string; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add a test for this type? We use tsd
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ptal at most recent commit
Closes #394 and closes #412
The purpose of this PR is to implement a new reply decorator, called
viewAsync
by default.viewAsync
is similar toview
, except it does not callreply.send
on template render or error, and instead returns a promise (to be returned from the route handler and allow fastify hook chain to take over).See #394 and #412 for context. 412 will be closed by this PR, though maybe it should be revisited in the future, if the legacy
view
should be replaced withviewAsync
as the default - would be a semver-major change and would probably make most sense to coincide with a major fastify version bump.Approach
asyncRender
async functionfastify.viewAsync
decoratorasyncRender
for existingfastify.view
decoratorasyncRender
for existingreply.view
decoratorWith this PR, all exposed decorators utilize the same underlying implementation of the rendering function, so each only contains logic specific to the needs of that decorator.
Tests
Sufficient tests added to be thoroughly confident the changes work as expected. Of particular interest:
setErrorHandler
works as expectedasyncPropertyName
andpropertyName
options work as expectedfastify.view
is rendered withoutreply.locals
#394 is resolvedBenchmarks
fastify-viewAsync
, identical tofastify.js
but usesreply.viewAsync
instead ofreply.view
All within run-to-run variance (my laptop, M1 mac @ Node v20):
Docs
Cleanup, re-organize for readability, and add documentation for new decorator:
viewAsync
Providing a layout on render
to be beforeRendering the template into a variable
, so the former can reference the latter and it makes sense reading from top-to-bottomMigrating from view to viewAsync
Checklist
npm run test
andnpm run benchmark
and the Code of conduct