-
-
Notifications
You must be signed in to change notification settings - Fork 351
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
qual: make config hook types more precise #1137
Conversation
@brillout I think it is better now |
bc08dbe
to
aaecd95
Compare
@brillout does it now look more like what you had in mind? Thanks |
I'm pretty sure this is because the vike auth example +config.h.ts includes the new vike Config that I have touched, but also wants to satisty vike-react's Config, which wants to satisfy the old vike Config. In other words there is a kind of circular type dep now accross vike and vike-react. @brillout I believe we should tackle this circular dep first as this will hit us back whenever we touch the Config type. What do you think? Does that make sense to you if I start looking into this? |
Yes, exactly. If the user always extends Btw. for An interesting question is what happens when the user sets |
As for the TS error: I'm inclined to think it's a mismatch between the Config used by We set this in the root
But, if I remember correctly, this isn't recursive. |
Actually, since |
You made me realize I wanted to use Regarding Alternatively I was thinking of removing
What do you think?
In this example actually |
Yes. (I had a quick look and it does seem like pnpm is linking everything correctly, so I'm not sure why we get that TypeScript error.) |
Yes exactly. That's why we use pnpm's overrides feature instead.
I believe this wouldn't type
The example itself declares a direct dependency to Let me know if you want me to dig into that TS error. |
@brillout I found the culprit: the example has a dependency to an old Thanks for the useful pointers. Updating the PR |
Ah, indeed, I forgot to update that one. Thanks 🙏. |
👍 I'm seeing you added the type utils for the hooks 💯. Async I'm thinking whethter other hooks should be sync by default. E.g. I expect most |
I just tried and this works: type OnHydrationEnd = (pageContext: PageContextClient) => Promise<void | undefined> | void | undefined; So we indeed can remove the variants for hooks that return On the other hand, it's kinda nice to keep the convention Hm 🤔 |
Make sense, yes
Yes I like this
The problem with this is that we can't use // error TS1064: The return type of an async function or method must be the global Promise<T> type. Did you mean to write 'Promise<void>'?
const onHydrationEnd: OnHydrationEnd = async (): ReturnType<OnHydrationEnd> => {
console.log('Hydration finished; page is now interactive.')
} This is why we stopped mixing |
@@ -6,7 +6,7 @@ export default { | |||
passToClient: ['pageProps', 'title'], | |||
clientRouting: true, | |||
prefetchStaticAssets: 'viewport', | |||
onHydrationEnd, | |||
onHydrationEnd, // NOTE(aurelien): this assignment breaks if we stop supporting the sync variant |
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.
See inline comment. It seems like we're introducing a breaking change by not supporting the sync variant of void-returning hooks. So I think we shouldn't do that either.
My suggestion is that we keep OnHydrationEnd | OnHydrationEndSync
, yet from now on, as you said, we try to make examples use async variants as much as we can. What do you think?
Ah, you're right, Ok let's go with your with your suggestion. In other words, looking at the list: Guard,
GuardSync,
OnBeforePrerenderStart,
OnBeforePrerenderStartSync,
OnBeforeRender,
OnBeforeRenderSync,
OnBeforeRoute,
OnBeforeRouteSync,
OnHydrationEnd,
OnPageTransitionEnd,
OnPageTransitionStart,
OnPrerenderStart,
OnPrerenderStartSync,
OnRenderClient,
OnRenderClientSync,
OnRenderHtml,
OnRenderHtmlSync,
Route Only
Agreed. I think it's easier for the user if we keep things consistent. |
Idea: we provide I think I've a slight preference for that. Thoughts? Let me think this a bit. |
Actually, there is a caveat I think. When browsing Vike's source code, I came to the conclusion that the following hooks are sync-only: route, onPageTransitionStart, onPageTransitionEnd. The reason is that there is no |
Yes, I prefer explicit |
The route definitely can be async (its async handling may not be obvious). Let me check about |
👍 Ok let's move with that then: we can add an alias |
Fixed: 58f822b. |
Since we're explicit, I think we don't need to use async hooks in all examples. Some hooks are trivial and obviously sync: I think it's fine to use the |
@brillout I think it looks good now :) |
…mented Vike.PageContext on the boierlplates. But we can also add add a note if you want; as you wish.
…on in the future as we'll incrinsingly promote the vike-{react,vue,solid} packages). When the user uses Client Routing then the route functions are called on the server-side as well as on the client-side
A real beauty 😍 I've added a couple of commits (see the entire commit messages); let me know if you object. (I'm actually not 100% sure about my I'm 👍 for proceeding. Btw. we can already merge; we can add docs and update examples in an extra PR. Whatever works best for you. |
* | ||
* https://vike.dev/route | ||
*/ | ||
type RouteSync = (pageContext: PageContextServer | PageContextClient) => { routeParams: Record<string, 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.
This won't work unfortunately, we had this topic earlier in this PR: PageContextServer
won't be assignable to PageContextServer | PageContextClient
. It works the other way around. In other words:
(A | B) => void
is assignable to(A) => void
, but(A) => void
is not assignable to(A | B) => void
So the user won't be able to stop using client routing and create a route()
that takes only PageContextServer
as argument. I can create a TS playground to illustrate if needed.
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.
Yes I know. My idea is to tell Server Routing users to not use the Route
type. We can increasingly assume users to use Client Routing because of vike-{react,vue,solid}
.
My thinking is: users who use vike-{react,vue,solid}
are more likely to be junior-ish and it's particularly important for them to provide friendly types.
Current users who use Server Routing are "expert users"; I think it's fine to be less friendly. (Alternatively we can provide RouteWithServerRouting
, like PageContextClientWithServerRouting
.)
In a nutshell: we highly polish things for Client Routing and neglect Server Routing. (Honestly, I'm even considering deprecating Server Routing.)
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.
@brillout even an expert won't be able to perform such an assignment if they do it in +config.h.ts
, similarly to the problem I was showing here: #1137 (comment)
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.
In other words, yes if you use a +route.ts
file then you are free not to use the Route
type and no assignment type checking will be performed, true, but this won't work when directly assigning in +config.h.ts
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.
True 👍. A solution would be to use pageContext: PageContextServer
for Config['route']
(instead of setting it to RouteSync | RouteAsync
). Alternatively, we create RouteWithServerRouting
and set Config['route']
to RouteSync | RouteAsync | RouteWithServerRoutingSync | RouteWithServerRoutingAsync
. Either way is fine with me.
I know it's very ugly for Server Routing users and only slightly prettier for Client Routing users. That's how much I think we should prioritize Client Routing over Server Routing... (I'd be up for deprecating Server Routing after all).
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.
(if you agree, let's merge 🚀)
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 think you're right, the slight mismatch won't bother Server Routing users that much.
To answer your question: yes, there are slight mismatches between PageContextServer
and PageContextClient
, the most notable one is that everything is Partial
because TypeScript cannot now the value of passToClient
. (See vike/shared/types.ts
.)
Actually... I'm just realizing that PageContextClient
is only correct for Client Routing users... For Server Routing users it should actually be PageContextClientWithServerRouting
. I've just checked and PageContextBuiltInClientWithServerRouting
and PageContextBuiltInClientWithClientRouting
(that's the core diff) are quite similar though: I think this mismatch is ok.
This is actually a good example for why I'm inclined to deprecate Server Routing: in my experience the maintaince costs it adds isn't worth it.
After thinking more about it: I suggest we keep the implementation as is while we tell Server Routing users to not use these new types introduced by this PR. This clearly marks Server Routing users as second-class citizen which fits the long-term plan of encouraging users to use vike-{react,vue,solid}
while eventually deprecating Server Routing as soon it becomes too annoying to maintain.
The issues we're having with it in this PR makes me think it's a reason enough to deprecate it. I'm now inclined to think we should deprecate Server Routing before releasing v1.0.0
.
(if you agree, let's merge )
👍 Let me know if you don't object with that last comment and I'll merge.
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.
This sounds scary - aren't there valid use cases for not wanting client routing? I'll trust your guts on this
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.
(whether or not we deprecate server routing, I think this PR is good enough to be merged)
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.
While Server Routing is marginally faster on first page load (less client-side code to load), Client Routing is tremendously faster on subsequent navigation. I find this is a reason enough to recommend Client Routing over Server Routing.
Also there are use cases that only work with Client Routing (e.g. a music player that should still play music when navigating pages). That's the biggest reason why I'd always recommend using Client Routing. (You never know what use case you may need in the future.)
The idea of supporting Server Routing was neat but, in hindsight, I think it was a mistake.
All in all, I think it's worth it to deprecate it.
(all the rest looks good to me 👍) |
(We can ignore Cloudflare's CI failing: we've reached Cloudflare's free tier daily rate liming.) |
Merged 🎉 Thanks for the PR. Can't wait to release these really neat types. |
@brillout, validated with
tsc --noEmit
on the example. Is this going in the right direction? If yes I would like to:Is it OK with you?