kit
kit copied to clipboard
Allowing regular expressions as arguments in the "depends" function for load functions
Describe the problem
I have to use regular expressions in depends
to invalidate certain load functions by calling the invalidate(urlWithPattern => condition(urlWithPattern))
function. Sometimes urls passed to depends
have parameters and I don't want to specify the whole url, or cannot write the full pathname, because it's dynamic. However, I have to decode them each time from the string urlWithPattern which is automatically encoded when passing them to depends. Could there be an option to pass regular expressions to the depends function? It seems logical given that there are dynamic urls everywhere.
Describe the proposed solution
Allow instances of the class RegExp
as arguments to depends
instead of just strings.
Alternatives considered
Using decodeURI, see my hack below.
Importance
nice to have
Additional Information
My current hack is
export const smartInvalidate = async (absoluteOrRelativeUrl: string): Promise<void> => {
const fullUrl = urlForSvelteFetch(absoluteOrRelativeUrl);
await invalidate((loadUrlPattern: URL) => {
const decoded = urlForSvelteFetch(
decodeURI(loadUrlPattern.toString())
);
const regex = new RegExp(`${escapeUrl(decoded)}$`);
const matches = fullUrl.match(regex);
const condition = (matches && matches.length > 0) ?? false;
return condition;
});
}
What would this give you that the current way of passing a function wouldn't give you? What you describe as a hack is a valid way of doing things to me (I think you can simplify this to just using .href
for getting the string btw), and from looking at your function body it sounds like you need more capabilities than a simple regex either way.
How would your current solution look like if you had the regex capability?
It would save me the decodeURI
call, but I can also just do it with this current function.
Do you mean I could change decodeURI(loadUrlPattern.toString())
to loadUrlPattern.href
? I am afraid that that is undefined for me. I also have to decode the regex if it would be defined.
Can you give a concrete example where the decodeURI/href things is necessary? Like "depends('x:y')
followed by smartInvalidate('z')
"
For example, while parsing a form endpoint response, I do this
if (!text) {
throw Error(`Response was undefined.`);
}
try {
response = deserialize(text) as ActionResult<ServerDataOutput>;
} catch (e) {
throw Error(`Problem deserializing ${text.slice(0, 100)}`);
}
// fetching.done(`Done fetching`);
const result: ActionResult<ServerDataOutput> = response;
if (result.type === 'success' || (!('type' in result) && fetchResponse.ok)) {
await smartInvalidate(rURL);
return { serverDataOutput: result.data ?? (result as unknown as ServerDataOutput) };
} else if (result.type === 'redirect') {
const newUrl = relativeURL(result.location);
await goto(newUrl, { keepFocus: true, noScroll: true });
await smartInvalidate(rURL);
return {};
} else if (result.type === 'failure') {
await smartInvalidate(rURL);
return {
processorError: new Error(`Form failure with status ${result.status}.`),
serverDataOutput: result.data as ServerDataOutput
};
} else {
I have declared dependencies in load functions using
export function regexToPathname(regex: RegExp, root: URL) {
// Remove the starting and ending slashes.
const regexString = regex.source;
// Encode special characters in the regex to create a valid URL pathname.
const isAbsolute = regex.source.startsWith('^\\/');
if (isAbsolute) {
return '/regex/' + encodeURIComponent(regexString);
} else if (regex.source.startsWith('\\?')) {
return (
'/regex/' +
encodeURIComponent(
`${stringToRegex(decodeURIComponent(root.pathname.replace(/\/$/, '')))}${regexString}`
)
);
} else {
return (
'/regex/' +
encodeURIComponent(
`${stringToRegex(decodeURIComponent(root.pathname.replace(/\/$/, '')))}\\/${regexString}`
)
);
}
}
Then i use this with
import { regexToPathname } from '$lib/browser/http';
import type { PageServerLoad } from './$types';
export const load: PageServerLoad = async ({ depends, params, url }) => {
depends(
...[
new RegExp(
`^\\/${params.projectLabel}\\/${params.processIndex}\\/files/upload\\/[^/]+\\?\\/upload`
),
new RegExp(
`[^/]+\\?\\/deleteFile`
)
].map((r) => regexToPathname(r, url))
);
///
}
But this feels like an unnecessary hack. If regexes would be directly accepted (opposed to strings) this would not be necessary.
strings passed to depends
must be valid URL strings as its converted to an URL object. Passing regexes would make all this more complicated, and we would need to ship additional code in the client for everybody when only a fraction of people would use this. I'm therefore closing this issue - creating helper functions building upon depends
and invalidate
is the way to go.
For SvelteKit 2 we might in general rethink whether or not really makes sense for depends
/invalidate
to deal with URLs instead of just plain strings.