-
-
Notifications
You must be signed in to change notification settings - Fork 362
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
Deep Integration with Vue Router #9
Comments
Yes
I'm not that familiar with Vue Router but AFAIK you wouldn't do that. I believe with Vue Router you define a mapping between URLs and Vue components. This means that you would completely bypass vite-plugin-ssr's routing. Whether that's what you want depends on what you want to achieve. Why do you want to use Vue Router instead of vite-plugin-ssr's routing? |
Ideally they'd work in tandem. Vue Router handling client-side navigation would prevent having to fetch the full payload for subsequent pages, allow for client-side transition effects, etc BTW I've built similar integrations in the past. Happy to help if I understand a little more about how your plugin functions |
I don't encourage using Vue Router with SSR as it complexifies the architecture of your app. That said: https://github.com/brillout/vite-plugin-ssr/tree/master/examples/vue-router I've a plan for smooth transitions that is simpler than Vue Router. The idea is to use the "pjax" technique, some prior art:
The big advantage here is that we get smooth transitions without complexifying the user's app architecture. A founding principle of vite-plugin-ssr is to provide a scalable architecture.
Yes, that would be lovely. How does my plan sound to you? |
I do understand where you're coming from here in trying to avoid complexity. In my view, an application should have a single source of truth for routing information, shared between server and client. Since you have your own abstraction for routing here, I can see why you'd be hesitant to integrate directly with any specific routing library - you are trying to use your routing abstraction as the source of truth and avoid having two routing solutions in play. I do worry though that by baking in any of these solutions you've linked, you'd actually be sacrificing some flexibility with regard to client side routing. A solution using these tools might be nice for some use cases, but there are features in proprietary client-side routers that you cannot recreate (nested views, dynamic routes, component navigation guards to name a few more vue router features you'd be shutting out). I wonder if there is a solution somewhere along the lines of exposing your routing information in a way that it could be consumed and integrated with other routers for use in the client. The way Nuxt works is it generates vue routes from the page-based routing abstraction, then uses those generated routes in the client. That's obviously far too coupled to make sense given your design philosophy, but I wonder if the user (or an additional integration plugin) could take your routes and transform them to a proprietary router's expected format? |
If I can see a use case for it not covered by other simpler solutions, then I'll implement it.
With that pjax solution, you'll be able to do that in a simple way: you simply define a paramterized route, e.g. The pjax solution is optional. It's actually not going to be included by default. Because server-side routing is the more classical way of doing things and it's what most web devs expect. It's easier to reason about. It doesn't suffer long-living user sessions that make deploying new versions more painful (these "Please reload your browser, a new version is available" toaster notification are a non-negligable degradation). Only a fraction of web dev demand smooth transitions. Most product managers don't care about smooth transitions. That said, there are situations where smooth transitions are needed, hence the pjax solution I want to implement. The pjax solution is optional so you don't have to use it if you don't want to. I do care about the premise that vite-plugin-ssr is compatible with the entire ecosystem. That's why I'm showing the integration examples React Router and Vue Router: it should become clear that vite-plugin-ssr is usable with anything. Even though I don't see Vue Router or React Router to have that much of a place (zero place?) in an SSR world. I'm more than happy to be shown a use case where a pjax solution would be an inferior solution to Vue Router.
See answer above.
The pjax solution will do that.
I'm not sure what you mean here but note that you can do route guards with route functions. // /pages/admin.page.route.js
// Route functions allow us to implement advanced routing such as route guards.
export default ({ url, contextProps }) => {
if (url==='/admin' && contextProps.user.isAdmin) {
return { match: true }
}
}
I'd be happy to hear them out. |
Someone who is used to working with Vue Router expects to be able to compose components within each other under nested router views. What you're describing sounds like it would, within the Vue ecosystem, constitute a workaround / hack / wheel recreation. https://next.router.vuejs.org/guide/essentials/nested-routes.html#nested-routes
Really? It will do this? https://next.router.vuejs.org/guide/advanced/dynamic-routing.html
This is what an in-component guard looks like: https://next.router.vuejs.org/guide/advanced/navigation-guards.html#in-component-guards The ssr routing guards only run on the server, right? In some cases it is useful to have navigation guards that run on the client, and as indicated by the link above, it is standard practice to do this within the component itself.
IMO that's not really a decision your plugin should be making for your users (nor do you seem to have, based on the fact that your docs do reference client-side routers). As you've clearly set out to do, do one thing, do it well - server side render the things. If your users want to rely entirely on SSR payloads, great, but there is a common more hybrid approach where the initial payload is SS-rendered or pre-generated, and the client takes over from there. I see no great reason why you shouldn't support both. The only piece that's missing is clear usage guidelines for making that hybrid approach work with the abstractions you provide (and potentially other things making such an approach feasible, not really sure without digging in). If you wouldn't mind giving me some time, I'll mess around with your plugin and see if I can come up with a recommendation for a usage example with Vue Router, and whether there is additional data I'd suggest exposing to make that integration more feasible. |
You're right. In afterthought, no matter the arguments of server-side routing VS Vue Router, if your wish is to use Vue Router then I should accommodate for that. Even just habits is a good and valid reason to use Vue Router.
Sounds good.
Ok. I'll implement what you need. |
FYI Client-side Routing landed: https://github.com/brillout/vite-plugin-ssr#import--useClientRouter--from-vite-plugin-ssrclientrouter I'd be more than happy to offer a lower-level API to accommodate for a deep Vue Router integration. Looking forward to see how this is going to look like. |
Cool! I just took a look - looks good for use cases that don't require a proprietary router. Regarding the lower level APIs that might be needed to perform a proprietary router integration, here's what I'm thinking: expose a function usable in the client (to be called in _default.page.client.js or similar) that would return all routes in the application, pre-parsed via
I should be able to call [
{ id: "about", tokens: ["about"] },
{ id: "news", tokens: ["news", { name: "news", prefix: "/", suffix: "", pattern: "[^\\/#\\?]+?", modifier: "" }] }
] Why am I suggesting a parsed route rather than a routing string? With the token list, one should be able to re-compile a route specification in another router's supported path syntax, whatever that may be (in the case of Vue, it's similar to pathToRegexp but with some subtle changes) without having to load in the full pathToRegexp dependency in the client. With this information, I believe one could construct a list of routes for the client router that matches up with the routing performed by the server assuming that they come pre-sorted in order of priority. It would also be useful to be able to get a page by id. I think the function const routes = await getParsedRoutes()
app.use(createRouter({
routes: routes.map(route => ({
path: convertTokensToVueRouterPath(route.tokens),
component: async () => (await getPageById(route.id)).Page //handling of contextProps omitted for now
}))
})) Does that all make sense? Do you see any problems with this? The only thing I haven't quite thought through yet is how features like nested routes might be supported... going to give that some more thought. |
Yes that makes sense. One question: can Also I'd be totally ok with changing from the current pathToRegexp implementation and replace it with Vue Router's one. That would get us quicker to an MVP. Later we can implement Btw the other two GitHub issues are fixed in |
I have been working on a POC vue router integration - stand by for more thoughts on this topic |
Exciting. Let me know if there is anything you need from me, or if you have questions about the code (some parts are not source code reader friendly yet). |
One thing I already know will be useful - exposing |
One thing we could do is that you change We create a draft PR and take it from there. Comfy to discuss and collaborate on code changes. We can create the draft PR as soon as there is even only one LOC change. Would that work for you? |
Yeah sounds good |
So on this topic, I'm wondering if there is a way we can structure this such that the route resolution is overridable / not necessarily coupled to any routing solution. Default (pathToRegExp-based) Routing
export default "/:myPathToRegexParam?"
/**
* @param {(string|Function)[]} routes The accumulation of all my.page.route.js files and / or static page identifiers in an unsorted state.
* @returns {(string|Function)[]} Sorted routes
*/
export function sortRoutes(routes) {
/* apply default, common-sense sort */
return routes.sort(defaultRouteSort);
}
/**
* @param {(string|Function)[]} routes Pre-sorted routes to be matched
* @returns {string|Function|null} A single matching route
*/
export function matchRoutes(routes, url) {
return routes
.sort(defaultRouteSort)
.find(route => matchRouteByPathToRegexp(route, url));
} Vue Router integration
export default { path: "/:myVueRouterParam?" } /* "component" property is assumed to be the current page component
and will be auto-populated. Though, presumably "children" property could be filled in here...? But then how do
child components get auto-populated? */
export function sortRoutes(routes) {
/* Apply common-sense sort on Vue Router routes. Perhaps this in turn should expose application-specific overrides as the default sort might not always work as needed... */
return routes.sort(sortRoutesByVueRouterPriority);
}
/**
* @param {(string|Function)[]} routes Pre-sorted routes to be matched
* @returns {string|Function|null} A single matching route
*/
export async function matchRoutes(routes, url) {
const router = createRouter({
routes,
history: createMemoryHistory()
});
await router.push(url);
return router.currentRoute; // Not 100% accurate, basically pseudo-code.
} Something like this could allow for overriding the default routing mechanism with something more specific to an application's routing needs. As indicated above, I don't really know where this code goes since it seems like it would be application-specific, not page-specific, and currently there is not a place where the plugin stores application-specific overrides. I wonder if the plugin could expose some sort of plugin interface for overriding behavior like this (while also making those overrides portable)? E.g. a "@vite-plugin-ssr/vue-router" plugin could package this integration up for easy consumption. One other topic / thought here that is a little bit of a tangent, but just throwing it out there as something to think about: Vue Router has a concept of nested routes, which correspond to composed router views. E.g. EDIT: Forgot to mention that the solution I'm offering above makes it trivial to integrate with Vue Router in the client. As long as we have a way of fetching those routes (pre-sorted by the server / prerender process), it can instantiate a vue router instance similar to the above example. Route transformation (as I had previously suggested) would no longer be needed as they are authored in the Vue Router format within the application both on server and client. |
I'd suggest we proceed like the following:
Allowing to replace the Filesystem Routing with a custom one should AFAICT fairly easy to achieve. export { useCustomFilesytemRouter }
let customFilesystemRouter;
function useCustomFilesytemRouter(_customRouter) {
customFilesystemRouter = _customRouter
}
function routeWithFileSystem() {
if( customFilesystemRouter ) {
// ...
} else {
useDefaultFilesystemRouter()
}
} As for accessing all routes of all pages: check out the Any other questions about the We can discuss things like plugin architecture later. (I've a couple of ideas here but let's first do quick & dirty hacks to improve |
OK sounds good. I'll start putting a PR together. |
One big disadvantage of ssr-only routes is that an application "hangs" while data is being fetched by ssr engine. I'm seeing queries to |
This is why pre-rendering is great! |
We will tentatively merge the PR in 1-2 weeks. |
Gryphon was busy but we should be able to finish up the PR fairly easy (thanks to the new |
@gryphonmyers I guess you got caught up with high prio things :-) If you'd be interested in working on this, I'd be more than happy to do it together 😊 Warm regards from the Vike team. Removing the |
Yes sorry for the delay. I will have more time for this mid November
…On Wed, Oct 20, 2021, 12:03 PM Romuald Brillout ***@***.***> wrote:
@gryphonmyers <https://github.com/gryphonmyers> I guess you got caught up
with high prio things :-) If you'd be interested in working on this, I'd be
more than happy to do it together 😊 Warm regards from the Vike team.
Removing the being-worked-on label in the meantime.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#9 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/ABMENWEFHK6EJOLSY3RYSPTUH4HBLANCNFSM4ZICU36Q>
.
|
No worries; re-labeling as |
What is the state now? |
I'm not aware of any updates. That said, I believe |
In the react-router example there's mention of this issue potentially allowing deep integration with react router and the docs state that it should be possible now using the onBeforeRoute function. Would it be possible to see the example updated to use it or is there an existing demo? |
@sebasptsch To my knowledge, no one has tried to deeply integrate React Router before. So you're entering uncharted territory here. On vite-plugin-ssr's side |
Closing, see https://vite-plugin-ssr.com/vue-router-and-react-router. Bottom line being:
|
The docs indicate that this plugin can be used with Vue Router for client-side routing, but does not go into any more detail. Is an example planned for this integration? Curious to see how one might get the file-based routing information into Vue Router routes.
The text was updated successfully, but these errors were encountered: