Router primitives can be only used in side a Route.

I have a route that has a setup like this:
export const route = {
load: () => getRouteData(),
};

const getRouteData = cache(async () => {
'use server';
const location = useLocation();

/* Here I use the location pathname to do some logic, checks a cookie for an existing password hash, validates it with DB, and redirects to an auth page via return redirect(redirectUrl); if need be. */
export const route = {
load: () => getRouteData(),
};

const getRouteData = cache(async () => {
'use server';
const location = useLocation();

/* Here I use the location pathname to do some logic, checks a cookie for an existing password hash, validates it with DB, and redirects to an auth page via return redirect(redirectUrl); if need be. */
The auth page has a little form password popup, verifies the password , and saves a hash into a cookie, with the following pseudocode:
const actionSubmission = useSubmission(isPasswordValidated);

return (<form action={isPasswordValidated} method="post">)
const actionSubmission = useSubmission(isPasswordValidated);

return (<form action={isPasswordValidated} method="post">)
Once the right password is entered, the auth page action does a return redirect(redirectUrl); back to the original page... but then I get the attached error. If I console log, I can see that it dies on the line where I have the const location = useLocation(); line in my getRouteData function. If I manually refresh the page, it loads fine. This worked fine in my initial build of the app prior to rc0 ๐Ÿ˜
No description
25 Replies
peerreynders
peerreyndersโ€ข8mo ago
This part
/* ... checks a cookie for an existing password hash, validates it with DB, and redirects to an auth page via return redirect(redirectUrl); if need be. */
/* ... checks a cookie for an existing password hash, validates it with DB, and redirects to an auth page via return redirect(redirectUrl); if need be. */
sounds like it should be done in onRequest in middleware. There you can stuff the result into in RequestEvent.locals or even return the redirect. That way everything should be ready by the time it hits your "use server" section and you can obtain it via getRequestEvent.
SolidStart Release Candidate Documentation
SolidStart Release Candidate Documentation
Early release documentation and resources for SolidStart Release Candidate
SolidStart Release Candidate Documentation
SolidStart Release Candidate Documentation
Early release documentation and resources for SolidStart Release Candidate
peerreynders
peerreyndersโ€ข8mo ago
Unfortunately this example is a bit in a rough state (this was post Beta 2 but pre-RC) but it uses some of the concepts I was alluding to: https://github.com/peerreynders/solid-start-demo-login/blob/restart/src/middleware.ts If I were to clean it up now I'd be able to ditch the direct cookie manipulation and just use the h3 session api
GitHub
solid-start-demo-login/src/middleware.ts at restart ยท peerreynders/...
SolidStart seed project with simple user management for demonstration projects. - peerreynders/solid-start-demo-login
Handle Session - h3
Remember your users using a session.
Some Call Me Tim
Some Call Me TimOPโ€ข8mo ago
Yeah, middleware could be a solution, but this setup is only needed for this one route.. and it was working fine until the upgrade to rc0. The fact that the initial Route A works fine unless it's coming from a redirect from another route is the main issue, middleware won't cure that unfortunately. oooh, just looking at your example, I don't know of sendRedirect, is that a thing still?
peerreynders
peerreyndersโ€ข8mo ago
In middleware you have direct access to the URL, no useLocation required.
Some Call Me Tim
Some Call Me TimOPโ€ข8mo ago
Maybe I'm just redirecting incorrectly with this version. Gotcha, will dive into the sample code, thanks ๐Ÿ˜„
peerreynders
peerreyndersโ€ข8mo ago
Middleware can terminate the handler chain by returning, i.e. redirect.
Some Call Me Tim
Some Call Me TimOPโ€ข8mo ago
Still wondering why useLocation works fine unless the page is loaded from a redirect though.... router magic.
peerreynders
peerreyndersโ€ข8mo ago
Full disclosure: nitro recommends against prematurely terminating the handler chain but they are not clear on why https://nitro.unjs.io/guide/routing#simple-middleware
Server Routes - Nitro
Nitro support filesystem routing to automatically map files to h3 routes.
Some Call Me Tim
Some Call Me TimOPโ€ข8mo ago
urgg, always something. What could go wrong? ๐Ÿ˜‰
peerreynders
peerreyndersโ€ข8mo ago
I just think it's philosophical and judged as harder to maintain. But in the face of streaming SSR middleware is the best place to manipulate cookies and return redirects.
Some Call Me Tim
Some Call Me TimOPโ€ข8mo ago
Claude ai says "The reason why it is not recommended to use the returned value from middleware as the response in Nitro (or any other middleware-based system) is that it can lead to potential issues and can make the code more difficult to maintain and understand. In a typical middleware system, the middleware functions are intended to perform specific tasks or operations before or after the main request handling logic. These tasks can include authentication, logging, parsing request data, modifying the request or response objects, and so on. The middleware functions are not meant to directly handle the main request or generate the final response. When you return a value from a middleware function, it essentially short-circuits the request pipeline, and the remaining middleware functions and the main request handler will not be executed. This can lead to several problems:" "Violation of Separation of Concerns: By allowing middleware to generate the final response, you are mixing concerns and responsibilities. Middleware functions should focus on their specific tasks, while the main request handler should be responsible for generating the response. Difficulty in Maintaining and Understanding the Flow: If middleware functions can generate responses, it becomes harder to understand the flow of the application and the order in which different parts of the code are executed. This can make the codebase more difficult to maintain and debug. Potential for Inconsistent Behavior: If multiple middleware functions can generate responses, it can lead to inconsistent behavior and unexpected outcomes, especially if there are dependencies between middleware functions or if they rely on certain data or state that may not be properly set up due to short-circuiting. Lack of Centralized Error Handling: When middleware functions generate responses, it becomes harder to implement centralized error handling and response formatting, as errors and responses may be generated at different points in the request pipeline. Instead of returning a response from middleware, it is recommended to follow the intended pattern of middleware systems, which is to perform specific tasks within the middleware functions and then pass control to the next middleware or the main request handler. This approach promotes better separation of concerns, maintainability, and a more predictable flow of execution. If you need to generate a response early in the request pipeline (e.g., for authentication failures, rate limiting, or other early-exit scenarios), it is generally better to use the provided mechanisms within the middleware system, such as calling a dedicated response generation function or throwing an error that can be caught and handled by a centralized error handler." So yeah, more for maintenance and behavior than anything technical
peerreynders
peerreyndersโ€ข8mo ago
unless the page is loaded from a redirect thought
I suspect the route preload is creating a race condition. useLocation only works once the Router component is "fully informed" and likely the cache point is being hit before that is the case. Pure conjecture at this point though โ€ฆ
Some Call Me Tim
Some Call Me TimOPโ€ข8mo ago
but a great idea, and something to look into... nope ๐Ÿ™‚ Removed cache() altogether and still get the same thing.
peerreynders
peerreyndersโ€ข8mo ago
This comment makes me think we are going to see more "best practices" about moving functionality into middleware going forward. https://github.com/nksaraf/vinxi/issues/208#issuecomment-1964625870
GitHub
Error: Cannot set headers after they are sent to the client ยท Issue...
It seems it's not possible to set the session at present in my solid-start project. All request are returning: Error: Cannot set headers after they are sent to the client at ServerResponse.setH...
peerreynders
peerreyndersโ€ข8mo ago
I was thinking the preload is the problem
Some Call Me Tim
Some Call Me TimOPโ€ข8mo ago
in the page that dies, I am deferring it via const routeData = createAsync(() => getRouteData(), { deferStream: true }); So I was assuming it'd 'wait'.
peerreynders
peerreyndersโ€ข8mo ago
That just defers the response during SSR.
Some Call Me Tim
Some Call Me TimOPโ€ข8mo ago
right, but doesn't that halt everything until the server code is all executed/finalized? Regardless, it looks like I need to do some middleware for this one route.
peerreynders
peerreyndersโ€ข8mo ago
That wouldn't resolve any timing issues "at the front "
Some Call Me Tim
Some Call Me TimOPโ€ข8mo ago
yeah next question is how can I only run middleware for 1 route block? i.e. I've got 100 routes, but only need it to run on this block of 3 which are nested in a ViewersRoute component .
<Route path="/" component={ViewersRoute} >
<Route path="/tg/:roomId" component={ViewerRoute} />
<Route path="/v/:slug" component={ViewerRoute} />
<Route path="/v/:slug/abc" component={TextViewer} />
</Route>
<Route path="/" component={ViewersRoute} >
<Route path="/tg/:roomId" component={ViewerRoute} />
<Route path="/v/:slug" component={ViewerRoute} />
<Route path="/v/:slug/abc" component={TextViewer} />
</Route>
docs look like it's only a global thing, and I don't really want to do a url path check for every single request?
peerreynders
peerreyndersโ€ข8mo ago
You simply look at the relevant part of the URL. If there is nothing to do you let it go.
Some Call Me Tim
Some Call Me TimOPโ€ข8mo ago
right, that's what I was worried about. Okay, url path check for every single request it is.
peerreynders
peerreyndersโ€ข8mo ago
Chain of Responsibility
Chain of Responsibility is a behavioral design pattern that lets you pass requests along a chain of handlers. Upon receiving a request, each handler decides either to process the request or to pass it to the next handler in the chain.
peerreynders
peerreyndersโ€ข8mo ago
GitHub
vinxi/packages/vinxi/runtime/http.js at 6f3d81beabc8cf003c0095eb9b4...
The Full Stack JavaScript SDK. Contribute to nksaraf/vinxi development by creating an account on GitHub.
Response - h3
Utilities to send response headers and data
Some Call Me Tim
Some Call Me TimOPโ€ข8mo ago
Sooo, the actual issue was that on the redirect from Component B back to Component A, the routeData function is called using an internal _server url, which didn't have access to use useLocation(). I also found getRequestEvent();, so I was able to find out what caused the issue with useLocation(), but also able to get rid of useLocation() ๐Ÿ™‚
Want results from more Discord servers?
Add your server