{"id":13760293,"url":"https://github.com/valerauko/hoge","last_synced_at":"2026-03-01T22:37:53.412Z","repository":{"id":77443871,"uuid":"548989105","full_name":"valerauko/hoge","owner":"valerauko","description":"Server-side rendering example with re-frame, shadow-cljs and Deno","archived":false,"fork":false,"pushed_at":"2025-02-08T07:09:28.000Z","size":75,"stargazers_count":11,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-05-07T10:11:23.339Z","etag":null,"topics":["clojure","clojurescript","deno","example","hacktoberfest","re-frame","react","server-side-rendering","shadow-cljs","ssr"],"latest_commit_sha":null,"homepage":"","language":"Clojure","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/valerauko.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","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},"funding":{"ko_fi":"valerauko"}},"created_at":"2022-10-10T13:56:25.000Z","updated_at":"2025-02-08T07:09:32.000Z","dependencies_parsed_at":"2025-04-19T19:33:36.442Z","dependency_job_id":"82e13f99-d71b-498d-aff4-2ead9a014461","html_url":"https://github.com/valerauko/hoge","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/valerauko/hoge","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/valerauko%2Fhoge","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/valerauko%2Fhoge/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/valerauko%2Fhoge/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/valerauko%2Fhoge/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/valerauko","download_url":"https://codeload.github.com/valerauko/hoge/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/valerauko%2Fhoge/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29987365,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-01T21:06:37.093Z","status":"ssl_error","status_checked_at":"2026-03-01T21:05:45.052Z","response_time":124,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["clojure","clojurescript","deno","example","hacktoberfest","re-frame","react","server-side-rendering","shadow-cljs","ssr"],"created_at":"2024-08-03T13:01:07.244Z","updated_at":"2026-03-01T22:37:53.394Z","avatar_url":"https://github.com/valerauko.png","language":"Clojure","funding_links":["https://ko-fi.com/valerauko"],"categories":["Clojure"],"sub_categories":[],"readme":"# Server-side rendering example `HOGE`\n\nFeaturing:\n\n* [re-frame](https://day8.github.io/re-frame/)\n* [reitit](https://cljdoc.org/d/metosin/reitit/0.5.18/doc/introduction)\n* [shadow-cljs](https://shadow-cljs.github.io/docs/UsersGuide.html)\n* [Deno](https://deno.land/)\n* docker-compose\n\n## Just run it\n\n`docker compose up`\n\nNote: if you're using Podman, you'll have to have some fun configuring the networking so that the containers can talk to each other.\n\n## What's HOGE\n\nThe Japanese version of `foo`.\n\n## How it works\n\nIt uses nginx as load balancer/ingress. It pushes every resource call (JS, CSS etc) to shadow-cljs's server, while everything else goes through to server-side rendering.\n\nBefore hydrating the rendered HTML, `hoge.core/hydrate` rebuilds the application state and waits for completion (using the `::loaded` event as callback). It's the same as it works when it gets rendered on Deno, so there should be no hydration errors.\n\n## Stuff to pay attention to\n\n### No History\n\nDeno has no [History API](https://developer.mozilla.org/en-US/docs/Web/API/History_API), so Reitit's defaults don't work there. In the current version it's worked around by manually calling `hoge.routes/navigate` from the renderer-side script. If you want to utilize some Reitit features that depend on History, such as `reitit.frontend.easy/href`, you'll have to stub a `reitit.frontend.history/History` object for the server-side rendering.\n\n### Fetch is different\n\nThe [fetch API](https://developer.mozilla.org/en-US/docs/Web/API/fetch) works slightly differently from what most people are used to:\n\n\u003eA fetch() promise only rejects when a network error is encountered (which is usually when there's a permissions issue or similar). A fetch() promise does not reject on HTTP errors (404, etc.). Instead, a then() handler must check the Response.ok and/or Response.status properties.\n\nOn the other hand, the [Response.json](https://developer.mozilla.org/en-US/docs/Web/API/Response/json) method makes it pretty convenient to use when it comes to API calls.\n\n### Callback hell\n\nBoth the server-side response and the client-side hydration depends on the `::loaded` event being called when the app is ready. In this example it's fired when all HTTP requests are finished, but that's arbitrary. The important thing is that it *must* be called somewhere, or the app will never start (Deno won't respond and nginx will throw a timeout).\n\n### No document\n\nThere's no `document` on Deno, so anything that would touch it (such as setting the page title) has to check if it `exists?` or result in an error.\n\nThis is also the reason that Deno has to reference the `:compiled` JS: the dev build shadow-cljs generates has `document` references that make the server crash.\n\n### No hot-reload on Deno\n\nDeno doesn't do hot reloading, so if there's a change to either `serve.tsx` or `compiled.js`, it should be restarted with `docker-compose restart ssr`.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvalerauko%2Fhoge","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvalerauko%2Fhoge","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvalerauko%2Fhoge/lists"}