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

Create configuration option to limit data-sveltekit-fetched blobs during SSR #13363

Open
grant-h opened this issue Jan 23, 2025 · 5 comments
Open
Labels
feature / enhancement New feature or request

Comments

@grant-h
Copy link

grant-h commented Jan 23, 2025

Describe the problem

I am writing a web application that uses adapter-static. It involves a very large inventory file with thousands of elements. This file must be loaded before the application can work properly. Hence, I load it in the top-level +layout.ts using fetch. This means all child pages will have the data-sveltekit-fetched script blob included inline after SSR. This makes prerendered pages very large, leading to an exported website exceeding GB in size.

I am about to resort to either maintaining a private SvelteKit fork or adding a post-SSR transformation pass to strip these blobs from the final HTML as this is a blocker for achieving small pre-rendered pages.

Describe the proposed solution

Make an SvelteKit configuration option (svelte.config.js),+page.ts variable, or other to prevent some or all pages from including these blobs during pre-rendering.

Alternatives considered

No response

Importance

would make my life easier

Additional Information

No response

@eltigerchino
Copy link
Member

Have you tried fetching the data in the load function without using SvelteKit's fetch? Using the native fetch implementation will not inline the response into the HTML. Similarly, you could perform the fetch in an onMount() call in the +layout.svelte script tags.

@grant-h
Copy link
Author

grant-h commented Jan 23, 2025

Have you tried fetching the data in the load function without using SvelteKit's fetch? Using the native fetch implementation will not inline the response into the HTML. Similarly, you could perform the fetch in an onMount() call in the +layout.svelte script tags.

I ran into issues with using the native fetch for SSR due to: Cannot use relative URL with global fetch. It directed me to use event.fetch, which is the server-side hook of fetch. This works great both on client and server, but with the added issue of fetch caching. To fetch relative URLs, it looks like I need to create my own wrapper around fetch which prepends the event.url.origin field only during server-side fetches (I'm only fetching static assets). But this only works using the dev server, not builds (I get fetch failed ECONNREFUSED).

Using onMount would prevent proper SSR for the data that is needed to render the page if I am not mistaken.

So I have resorted to an HTML transforming hook in hooks.server.ts.

import type { Handle } from '@sveltejs/kit';

export const handle: Handle = async ({ event, resolve }) => {
    const response = await resolve(event, {
        transformPageChunk: ({ html, done }) => {
            if (done) {
                html = html.replace(/<script.*data-sveltekit-fetched.*<\/script>/g, "");
            }
            return html
        }
    });

    return response;
};

This is a bit wasteful to generate large HTML, strip inlined fetches and then re-emit the HTML, so a better option would be preferred.

@eltigerchino
Copy link
Member

What about fetching the data in a server load function? If your server load is prerendered, the data isn't inlined into the HTML.

@grant-h
Copy link
Author

grant-h commented Jan 24, 2025

What about fetching the data in a server load function? If your server load is prerendered, the data isn't inlined into the HTML.

I tried this, but now the data is pre-rendered into the bottom <script> under the data variable. I can't pass back non POJO types via the server load function returns, even in a static context (I have a class that manages inventory resource state and caching).

An additional problem is that SSR is very slow. I have a page like /detail/[slug]. And slug can be one of thousands of items. I want a prerendered version of each page. I attempt to initialize all the expensive loading and processing of inventory JSON files in the top-level +layout.ts using fetch, which causes the data to be inlined. No problem, I can remove this data using the above hook. But now generating each slug specific page also takes a very long time, as if +layout.ts is being re-run for each individual item, instead of once for the group of items. Is there a way to profile the SvelteKit SSR process to figure out the component bottle-neck? I've tried vite-plugin-inspect during dev and build, but it doesn't appear to give details on individually rendered HTML pages.

@eltigerchino
Copy link
Member

But now generating each slug specific page also takes a very long time, as if +layout.ts is being re-run for each individual item, instead of once for the group of items.

That's because each page is prerendered by invoking the server respond function, so all load functions re-run.

const response = await server.respond(new Request(config.prerender.origin + encoded), {

Can you share more about the large inventory file you're fetching? Is it possible to import it as an asset through Vite?

@eltigerchino eltigerchino added the feature / enhancement New feature or request label Jan 24, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature / enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants