Replies: 5 comments 4 replies
-
Highly in support as it feels like a very natural place to handle authorization together with layout groups. Either this or layout group wide hooks with the already discussed |
Beta Was this translation helpful? Give feedback.
-
Throwing my quick thought into here: A different way to tackle this could be to tell a load function to
import { ignore } from "@sveltejs/kit";
export function load({ changes, depends }) {
depends(true); // always rerun
if (changes.url) { // called due to url change
throw ignore(); // skip this load function, signal to reuse the old version
}
// ..
} |
Beta Was this translation helpful? Give feedback.
-
Is there a current workaround where one could somewhat achieve this? 🤞 |
Beta Was this translation helpful? Give feedback.
-
It feels like I could also create this behavior through auth logic in the hooks.server.js handle function. Perhaps an enhancement which would aid in writing the handle function would be to expose what layout groups/layouts are being accessed for a specific request. this would allow writing something like this in the handle function: if(request.route.groups.contains(”auth”){
handleGuard(request);
} or something like: if(request.route.layouts.auth){
handleGuard(request);
} Would it make sense to provide something like this even if the decision is made to go forward with either the |
Beta Was this translation helpful? Give feedback.
-
I agree we should have something like For example, if you have query parameters for sorting data and pagination, but you don't want to rerun the DB query inside of Guard would work in this scenario - but in a different way. The same way Svelte has To get around this in a situation where some search params changing needed a new DB call and some didn't (they all invalidate and cause load to rerun), I had to store the result of my load function as a memoized variable and "short circuit" to prevent calling the DB again. Without that memoization - I can't end load early because I have no way of persisting the data that's already there from the last load. I'd love it if we could figure out a way to address both of these needs. interface ExploreParams {
tags?: string;
status?: string;
page?: number;
sort?: string;
}
let urlParams: ExploreParams;
let memoizedResult: any = null;
const triggerReload = ['tags', 'status']
const preventLoad = (url: URL): boolean => {
if(url.search === '') return false
if(memoizedResult === null) return false;
for (const key of url.searchParams.keys()) {
if(triggerReload.includes(key)) {
if(urlParams[key] === undefined) return false;
if(urlParams[key] !== url.searchParams.get(key)) return false;
}
}
return true;
}
export const load = (async ({ url } : {url: URL}) => {
if(preventLoad(url)) return memoizedResult;
if(url.search && urlParams === undefined) urlParams = Object.fromEntries(url.searchParams)
// ...Database Query ...
let result = {
meta: {
title: 'Title',
description: 'Page description'
},
tags,
results
}
memoizedResult = result; // saves a copy every time a new result is generated
return result;
}) satisfies PageServerLoad; |
Beta Was this translation helpful? Give feedback.
-
tldr; Allow
layout.server.js
to export aguard
function in addition toload
. This would decouple business logic (e.g. auth) from from data caching, provide a clearer developer experience and encourage secure practices.Related issues: #6315, #6731
Current benefits of
layout.server.js
+page.server.js
Disadvantages/Needs Work
+page.server.js
.In order to cache data the client router must have the power to decide, on its own, whether or not to fetch data from the tree.
But the semantics of the current system may tempt the developer to place important logic in the
+layout.server.js
tree, leaving leaf nodes unprotected. This is an easy mistake to make:+layout.server.js
will be called for every request just like+page.server.js
. (It isn't.)My current way around this is to secure each route as necessary in
+page.server.js
, which always runs. This is reasonable, and it may be better to simply say this is the correct approach, rather than adding a feature to the API. But I think that would throw a couple of babies (caching, less boilerplate) out with the bathwater.General Considerations
Proposed Solution
Each
+layout.server.js
exports one or both of:load
function as it is now.guard
function:Some notes about this:
guard
+load
pair (i.e., appearing in the same+layout.server.js
) as a unit. Within that unitguard
runs beforeload
, in series. But many of these pairs can be run concurrently, just as manyload
s are now.load
,guard
isn't part of a tree. It only applies to its layout node.guard
, if present, runs on every request the layout node applies to.load
, as now, runs on the first request and after cache invalidation.guard
takes only aRequestEvent
, and returnsvoid
. This is deliberate, to decouple it from data collection and caching.guard
runs are enforced on the server. The only thing the client router has to know is whether a particular layout node is guarded or not, so it can decide what needs to be re-fetched.load
gets run. This would only happen if the node had been invalidated.Here's a chart:
+layout.server.js
exports...guard
+load
guard
runs, thenload
runsguard
runsguard
runs, thenload
runsguard
onlyguard
runsguard
runsguard
runsload
onlyload
runsload
runsDX Benefits
guard
export is entirely optional. I think it would be a non-breaking change.Other Options
event.alwaysRun()
flag that one would call inload
. Described here.hooks.server.js
Add support for per-directory+hooks.server.js
route files #6731I'm pretty sure that
guard
is doable without too much work (famous last words.) Anyway let me know what you think and thanks for reading!Beta Was this translation helpful? Give feedback.
All reactions