{"id":33338688,"url":"https://github.com/phucvin/solv-03","last_synced_at":"2025-11-21T09:04:44.249Z","repository":{"id":322141239,"uuid":"1088335272","full_name":"phucvin/solv-03","owner":"phucvin","description":"Solv's prototype 03","archived":false,"fork":false,"pushed_at":"2025-11-20T18:17:39.000Z","size":247,"stargazers_count":6,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-11-20T19:22:05.459Z","etag":null,"topics":["data-star","fine-grained-reactivity","htmx","javascript","js","liveview","server-component","server-side-rendering","signals","solidjs","ssr"],"latest_commit_sha":null,"homepage":"https://stackblitz.com/~/github.com/phucvin/solv-03","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/phucvin.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-11-02T19:12:50.000Z","updated_at":"2025-11-20T18:16:49.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/phucvin/solv-03","commit_stats":null,"previous_names":["phucvin/solv-03"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/phucvin/solv-03","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phucvin%2Fsolv-03","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phucvin%2Fsolv-03/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phucvin%2Fsolv-03/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phucvin%2Fsolv-03/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/phucvin","download_url":"https://codeload.github.com/phucvin/solv-03/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phucvin%2Fsolv-03/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":285587839,"owners_count":27197177,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-11-21T02:00:06.175Z","response_time":61,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["data-star","fine-grained-reactivity","htmx","javascript","js","liveview","server-component","server-side-rendering","signals","solidjs","ssr"],"created_at":"2025-11-21T09:03:32.968Z","updated_at":"2025-11-21T09:04:44.239Z","avatar_url":"https://github.com/phucvin.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Solv - Stateless Offline-capable LiveView - Prototype 03\n\nSolv's main idea is that stateless servers keep client's state in a volatile\ncache. It enables server components that are also interactive, which is best of\nboth worlds between LiveView and htmx. Then fine-grained reactivity is added to\nachieve efficient DOM updates + minimal payload size.\n\n## What is this?\nA prototype to show:\n1. Server can create \u0026 modify client's DOM directly, simlar to LiveView/htmx but\nin a stateless \u0026 fine-grained way.\n1. Server knows client's state by storing it in a simple volatile cache. This\ncached state helps reduce payload size when client send request to server.\nBut if the cached item is cleared, client can always resend it to server.\n\nThis provides:\n1. SSR with close-to-zero rehydration cost.\n1. No API endpoints, server can just read from DB then render \u0026 update clients directly.\n1. Server components that are interactive.\n1. Minimal payload for updates from server.\n1. Stateless servers that can handle stateful-like request/response.\n1. Avoid consistent connection to server, clients can work offline after page load,\nupdate local state, keep pending server requests and sync later\n(can also use a sync engine like InstantDB to simplify some part of the page).\n\nTo compare with some other JS SPA/MPA library/framework:\n- React: rehydration cost is high; server components are limited so API\nendpoints are still needed to handle update.\n- Solid: rehydration cost is high; API endpoints are needed to handle update.\n- LiveView: requires stateful connection \u0026 server; doesn't work well or at all if offline.\n- htmx: bigger payload for updates from server; requires imperative JS to handle\ncomplex offline interaction (as constrast to having declarative JSX \u0026 signals).\n\n## Demos\n\nRun it yourself online: https://stackblitz.com/~/github.com/phucvin/solv-03\n\nBranch `workers` is also auto-deployed to:\nhttps://solv-03.phucvin.workers.dev/ (this uses a free plan of Cloudflare Workers)\n\nDetails:\n- Counter 01: simple counter work entirely at client.\n- Counter 02: 2 counters; increasing is client-side; reseting is a server action.\n- Counter 03: multiple counters; adding a new counter is a server action that\nalso renders the component server-side (note that client handles the loading\neffect when button is clicked).\n\nYou can open console and see `dispatchServer` (what is sent to the server) and\n`cm` (CommandMap, what server responded) being logs when a server action is executed.\n- When the server lost cached client state (e.g. after keeping a demo page open for\na while, or 10s if running with Stackblitz), making a server action will show log\n`Server lost cache, resending client state`, and the next `dispatchServer` will\ncontains a bigger payload than before since it contains client's full current state.\n\nCode for these demos are int `src/routes`.\n\n## How does it works?\nLife of a page request:\n1. Client makes a request to view a page.\n1. Server calls the page's component to render, this propagates a CommandMap which\ncontains created DOM nodes, signals, and effects.\n1. Server generates a unique id for this client, caches the signals and effects\n(but not the DOM nodes) with this id.\n1. Server does SSR by generating HTML body from the created DOM nodes.\n1. Server composes the HTML body with several things: unique id for this client,\nsignals and effects (so the client can rehyrate), required scripts for component\nand their client action \u0026 effect handlers.\n\nLife of a client action:\n1. After rehyration, clicking a button will trigger an action, if this is a client\naction, no request is made to server.\n1. The action will execute and modify signals and DOM nodes.\n1. Modified signals will trigger effects, which might modify more.\n1. Repeat until no more changes or repeats exhausted (avoid infinite loop).\n\nLife of a server action:\n1. If an action handler is not found at client, it will be send to server a long\nwith the client's unique id, signal \u0026 effect updates.\n1. Server finds the previously saved signals \u0026 effects for the client from cache.\n1. If not found, server send 404 error, client sees that and resend the request\nwith ALL of its current signals \u0026 effects.\n1. Now server has the client's signals \u0026 effects.\n1. Server applies the updates and the action, which might modify more signals.\n1. Modified signals will trigger effects, server runs these effects until no\nmore changes or repeat exhausted.\n1. As the previous 2 steps run, it also propagate a CommandMap which contains\nnewly created DOM nodes, existing DOM property updates, new signals, new effects.\n1. The CommandMap is then send to client. Client apply that to its current DOM tree,\nsignals and effects.\n\n## What's next?\nSince this is just a prototype, the required code to achieve what we want is\nstill rough \u0026 long.\n\nIf this idea makes sense and the provided benefits are good enough to the community,\na compiler is needed to compile ideal code (code that looks like a Solid's component)\nto raw code.\n\n## Raw notes\n\nThis prototype version is focusing on:\n- Fine-grained reactivity (like SolidJS)\n- Offline-capable to allow DOM updates on both client and server\n\nTODOs:\n- Use Hono (https://hono.dev/docs/getting-started/cloudflare-workers)\n- Input field binding to signal\n- Streaming server responses, including the initial HTML (idea: https://lamplightdev.com/blog/2024/01/10/streaming-html-out-of-order-without-javascript/)\n- Remove signals \u0026 effects when all related elements are deleted, a GC (scanning effect params) is easiest first\n\nReferences:\n- https://github.com/phucvin/solv-01/\n- https://github.com/phucvin/solv-01/tree/workers\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fphucvin%2Fsolv-03","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fphucvin%2Fsolv-03","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fphucvin%2Fsolv-03/lists"}