Creating a new web + figwheel project

Hi everyone.

I want to make a new Clojure / ClojureScript project

That will use Ring and http-kit on the backend.

Has a client written in ClojureScript which I can develop with hot-reloading using Figwheel.

I don’t care whether it’s lein based or clj-new etc.

I’d assumed that there must be some kind of template or off-the-shelf way to do this today. But I can’t find one. And all my attempts to either retrofit existing projects or to manually build this over the last week have ended in failures I can’t fix.

Isn’t there something like this in 2024?

There probably are some templates, but I would suggest to avoid relying on them for various reasons and just build what you want from scratch. With modern tools it’s relatively trivial to do.

You mention failures that you can’t fix when trying to go that route. What exactly are those failures? Have you encountered them while following the official docs at Introduction | figwheel-main or by doing something else?

The main problem at the moment is getting a

Cannot invoke "Object.getClass()" because "x" is null

error when Figwheel tries to recompile the ClojureScript client. I don’t get this if I recompile the client directly on the command line, so I’m guessing it’s something to do with the Figwheel configuration. Maybe a version incompatibility or similar.

From googling around it doesn’t look like that error is specifically to do with either Figwheel or even ClojureScript. Other people seem to have seen it in Clojure. So I’m guessing it’s from the compiler being called from Figwheel.

I’m doing something like Your Own Server | figwheel-main though the route I got there was through starting with a non-Figwheel project and trying to add Figwheel to it.

Do you have the full error? There should be a stacktrace, which would tell you where that error is coming from exactly.

Not sure how helpful the full error is

[Figwheel] Validating figwheel-main.edn
[Figwheel] figwheel-main.edn is valid \(ツ)/
[Figwheel] Compiling build dev to "resources/public/main.js"
[Figwheel] Failed to compile build dev in 1.715 seconds.
[Figwheel:WARNING] Could not Analyze   src/cardiganbay/types.cljc   line:38  column:1

  Cannot invoke "Object.getClass()" because "x" is null

  33  
  34    (media-list [ps])
  35  
  36  )
  37  
  38  (defprotocol IPageExporter
      ^---
  39    (as-map [ex])
  40    (page-name->export-file-path [ex page-name])
  41    (export-path [ex])
  42    (page-name->exported-link [ex page-name])
  43    (media-name->exported-link [ex media-name])

[Figwheel:SEVERE] failed compiling file:src/cardiganbay/types.cljc

Figwheel doesn’t give you a stack-trace.

The file types.cljc is a cljc file (compiled from both Clojure and ClojureScript) and all it does is define a couple of interfaces using (defprotocol …)

This file compiles without problems both when used within the Clojure server. And also when I compile the ClojureScript client (that also includes it) from the command line

The error ONLY occurs when Figwheel tries to recompile it during the hot reload. So I’m assuming this is a Figwheel specific problem. And something to do with the way Figwheel is configured.

That’s why a good off-the-shelf template where all the parts (ie. the clojure, clojurescript , figwheel etc.) versions were compatible with each other, would probably resolve this. I’m sure the problem is within the Frankenstein’s monster of a configuration I’ve tried to piece together myself. Rather than that particular source file.

My instinct says its the code, rather than the tools or their configuration.

CLJC is often misunderstood in how it works, so it is easy to have JVM-isms leaking into a CLJS compilation pipeline in a way that cannot be compiled. Kinda hard to say without a stacktrace though. Never seen a defprotocol break before, so no guesses from my side.

But it can be compiled with cljs

If I do it directly from the command line

The file consists of nothing but defprotocols

And it’s been compiling and working fine for over 18 months in the previous version of the project. In both clj and cljs

It’s only with figwheel that I get this error.

But I suspect the error isn’t with this file at all. It’s sone other obscurity

Which is why I’m really not trying to debug it.

I just want a nice working blank configuration setup with all the parts I use, that I can bring my own app code back into

Can’t help you with figwheel. I’m not sure why defprotocol would fail.

If you want to try shadow-cljs I can guide you.

Server needs to be Clojure on JVM I’m afraid.

public repo would aid in discovery and reproducibility. ideally a minimal failing example.

1 Like

There seems to be a rather big misunderstanding in how this all works.

a) shadow-cljs is implemented in Clojure and runs in the JVM, just as figwheel or cljs.main. No difference in that regard. The only difference is in the provided feature set, in that shadow-cljs generally does more, e.g. support npm packages out of the box without additional tools.

b) npm in shadow-cljs is only required if you want to use actual npm packages. No packages then no npm is required.

c) regardless of which build tool you use, they all take .clj(s|c) files and generate .js files as the output.

d) your JVM server does not need to know or care how these .js files were generated. It just needs to serve them as they are as text.

With shadow-cljs you have 2 options.

You can run it separately from your CLJ server. This is what I generally recommend, as it is generally simpler and avoids common problems such as dependency conflicts. It is also much closer to how a production setup would look, since no production setup should ever include running a build tool, doesn’t matter which, as part of the production CLJ server.

So, the workflow is npx shadow-cljs watch <your-build> during development. Once you are ready to move to production you make a release build, via npx shadow-cljs release <your-build> which optimizes everything and substantially reduces the size of the final build.

The other option is running it in embedded mode, which means it is started as part of your CLJ development setup and runs in the same JVM. And then controlling shadow-cljs via either its UI (default http://localhost:9630) or the CLJ REPL.

So can I import shadow-cljs into an existing project, just as I can with figwheel? As another dependency? And then run it entirely through clj, rather than installing and having anything to do with npm?

Yep.

Just going to need npm for actual npm packages, such as react.

1 Like

This doesn’t solve the immediate problem, but the book Learn Clojurescript by Andrew Meredith takes you through uaing Figwheel and shadow-cljs in a clear and concise way.

1 Like

You can use Kit, and there’s a cljs module available

https://kit-clj.github.io/

here are the docs for adding cljs support Kit Framework

I made something some time ago, but don’t maintain it anymore.
Several happy customers have a product based upon my framework.

GitHub - rpompen/mkproj: Clojure(script) project

It’s just a bash script to create a project template.
Keywords:
hoplon, chord, couchdb, decomplected.

The expanded project is also available on the same github page.

I dare you to find a simpler framework for client-server cloud applications.

The lack of a popular project template like this is indeed a sad state of affairs.

I came to create this after the mismatch between watching “Simple made Easy” and then having to resort to frameworks like pedestal, luminus, etc…

Performance is awesome and no lifecycle management of components.

I’m still using a newer version based incorporating fossil instead of git.

Since I’m thinking about starting a business again, I’m not publishing that newer template.

Succes!

I think Cannot invoke "Object.getClass()" because "x" is null is hiding a NullPointerException that is lurking somewhere in your code. I would recommend you to search for null values. Hope this works!