hyperfiddle

tobias 2025-05-24T23:33:11.939869Z

Hi can I get some help making an uberjar that can be run with java -jar target/app.jar ? What I've done so far: Cloned the latest electric v3 starter app. Added #?(:clj (:gen-class)) to the top of src-prod/prod.cljc Modified src-build/build.clj to compile before uber - see Tobias comments below

(let [jar-name (or (some-> jar-name str) 
                   (format "electricfiddle-%s.jar" version))
        aliases [:prod]
        basis (b/create-basis {:project "deps.edn" :aliases aliases})] ; Tobias added line
    ;; Tobias added b/compile-clj form below
    (b/compile-clj {:basis basis
                    :ns-compile '[prod]
                    :class-dir class-dir})
    (b/uber {:class-dir class-dir
             :uber-file (str "target/" jar-name)
             :basis     basis                               ; Tobias changed line
             :main      'prod})                             ; Tobias edited line
    (log/info jar-name))
Compiled app with clj -X:build:prod uberjar :build/jar-name "app.jar" Run app with java -jar target/app.jar Then I get the following error: Exception in thread "main" java.lang.NoClassDefFoundError: hyperfiddle/electric3$Apply (wrong name: hyperfiddle/electric3$apply) My java version is openjdk 21.0.6 2025-01-21 LTS Thanks in advance for your help!

tobias 2025-05-25T07:41:17.810259Z

Could the error be due to the compiler trying to compile hyperfiddle.electric3/apply and hyperfiddle.electric3/Apply (both defined in ns hyperfiddle.electric3) to the same file name hyperfiddle/electric3$Apply.class on a case-insensitive file system? Weirdly I get the same error though even if I try compiling on a newly-created case-sensitive volume on my mac.

Dustin Getz (Hyperfiddle) 2025-05-24T23:36:47.397229Z

hard to debug this from my phone, did you confirm that the unmodified starter app repo dockerfile works? i believe we deploy it and therefore it should work

tobias 2025-05-24T23:41:32.831849Z

Not sure about Docker but the regular way of building and running work just fine, i.e. leave prod.cljc and build.clj unchanged and run the following

clj -X:build:prod uberjar :build/jar-name "app.jar"
java -cp target/app.jar clojure.main -m prod
BTW there's no urgency this can wait until after the weekend

tobias 2025-05-24T23:42:53.235549Z

The only reason I want to run it as java -jar target/app.jar is that's just a lot easier to set up with my hosting provider as they have a managed java image they keep up to date

tobias 2025-05-27T09:28:33.871879Z

A workaround in case anyone else runs into this problem is to compile the app inside of a Docker container using the Dockerfile that comes with the starter app. Here's a one-liner script to compile and then copy the app.jar out of the container:

VERSION=$(git describe --tags --long --always --dirty) \
&& docker build --build-arg VERSION=$VERSION -t electric3-starter-app-builder . \
&& docker create --name extract-electric electric3-starter-app-builder \
&& rm -rf target && mkdir -p target \
&& docker cp extract-electric:/app/target/app.jar target/app.jar \
&& docker rm extract-electric \
&& echo "✅ Built target/app.jar with version: $VERSION"
I think the reason this works is because the file system inside the docker container is case sensitive.

👀 1