S
SolidJS3w ago
Leal

Complex createResource management

I'm trying to write a way to handle a specific scenario where I wanted to use something like a const ws = useWebSocket(); that: - when called on the server side, initializes a WebSocket connection to another server and returns a server side wrapper to the WebSocket ~ must be waited and cached - when called on the client side, initializes a WebSocket connection to the SolidStart server and returns a client side wrapper to the WebSocket ~ must be cached - when the user session id changes, the connection must be closed if the id becomes undefined or create a new one if the id is not the same as the previous one - the wrapper contains the same functions on the server side and client side, allowing it to be used inside other resources By cached I mean using the same resource in more than a single component does not create a second connection. I know there's a package named solid-cached-resource that solves this exact problem using resources The ideal approach would be something exactly like an createResource, wich can receive a signal to refetch, stores the current fetch state (loading, error or loaded) and has a deferStream option that makes the server await until the fetch is completed but I couldn't make it work using resources due to: - the resource result is transferred to the client side for hydration, therefore the client WebSocket is not initialized - the server side data must not be transferred to the client I'm not sure if SolidStart provides a way to do this operation or if I should study the createResource source code to create something alike that allows this scenario. Any help is appreciated!
6 Replies
peerreynders
peerreynders3w ago
Websocket support is very experimental and createResource exist to handle strictly async data (to be superseded by createAsync) so the two are apples and oranges. That said it is possible to use an API route to establish server-to-client communication via SSE (example).
MDN Web Docs
Using server-sent events - Web APIs | MDN
Developing a web application that uses server-sent events is straightforward. You'll need a bit of code on the server to stream events to the front-end, but the client side code works almost identically to websockets in part of handling incoming events. This is a one-way connection, so you can't send events from a client to a server.
Leal
LealOP3w ago
Oh, SSE is something new to me! I'm going to take a look right now! But out of the scope of websockets, is it possible to make the resource fetch once in the server AND fetch once in the client? Or disable its hydration
peerreynders
peerreynders3w ago
Sounds like you could already accomplish something similar by using query which can already supply multiple components with the same data via createAsync. A server side event could then be used to revalidate a specific query to force a refetch; the resulting update would then be propagated to the components currently connected to that query. isServer can be used to differentiate server and client side behavior. Here I use it to change the initialization of a store inside context depending on where is is being initialized. For example createResource won't fetch if you use the source/fetchData variant and source returns false, null, or undefined, Just keep in mind that createResource will likely with Solid 2.0 be moved out of the core and into a community library. query/createAsync are the core replacement.
Leal
LealOP3w ago
Well, the following code still runs only once, in the server or in the client and the data is still transferred to the client if rendered by the server
import { createAsync, query } from '@solidjs/router';
import { isServer } from 'solid-js/web';
import { fetchTestClient } from './use-test.client';
import { fetchTestServer } from './use-test.server';

const TEST_RESOURCE_KEY = 'test';

const fetchTest = isServer
? fetchTestSSR
: fetchTestCSR;

const testQuery = query(
fetchTest,
TEST_RESOURCE_KEY
);

export const useTest = () =>
createAsync(() => testQuery(), { deferStream: isServer });
import { createAsync, query } from '@solidjs/router';
import { isServer } from 'solid-js/web';
import { fetchTestClient } from './use-test.client';
import { fetchTestServer } from './use-test.server';

const TEST_RESOURCE_KEY = 'test';

const fetchTest = isServer
? fetchTestSSR
: fetchTestCSR;

const testQuery = query(
fetchTest,
TEST_RESOURCE_KEY
);

export const useTest = () =>
createAsync(() => testQuery(), { deferStream: isServer });
I'll probably have to refactor half the project to remove the WebSocket, which although is experimental, was actually working fine and move to SSE. I'll probably have to think in a new solution to the problem Thank you very much for your help (again :P)!
peerreynders
peerreynders3w ago
If the web socket is already working for you then fine. Due the route being separate from the standard SolidStart UI Routes, I found that the WS was cut off from a lot of SolidStart server functionality. I got this self-contained example to work but without accessing any of the other "server stuff".
GitHub
solid-start-ws-demo/src/server/ws.ts at main · peerreynders/solid-s...
Use a websocket server within SolidStart v1. Contribute to peerreynders/solid-start-ws-demo development by creating an account on GitHub.
Leal
LealOP3w ago
I'll take this chance to learn the SSE thing, i think it can actually solve my problem in a nicer way All integrations that I made were made by sending the user sessionId through the WS protocol header, so there was no actual interaction with the SolidStart server Thank you very much for your help and time I'll close this thread

Did you find this page helpful?