Ctmx - super lightweight web dev

Me too, I’m definitely looking forward to trying out your Ctmx lib.

Thanks to @md1frejo Jonas’s suggestion I made a template to easily create ctmx with leiningen. Go

lein new luminus my-project +ctmx
cd my-project
lein run

The ctmx source is entirely in the routes/home.clj ns, so you can see it is very simple.

2 Likes

great work. I can conform that it is working

Hi @Matthew_Molloy,

I want to say thanks to let me knew about htmx & ctmx.
For the first approach, I toyed with Babashka + htmx little project and it was very fun!

I plan to make a version with your ctmx lib.
Cheers!

3 Likes

Great to hear Prestance! Shout out if you have any questions. I’m also interested to know if there’s anything confusing about the setup.

1 Like

Hi @Matthew_Molloy ,

Thanks a lot for ctmx! I want to do an app in tools.deps and I am having a hard time setting up the middleware. Could you point me to a simple app that I could use as a template?

Thanks,
Hadil

Sure @hadils,

To see a working setup try lein new luminus my-project +ctmx. Then look in the routes/home.clj namespace. CTMX will work with any setup that uses reitit for routing.

Matt

Thanks @Matthew_Molloy !

I am trying this out and it’s all new to me, so here is a simple question: I am trying to create a page with the “my name” exmaple but I get a 505 error. Any suggestions?

name.clj:

(ns test.routes.name
(:require
[ctmx.core :as ctmx]))

(ctmx/defcomponent ^:endpoint hello [req my-name]
[:div#hello "hello " my-name])

(defn routes
(ctmx/make-routes “/name” (fn [req]
[:div
[:label “what is your name?”]
[:input {:name “my-name” :hx-patch “hello” :hx-target “#hello”}]
(hello req “”)])))

handler.clj:

(ns test.handler
(:require
[test.middleware :as middleware]
[test.layout :refer [error-page]]
[test.routes.home :refer [home-routes]]
[test.routes.name :as name]
[reitit.ring :as ring]
[ring.middleware.content-type :refer [wrap-content-type]]
[ring.middleware.webjars :refer [wrap-webjars]]
[test.env :refer [defaults]]
[mount.core :as mount]))

(mount/defstate init-app
:start ((or (:init defaults) (fn )))
:stop ((or (:stop defaults) (fn ))))

(mount/defstate app-routes
:start
(ring/ring-handler
(ring/router
[(home-routes)
(name/routes)])
(ring/routes
(ring/create-resource-handler
{:path “/”})
(wrap-content-type
(wrap-webjars (constantly nil)))
(ring/create-default-handler
{:not-found
(constantly (error-page {:status 404, :title “404 - Page not found”}))
:method-not-allowed
(constantly (error-page {:status 405, :title “405 - Not allowed”}))
:not-acceptable
(constantly (error-page {:status 406, :title “406 - Not acceptable”}))}))))

(defn app
(middleware/wrap-base #'app-routes))

Can you put it on GitHub and send me a link please? Alternately zip the project and mail to matthew@molloy.link.

ok, here the link if got it right: GitHub - md1frejo/clojure

it is basically the template with an added name request

Thanks @md1frejo,

I have cloned your project, cd in, lein run then visited http://localhost:3000. I can click the div and it increments. What exact query did you run to get http 505? Which browser were you in?

Matt

try localhost:3000/name
it should show an input form to write a name. thats in name.clj
the browser was firefox

@md1frejo I see there’s something confusing about my documentation. I will now fix that. I have also added a pull request to your repository. See how you need to wrap the initial request in a rendering function?

If I may, pardon me if I ask a very “beginner” question, but you mention in your initial post, “and no compiled js on the frontend,” as if that is a bad thing. To a beginner like me, your comment seems to suggest that frontend JS is better avoided. Is this what you meant? And if so, why is frontend JS better to be avoided?

The biggest problem is page rendering speed. Front end JS has to be loaded into the browser causing delays in first page render.

Subtler issue is state management on the browser. There are very simple to very complex solutions to this problem. They require learning on the developer’s part and need to be maintained.

A server-side solution reduces initial page load time. And all the state is on the server. You have to keep server state even with front end JS anyway.

@rmschindler as @hadils mentioned too much js slows page load (especially on mobile and in countries with slower internet). The last few years have seen a big shift towards heavy frameworks that use a lot of javascript. Some developers like it because it ‘separates concerns’ by having all the rendering code running on the browser, but it makes web development slower and more complex. ctmx / html are part of a reaction against that.

yes, thanks. now it works. I might try to wrap a graph in a page, exploring the collatz (3n+1) conjecture just for fun and learning.

Remember to push your findings to GitHub so we can see what you make!

A question, I see in your template that yuo don’t use hiccup bootstrap, is there any specific reassons for that? I am planning to use it but if there is some drawbakcs with with it I have to go with anoter one.