-
-
Notifications
You must be signed in to change notification settings - Fork 4.3k
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
SSR Actions #4375
Comments
Sounded easy, but is complexer than I initially thought:
|
Just wanted to chime in and say I think there is a strong use-case for setting SSR attributes in an action. I'm not sure that the main focus for users of actions is dom access, but rather abstractions of element logic that can be shared, and that can certainly apply on the server. I know a bunch of my most commonly used actions would really benefit from being able to render certain attributes in an SSR context, outside of dom access. For me at least the answers to the questions raised (1. and 2.) are simple — behave in the same way as if the attribute was written in markup. If some hydrated code clobbers the attribute the action set, so be it, that's up to both implementer and user to work around. I don't think it has to be very nuanced or complex in terms of behaviour. I'd just love a way to be able to do something like this function action(...) {
// clientside only stuff
return {
// SSR-able attribute map
attributes() {
return {
attr: val
}
}
}
} And have those attributes rendered in an SSR context as well as clientside. |
Highly relevant use case mentioned in another issue on spreading events, where this feature would've helped with:
Originally posted by @LeanderG in #5112 (comment) Event spreading seems to be achieved through actions in Svelte. For this use case I believe it would be a good in-between until spreadable events + props and dynamic elements ( |
Hello,
I think it's not possible like that, because the function expects an DOM node as the first parameter. But after some try, it seem possible to add a complementary SSR function in order to populate the attributes of the node. function action(node, args) {
// clientside only stuff
}
action.SRR = function(attrs, args) {
// serverside stuff here
// attrs is an object containing the tag attributes...
} The only small problem is that I think the SSR function will be exported in the client code (even if it will not be used). I tried a quick prototype and it's seem to work pretty well. <script lang="ts">
type ActionArgs = { title: string };
function close(node: HTMLButtonElement, args: ActionArgs) {
node.classList.add("close-button");
node.setAttribute("aria-label", args.title);
// other Client side stuff
}
close.SSR = function(attrs: Record<string,any>, args: ActionArgs) {
attrs.class = (attrs.class||'') + ' close-button'
attrs['aria-label'] = args.title;
}
</script>
<button use:close={{title:"Close"}} class="btn">X</button> Will generate the following HTML on SSR/prerendering : <button class="btn close-button" aria-label="Close">X</button> I think some things can still be improved :
My prototype is available here : https://github.com/adiguba/svelte/tree/ssr-actions |
Interesting! Has there any update regarding this feature request? |
No, and I'm still not fully clear on the benefits to be honest. Can't we just use spread attributes here? |
I'm disconnected from this problem now and thus' have less of an opinion, but for me Svelte 5 ergonomics make this less of an issue since spreading events was solved. And probably other stuff too. I'd love to hear more about the issues others get solved by potentially having this implemented. But this still serves as a good example: Ergonomics are so bad that it actually makes sense to make a preprocessor for an action lib's usecase, even if all the attributes can be controlled by the action. P.S. Still love that if you build using an action lib, you don't lose access to directives e.g. animate and such. A big part of component libs in Svelte being a pain in the past was having to reinvent element directives and conveniences, especially when you're like a headless lib where almost all your components mirror an element 1:1. It seems with Svelte 5, things like event directives (modifers?) have been removed in favor of making them functions. It does bring into question if other directives should be given the same consideration though |
For reusable state/behavior, we have 3 ways to go, and none is really satisfying:
Example.
Example.
Example SSR actions would improve the situation greatly by allowing to set the attributes in ssr, set the behavior on mount, and have a great DX. Bonus point if we can access some kind of virtual node in ssr allowing to grab and set attributes on the parent! const createTab= (node: HTMLButtonElement, active:boolean)=>{
if(node.ssr){
node.role="tab";
node.ariaSelected = `${active}`
node.parent.role = "tablist"; <- that's cool!
} else {
node.addEventListener("click", ()=>...)
}
} |
Although I'd love to see something like this from Svelte core, I somewhat agree with Rich & <script lang="ts">
import type { HTMLAttributes } from 'svelte/elements';
let { class: cls, onmouseenter, onmouseleave, ...rest }: HTMLAttributes<HTMLDivElement> = $props();
// `$props` is arguably much cleaner than `export let ...`
// and events are now just regular attributes
</script>
<div class={cls} {onmouseenter} {onmouseleave} {...rest}></div> Having action supports SSR will introduce not only complexity to the codebase but also ambiguity to ssr/client boundary and conflict between attributes added from multiple places. People will likely try to do client-only things in ssr-only area, and vice versa. That being said, i often find myself asking the same question as OP did and want some way to extract reusable action coupled with a bit of static attribute setup. So i spawn up a preprocessor-based lib named @svelte-put/preaction as a proof-of-concept in user-land. Here is the idea: <script>
import { make, apply } from '@svelte-put/preaction';
const doStuff = make((initialParam) => {
// do some stuff, as if ran at top-level script tag
return {
action: (node, param) => {
// regular Svelte action
},
attributes: {
// "static" attribute setup
'data-initial-param': initialParam,
},
};
});
</script>
<div use:apply={doStuff('argument'))} class="my-class"></div> Which will transform to this: <script>
// same stuff above
const __preaction = doStuff('argument');
</script>
<div {...__preaction.attributes} use:__preaction.action={'argument'} class="my-class"></div> CAUTION: proof-of-concept only do not use in production, and only tested with Svelte 5 |
Is your feature request related to a problem? Please describe.
It would be nice if actions could output attributes in SSR context.
Describe the solution you'd like
How important is this feature to you?
Somewhat. It's just an idea i had, that could play well with something like svelte-css-vars. Imagine that svelte-css-vars could return
{ style: '--color: red' }
when rendered on the server.The text was updated successfully, but these errors were encountered: