sveltejs / kit

web development, streamlined
https://kit.svelte.dev
MIT License
17.73k stars 1.75k forks source link

Sveltekit server components #12123

Open CurltureCo opened 2 weeks ago

CurltureCo commented 2 weeks ago

Describe the problem

Until now I havnt found a way to get server components similar to htmx. One possible way is to put components in the router and use them like a route but it produces a large response size.

Describe the proposed solution

This javascript function kindof works first I setup a components directory in routes, for example "routes/components/counter/+page.svelte" then when I want to update the component I pass the destination element and request path to the function below and it successfully grabs the component and places it

    const getComponent = async (componentPath: string, target: HTMLElement) => {
        const res = await fetch(componentPath, {
            method: 'GET',
            headers: {
                // html content type
                'Content-Type': 'text/html'
            }
        });
        if (res.ok) {
            const parser = new DOMParser();
            const doc = parser.parseFromString(await res.text(), 'text/html');

            const scriptTags = doc.getElementsByTagName('script');
            const lastScriptTag = scriptTags[scriptTags.length - 1]!;

            const script = document.createElement('script');
            script.innerHTML = lastScriptTag.innerHTML;

            const teleportContent = () => {
                div.querySelector('#svelte-announcer')?.remove();
                target.replaceWith(...div.childNodes);
            };

            // create a div in body to hold the component with id of the component path
            const div = document.createElement('div');
            div.id = componentPath;
            document.body.appendChild(div);

            // wait for the component to be hydrated
            const observer = new MutationObserver((mutations) => {
                if (mutations[0].removedNodes.length > 0) {
                    observer.disconnect();
                    teleportContent();
                }
            });
            observer.observe(div, { childList: true });

            div.appendChild(script);
            div.remove();
        } else {
            console.error('Fetch error:', res.status);
        }
    };

The issue with this is that although it does support the use of stores and imports in the component (which is great!) it produces a large response for a relatively small component. It would be great if the sveltekit team would add a more native and convenient solution that produces a smaller request. There are many directions this could go, I would love to see any of them happen.

Alternatives considered

I also tried setting htmx up, it worked but it was very clunky and not ideal for sveltekit in my opinion

How do I get it going? do npm install htmx.org && npm install -D typed-htmx

add this script in your app.html head

<script src="node_modules/htmx.org/dist/htmx.min.js"></script>

add this in tsconfig

"strict": true,
"types": [ "typed-htmx" ]

and this inside global in app.d.ts

declare namespace svelteHTML {
    interface HTMLAttributes extends HtmxAttributes {}
}

Importance

nice to have

Additional Information

No response

brunnerh commented 2 weeks ago

Why do you want or need this?

MahmoodKhalil57 commented 2 weeks ago

Why do you want or need this?

There are a lot of reasons to want to get html as a response https://htmx.org/essays/when-to-use-hypermedia/

For me it is to make specific components accessible only under authentication like +page.server.ts

edit: I am OP from a different account