Static / Server-Rendered Pages

ShipClojure supports two approaches to server-rendered pages:

1. Content pages (Blog, ToS, Privacy)

These are managed by the Powerpack content system and rendered as static HTML using UIX components. See Blog & Content System for full documentation.

Content pages are written in markdown, stored in content/, and rendered via:

content/*.md → Datomic → UIX components → HTML string → static files

In development, pages render dynamically from the in-memory DB. In production, they're pre-exported as static HTML.

2. Interactive landing pages (UIX SSR + hydration)

For pages that need both server-rendered HTML (for SEO/performance) and client-side interactivity, use UIX's server-side rendering with client-side hydration.

The key insight: write your components as .cljc files so they can render on both the JVM (static HTML) and in the browser (interactivity).

How it works

  1. Server: UIX renders your component tree to an HTML string via uix.dom.server/render-to-static-markup
  2. Client: Shadow-CLJS loads a small JS bundle that re-renders the same component tree, adding event handlers

Shadow-CLJS module splitting

Split your JS into modules so static pages don't load the full SPA bundle:

;; shadow-cljs.edn
{:builds
 {:app {:target :browser
        :modules {:base    {:entries [saas.base]}
                  :landing {:init-fn saas.landing/init!
                            :depends-on #{:base}}
                  :main    {:init-fn saas.core/init!
                            :depends-on #{:base}}}}}}
  • Static pages load base.js + landing.js (small)
  • SPA loads base.js + main.js (full app)

Layout integration

The content layout system (src/cljc/saas/content/ui/layout.cljc) handles script injection. The base-layout includes content.js for theme switching and TOC highlighting. The content-layout adds Prism.js for code syntax highlighting.

For interactive pages that need hydration, create a custom layout that includes the appropriate JS module.

Read this blog post for a deeper dive into UIX SSR with shadow-cljs.