Skip to content
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

proposal: handlePageData hook #12940

Open
konstantinov90 opened this issue Nov 3, 2024 · 2 comments · May be fixed by #13014
Open

proposal: handlePageData hook #12940

konstantinov90 opened this issue Nov 3, 2024 · 2 comments · May be fixed by #13014
Labels
feature request New feature or request

Comments

@konstantinov90
Copy link

Describe the problem

Sveltekit allows to implement multilayered data loading, which is great!

Now suppose you have some complex logic inside your load-functions, which you would like to test. While you might use unit tests, or you might use something like playwright, sometimes you just want to get that $page.data prop to test it

In my case we have a very complex inverted data loading scheme (in our organisation we have a convention to use NodeJs ONLY for rendering - so no backend calls from nodejs), where GO "frontend" calls svelte-kit service twice - first to get the "data-loading schema" (a bunch of graphql-queries), then loading this data, and second - POST request to svelte-kit again with that very data to render the page

Making svelte-kit to render page on POST-request and feeding it data on load-functions is not a problem, we use our adapter and async_hooks for it, but getting "data-loading schema" from load-functions turned out to be quite difficult. New hook solves this problem

Describe the proposed solution

I propose a new handlePageData, which should be called inside render_page function just before rendering

Patch might look just something like this

diff --git a/node_modules/@sveltejs/kit/src/exports/public.d.ts b/node_modules/@sveltejs/kit/src/exports/public.d.ts
index 861aff3..d7e7852 100644
--- a/node_modules/@sveltejs/kit/src/exports/public.d.ts
+++ b/node_modules/@sveltejs/kit/src/exports/public.d.ts
@@ -687,6 +687,13 @@ export type Handle = (input: {
 	resolve(event: RequestEvent, opts?: ResolveOptions): MaybePromise<Response>;
 }) => MaybePromise<Response>;
 
+
+/** docs */
+export type HandlePageData = (input: {
+	event: RequestEvent;
+	pageData: unknown;
+}) => MaybePromise<void | Response>;
+
 /**
  * The server-side [`handleError`](https://kit.svelte.dev/docs/hooks#shared-hooks-handleerror) hook runs when an unexpected error is thrown while responding to a request.
  *
diff --git a/node_modules/@sveltejs/kit/src/runtime/server/index.js b/node_modules/@sveltejs/kit/src/runtime/server/index.js
index 36cbd04..0b6f00e 100644
--- a/node_modules/@sveltejs/kit/src/runtime/server/index.js
+++ b/node_modules/@sveltejs/kit/src/runtime/server/index.js
@@ -69,6 +69,7 @@ export class Server {
 
 				this.#options.hooks = {
 					handle: module.handle || (({ event, resolve }) => resolve(event)),
+					handlePageData: module.handlePageData || (({ event, resolve }) => resolve(event)),
 					handleError: module.handleError || (({ error }) => console.error(error)),
 					handleFetch: module.handleFetch || (({ request, fetch }) => fetch(request)),
 					reroute: module.reroute || (() => {})
diff --git a/node_modules/@sveltejs/kit/src/runtime/server/page/index.js b/node_modules/@sveltejs/kit/src/runtime/server/page/index.js
index 3424c5f..1633ae4 100644
--- a/node_modules/@sveltejs/kit/src/runtime/server/page/index.js
+++ b/node_modules/@sveltejs/kit/src/runtime/server/page/index.js
@@ -281,6 +281,10 @@ export async function render_page(event, page, options, manifest, state, resolve
 			});
 		}
 
+		const hookResponse = options.hooks.handlePageData({event, pageData: compact(branch.map(b => b.data))});
+
+		if (hookResponse instanceof Response) return hookResponse;
+		
 		const ssr = get_option(nodes, 'ssr') ?? true;
 
 		return await render_response({
diff --git a/node_modules/@sveltejs/kit/src/types/internal.d.ts b/node_modules/@sveltejs/kit/src/types/internal.d.ts
index c9dbb51..cd4dce3 100644
--- a/node_modules/@sveltejs/kit/src/types/internal.d.ts
+++ b/node_modules/@sveltejs/kit/src/types/internal.d.ts
@@ -107,6 +107,7 @@ export type GetParams = (match: RegExpExecArray) => Record<string, string>;
 export interface ServerHooks {
 	handleFetch: HandleFetch;
 	handle: Handle;
+	handlePageData: HandlePageData;
 	handleError: HandleServerError;
 	reroute: Reroute;
 }

Then hook might look like this

import { type HandlePageData } from '@sveltejs/kit'

export const handlePageData: HandlePageData = function({event, pageData}) {
    if (event.request.headers.get('x-e2e-testing')) {
        return new Response(JSON.stringify(pageData), {
            headers: {
                'x-e2e-testing': 'PAGE_DATA'
            }
        });
    }
}

Alternatives considered

I considered using /__data.json route to get page data, but it only calls +page.server.ts load functions, which does not fully represents page data on render

Regarding the hook signature - first I tried to implement something like the handle hook, ((pageData: unknown, resolve: (pageData: unknown) => Response) => Response), but isolating just the pageData for this resolve function turned out to be too big of a deal

Importance

would make my life easier

Additional Information

No response

@Kapsonfire-DE
Copy link
Contributor

you can use the normal handle hook and inject your data in event.locals
create a global +layout.server.ts and put it into the data

@konstantinov90
Copy link
Author

No, I cannot, the problem is how to extract the data, not to inject it

@eltigerchino eltigerchino added the feature request New feature or request label Nov 12, 2024
@konstantinov90 konstantinov90 linked a pull request Nov 16, 2024 that will close this issue
6 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature request New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants