Single-page multi-URL static site with ClojureScript

I have been searching for an example of ClojureScript being used to build a:

  • Single page: Everything is contained in a page, not requiring further requests to the server, for an “app feeling” when browsing
  • Multi-URL: There are links in the page, simulating the navigation, as with React Router
  • Static site: like the ones that can be hosted in GitHub

If you know of an example that I could just git clone, build with anything, and then just drag and drop the folder to Netlify or some similar deployment, that is exactly what I am looking for. I can just continue from there.

I think this may be close to what you want. Creating ToryAnderson.com with ShadowCLJS | Tech.ToryAnderson.com

1 Like

I think that’s it. Thank you very much. That is a great example.

I have been checking many technologies in the past few days and somehow I discarded Reitit because I thought it was back-end and my internal PageRank did not find enough links pointing to it to give it a second thought.

Now I am going to build some toy examples cherry picking code from your repo, and I am going to put extra attention to using React components from Reagent. I still do not understand the challenges in using React-Router and I can foresee that React components not being usually straightforwardly and readily usable might be a source of frustration greater than the problems that JavaScript presents over ClojureScript.

I am just getting started with front-end.

1 Like

The search term you’re looking for is frontend routing. Any Clojure library that does frontend routing will work.

I’ve created an example app here if you’re interested. Hope it can help

It uses clj-commons/secretary for front-end routing

i have always been very happy with:

https://luminusweb.com/

there is also an excellent book:

Thank you all, I was able to make a MWE with Secretary.

I am now going to try:

  1. Generating everything with GitHub actions. Starting with HTML and no JavaScript.
  2. Using Reagent components from React.

Only two points, it is going to take a while :sweat_smile:

I’m a bit late but I made a demo with material-ui.
It uses reagent/re-frame, reitit for routing, is a single page app deployed to GitHub pages with GitHub actions.
Maybe it helps.

See the website and the git repo.

The reagent template creates such a project for you.

$ clojure -X:new :template reagent :name yourname/project-name

This demo was built that way: https://clerk-demo.netlify.app

I would avoid Secretary. It is macro based and doesn’t compose well. Go for reitit or bidi instead. Both are data oriented solutions, and both allow you to build bi-directional routes.

I struggled to get something I was happy with for a while with bidi and secretary. Finally I came across the reitit re-frame frontend example:

What I’m really happy about with this one is that it:

  • lets you use straight URLs in <a href="..."> where that makes sense,
  • lets you dispatch a route change as a re-frame event,
  • will properly restore the route on an initial page load (so you can eg. store app state in query params and they’d get carried along with a bookmark or emailed URL).

It’s this last one that was hard for me to achieve on my own.

1 Like

Thank you all, I am going to be checking these examples in more detail. The bidi README is very informative.

There are two things that I have noticed:

  1. URLs should probably use fragments (#), otherwise users may share URLs leading only to 404 errors.
  2. The DOM is rewritten in the navigation. Rendering everything initially and then changing only its visibility may have an impact on performance, although I do not have the expertise to guesstimate if it would be positive, negative, or negligible.

Not completely sure I understand, but it reminds me of a, slightly off-topic, super power that Clojure + ClojureScript offers. In a project I were involved in we used Rum both on the backend and the frontend to serve ready HTML from the server, then Rum on the front end ”jacked in” on the DOM and without rerendering it just took over and the rest, including navigation, happened in the SPA. It was super sweet. We also shared bidi routes between the two worlds, which maybe means this was not so off-topic after all. (And we added a dash of Citrus to the Rum for extra punch.)

Yes, that would be good, except the ready HTML should be in the front-end at all times (either not visible or directly returned from a function, e.g. “memoize’d”*). Then the static files may be hosted in GitHub, GitLab, etc.

In the end, it is like generating HTML offline and uploading the generated files, when paired with front-end routing, it allows for an entire site (several pages) to feel very fast**. Then APIs would make the complete JAMstack, which I consider very interesting.

* Since you mention Rum, Daiquiri might do this. I would need to check further.

** responsive?

I’m a big fan of the JAMStack myself. :smiley:

Have a look at Cryogen, maybe?

In a project I were involved in we used Rum both on the backend and the frontend to serve ready HTML from the server, then Rum on the front end ”jacked in” on the DOM and without rerendering it just took over and the rest, including navigation, happened in the SPA. It was super sweet. We also shared bidi routes between the two worlds

I’ve used Rum server-side rendering with CLJS taking over on a non-SPA project and can confirm, it works wonderfully. On my current (different) project, in which the HTML is basically just a display wrapper around the results of API calls, I’ve been thinking about how to do everything (including navigation) in the browser after CLJS jacks in. It’s apparent that I can’t just keep using compojure. Thank you for the bidi reference!

1 Like

Cryogen seems to be quite blog oriented, with Markdown conversion as one of the main features.

During the weekend I have made a quick test with Gatsby and CoffeeScript. Replacing CoffeeScript with ClojureScript would be quite nice, but I have not found anything similar to Gatsby in the Clojure world. Interestingly, Gatsby has plugins for CoffeeScript, PureScript, etc. (I understand CoffeeScript and ClojureScript are two completely different beasts).

I think it is time for me to take a closer look at the interoperability between React and Reagent. I think I have seen somewhere that Gatsby and ClojureScript do not play well together, but I did not understand the reasons yet.