I'm working through the tutorial now and am now at https://biffweb.com/docs/tutorial/new-project/, and am getting an unexpected 404 with /css/main.css request. I suppose this isn't a showstopper... or is this a sign of something deeper? how can I fix this?
interesting! something like this came up previously and I added this exception handler which at the time seemed to correctly catch incomplete downloads: https://github.com/jacobobryant/biff/blob/09ef8cef88cb699c67de124cbb472bbff0142d69/libs/tasks/src/com/biffweb/tasks.clj#L247
I did just test it and it looks like I need to update it to check the :exit key instead of the :babashka/exit key. What output do you get if run the following, with a borked bin/tailwindcss file?
$ clj -R:dev
-R is deprecated, use -A with repl, -M for main, or -X for exec
Clojure 1.11.1
user=> (require '[babashka.process :refer [shell]])
nil
user=> (try (shell "bin/tailwindcss") (catch Exception e (ex-data e)))
{:proc #object[java.lang.ProcessImpl 0x5434e40c "Process[pid=3168, exitValue=139]"], :exit 139, :in #object[java.lang.ProcessBuilder$NullOutputStream 0x3b48e183 "java.lang.ProcessBuilder$NullOutputStream@3b48e183"], :out #object[java.lang.ProcessBuilder$NullInputStream 0x514de325 "java.lang.ProcessBuilder$NullInputStream@514de325"], :err #object[java.lang.ProcessBuilder$NullInputStream 0x514de325 "java.lang.ProcessBuilder$NullInputStream@514de325"], :prev nil, :cmd ["bin/tailwindcss"], :type :babashka.process/error}
Also when running clj -M:dev dev, did you get a stack trace like this?
$ clj -M:dev dev
New config generated and written to config.env.
[main] INFO com.eelchat - starting: com.biffweb$use_aero_config@3b9bc8c0
[main] INFO com.eelchat - starting: com.biffweb$use_xtdb@2810a1d5
[main] INFO xtdb.tx - Started tx-ingester
[main] INFO com.eelchat - starting: com.biffweb$use_queues@5c4378fa
[main] INFO com.eelchat - starting: com.biffweb$use_xtdb_tx_listener@106ed71c
[main] INFO com.eelchat - starting: com.biffweb$use_htmx_refresh@2c708eed
[main] INFO com.eelchat - starting: com.biffweb$use_jetty@64a94c26
[main] INFO org.eclipse.jetty.server.Server - jetty-10.0.7; built: 2021-10-06T19:34:02.766Z; git: da8a4553af9dd84080931fa0f8c678cd2d60f3d9; jvm 17.0.10+7-Ubuntu-120.04.1
[main] INFO org.eclipse.jetty.server.handler.ContextHandler - Started o.e.j.s.ServletContextHandler@3fa0984a{/,null,AVAILABLE}
[main] INFO org.eclipse.jetty.server.AbstractConnector - Started ServerConnector@453b1c5{HTTP/1.1, (http/1.1)}{0.0.0.0:8080}
[main] INFO org.eclipse.jetty.server.Server - Started Server@a55796a{STARTING}[10.0.7,sto=0] @16666ms
[main] INFO com.biffweb.impl.misc - Jetty running on
[main] INFO com.eelchat - starting: com.biffweb$use_chime@5a09528e
[main] INFO com.eelchat - starting: com.biffweb$use_beholder@74e3033a
[main] INFO com.eelchat - System started.
[main] INFO com.eelchat - Go to
[chime-1] INFO com.eelchat.worker - There are 0 users.
clojure.lang.ExceptionInfo:
{:proc #object[java.lang.ProcessImpl 0x2b38c0d7 "Process[pid=2109, exitValue=139]"], :exit 139, :in #object[java.lang.ProcessBuilder$NullOutputStream 0x4e13bd5e "java.lang.ProcessBuilder$NullOutputStream@4e13bd5e"], :out #object[java.lang.ProcessBuilder$NullInputStream 0x5fa890bc "java.lang.ProcessBuilder$NullInputStream@5fa890bc"], :err #object[java.lang.ProcessBuilder$NullInputStream 0x5fa890bc "java.lang.ProcessBuilder$NullInputStream@5fa890bc"], :prev nil, :cmd ["bin/tailwindcss" "-c" "resources/tailwind.config.js" "-i" "resources/tailwind.css" "-o" "target/resources/public/css/main.css" "--watch"], :type :babashka.process/error}
at babashka.process$check.invokeStatic (process.cljc:111)
babashka.process$check.invoke (process.cljc:95)
babashka.process$shell.invokeStatic (process.cljc:646)
babashka.process$shell.doInvoke (process.cljc:622)
clojure.lang.RestFn.applyTo (RestFn.java:137)
clojure.lang.Var.applyTo (Var.java:705)
clojure.core$apply.invokeStatic (core.clj:667)
clojure.core$apply.invoke (core.clj:662)
com.biffweb.tasks.lazy.babashka.process$shell.invokeStatic (process.clj:4)
com.biffweb.tasks.lazy.babashka.process$shell.doInvoke (process.clj:4)
clojure.lang.RestFn.applyTo (RestFn.java:137)
clojure.core$apply.invokeStatic (core.clj:669)
clojure.core$apply.invoke (core.clj:662)
com.biffweb.tasks$shell.invokeStatic (tasks.clj:59)
com.biffweb.tasks$shell.doInvoke (tasks.clj:52)
clojure.lang.RestFn.applyTo (RestFn.java:137)
clojure.core$apply.invokeStatic (core.clj:667)
clojure.core$apply.invoke (core.clj:662)
com.biffweb.tasks$css.invokeStatic (tasks.clj:238)
com.biffweb.tasks$css.doInvoke (tasks.clj:206)
clojure.lang.RestFn.applyTo (RestFn.java:137)
clojure.lang.Var.applyTo (Var.java:705)
clojure.core$apply.invokeStatic (core.clj:667)
clojure.core$apply.invoke (core.clj:662)
com.biffweb.task_runner$run_task.invokeStatic (task_runner.clj:47)
com.biffweb.task_runner$run_task.doInvoke (task_runner.clj:35)
clojure.lang.RestFn.invoke (RestFn.java:423)
com.biffweb.tasks$dev$fn__495.invoke (tasks.clj:281)
clojure.core$binding_conveyor_fn$fn__5823.invoke (core.clj:2047)
clojure.lang.AFn.call (AFn.java:18)
java.util.concurrent.FutureTask.run (FutureTask.java:264)
java.util.concurrent.ThreadPoolExecutor.runWorker (ThreadPoolExecutor.java:1136)
java.util.concurrent.ThreadPoolExecutor$Worker.run (ThreadPoolExecutor.java:635)
java.lang.Thread.run (Thread.java:840)
nREPL server started on port 7888 on host localhost -
[chime-1] INFO com.eelchat.worker - There are 0 users. That being said: based on https://clojurians.slack.com/archives/C013Y4VG20J/p1711467523658699?thread_ts=1711467402.092779&cid=C013Y4VG20J, I'm not sure an incomplete download was responsible for the original problem--if the download was complete, I would expect the "Rebuilding..." message to never show up until you either delete the bin/tailwindcss file (thus triggering a redownload) or start a new project.
correct. The incomplete download is a new observation; I think the original issue might have been a throttled download as I surmised, so that the binary took a while to get downloaded (and then activated?)
re clj -M:dev dev yes, I do get a stack trace:
$ clj -M:dev dev
[main] INFO com.eelchat - starting: com.biffweb$use_aero_config@7bd9c6f7
[main] INFO com.eelchat - starting: com.biffweb$use_xtdb@5ec8af0d
clojure.lang.ExceptionInfo:
{:proc #object[java.lang.ProcessImpl 0x581a6939 "Process[pid=33827, exitValue=137]"], :exit 137, :in #object[java.lang.ProcessBuilder$NullOutputStream 0xf71c866 "java.lang.ProcessBuilder$NullOutputStream@f71c866"], :out #object[java.lang.ProcessBuilder$NullInputStream 0x4deca675 "java.lang.ProcessBuilder$NullInputStream@4deca675"], :err #object[java.lang.ProcessBuilder$NullInputStream 0x4deca675 "java.lang.ProcessBuilder$NullInputStream@4deca675"], :prev nil, :cmd ["bin/tailwindcss" "-c" "resources/tailwind.config.js" "-i" "resources/tailwind.css" "-o" "target/resources/public/css/main.css" "--watch"], :type :babashka.process/error}
at babashka.process$check.invokeStatic (process.cljc:111)
babashka.process$check.invoke (process.cljc:95)
babashka.process$shell.invokeStatic (process.cljc:646)
babashka.process$shell.doInvoke (process.cljc:622)
clojure.lang.RestFn.applyTo (RestFn.java:137)
clojure.lang.Var.applyTo (Var.java:705)
clojure.core$apply.invokeStatic (core.clj:667)
clojure.core$apply.invoke (core.clj:662)
com.biffweb.tasks.lazy.babashka.process$shell.invokeStatic (process.clj:4)
com.biffweb.tasks.lazy.babashka.process$shell.doInvoke (process.clj:4)
clojure.lang.RestFn.applyTo (RestFn.java:137)
clojure.core$apply.invokeStatic (core.clj:669)
clojure.core$apply.invoke (core.clj:662)
com.biffweb.tasks$shell.invokeStatic (tasks.clj:59)
com.biffweb.tasks$shell.doInvoke (tasks.clj:52)
clojure.lang.RestFn.applyTo (RestFn.java:137)
clojure.core$apply.invokeStatic (core.clj:667)
clojure.core$apply.invoke (core.clj:662)
com.biffweb.tasks$css.invokeStatic (tasks.clj:238)
com.biffweb.tasks$css.doInvoke (tasks.clj:206)
clojure.lang.RestFn.applyTo (RestFn.java:137)
clojure.lang.Var.applyTo (Var.java:705)
clojure.core$apply.invokeStatic (core.clj:667)
clojure.core$apply.invoke (core.clj:662)
com.biffwe[main] INFO xtdb.tx - Started tx-ingester
[main] INFO com.biffweb.impl.xtdb - Indexed #:xtdb.api{:tx-time #inst "2024-03-27T23:10:48.045-00:00", :tx-id 0}
[main] INFO com.eelchat - starting: com.biffweb$use_queues@23b30560
[main] INFO com.eelchat - starting: com.biffweb$use_xtdb_tx_listener@6938d886
[main] INFO com.eelchat - starting: com.biffweb$use_htmx_refresh@5d90b9a3
[main] INFO com.eelchat - starting: com.biffweb$use_jetty@5f43245a
[main] INFO org.eclipse.jetty.server.Server - jetty-10.0.7; built: 2021-10-06T19:34:02.766Z; git: da8a4553af9dd84080931fa0f8c678cd2d60f3d9; jvm 22+36-jvmci-b02
[main] INFO org.eclipse.jetty.server.handler.ContextHandler - Started o.e.j.s.ServletContextHandler@eb55e46{/,null,AVAILABLE}
[main] INFO org.eclipse.jetty.server.AbstractConnector - Started ServerConnector@40dd70bc{HTTP/1.1, (http/1.1)}{0.0.0.0:8080}
[main] INFO org.eclipse.jetty.server.Server - Started Server@7a37b645{STARTING}[10.0.7,sto=0] @9046ms
[main] INFO com.biffweb.impl.misc - Jetty running on
[main] INFO com.eelchat - starting: com.biffweb$use_chime@5f2017b1
[main] INFO com.eelchat - starting: com.biffweb$use_beholder@53978574
[chime-1] INFO com.eelchat.worker - There are 0 users.
[main] INFO com.eelchat - System started.
[main] INFO com.eelchat - Go to
b.task_runner$run_task.invokeStatic (task_runner.clj:47)
com.biffweb.task_runner$run_task.doInvoke (task_runner.clj:35)
clojure.lang.RestFn.invoke (RestFn.java:423)
com.biffweb.tasks$dev$fn__495.invoke (tasks.clj:281)
clojure.core$binding_conveyor_fn$fn__5823.invoke (core.clj:2047)
clojure.lang.AFn.call (AFn.java:18)
java.util.concurrent.FutureTask.run (FutureTask.java:317)
java.util.concurrent.ThreadPoolExecutor.runWorker (ThreadPoolExecutor.java:1144)
java.util.concurrent.ThreadPoolExecutor$Worker.run (ThreadPoolExecutor.java:642)
java.lang.Thread.run (Thread.java:1570)
nREPL server started on port 7888 on host localhost -
qtp717736374-47] INFO com.biffweb.impl.middleware - 37ms 303 get /app/chat
(I have my browser open to localhost:8080/app, btw; you can ignore that. Not sure if the second stack trace is due to that)clj -R:dev never seems to proceed to run for me:
$ clj -R:dev
-R is no longer supported, use -A with repl, -M for main, -X for exec, -T for tool
$
(a few more details, if they matter:
• I tried both with chmod 644, and chmod 744 with the borked bin/tailwindcss(running clj -M:dev dev does fix the chmod, but not the download)
• in both cases, the exit status is 1)sounds good, thanks for the info. I'll make sure clj -M:dev dev catches that error and prints a more helpful message. I'm also going to change it so that it waits until the tailwind binary is downloaded before it starts up the rest of the app--that should avoid the situation you ran into originally where the app was running but CSS wasn't working yet.
ok well. I just noticed a "Rebuilding..." message in the console; and now I am good. No more 404 on the css. Gotta say that is unexpected though
what is/are the condition/s for triggering the rebuild? I just tried it again from the start... and I am getting 404 again on /css/main.css
CSS is compiled by the Tailwind watcher whenever it sees that you've saved a file. For experimentation, instead of running clj -M:dev dev, you can run bin/tailwindcss -c resources/tailwind.config.js -i resources/tailwind.css -o target/resources/public/css/main.css --watch which will do just the CSS bit. (See https://github.com/jacobobryant/biff/blob/09ef8cef88cb699c67de124cbb472bbff0142d69/libs/tasks/src/com/biffweb/tasks.clj#L281 and https://github.com/jacobobryant/biff/blob/09ef8cef88cb699c67de124cbb472bbff0142d69/libs/tasks/src/com/biffweb/tasks.clj#L238 for the relevant code from clj -M:dev dev). It sounds like the problem might just be that the tailwind watcher takes a long time to build the CSS for some reason--when I create a new project, I get the Rebuilding... message (which comes from bin/tailwindcss) before I have a chance to open localhost:8080 in the browser anyway.
How about try starting a new project, but instead of running clj -M:dev dev, run clj -M:dev install-tailwind to download the tailwind binary and then see how long a first run of tailwind takes? e.g. on my machine the bin/tailwindcss command completes in under a second:
0 tmp $ clj -M -e '(load-string (slurp ""))' -M tutorial
Enter name for project directory: eelchat
Enter main namespace (e.g. com.example): com.eelchat
Your project is ready. Run the following commands to get started: cd eelchat
git init
git add .
git commit -m "First commit"
clj -M:dev dev Run `clj -M:dev --help` for a list of available commands.
(Consider adding `alias biff='clj -M:dev'` to your .bashrc) 0 tmp $ cd eelchat/
0 eelchat $ clj -M:dev install-tailwind
Downloading the latest version of tailwindcss-linux-x64 ...
If that's the wrong file, run `clj -M:dev install-tailwind <correct file>` After the download finishes, you can avoid downloading Tailwind again for future projects if you copy it to your path, e.g. by running:
sudo cp bin/tailwindcss /usr/local/bin/tailwindcss 0 eelchat $ time bin/tailwindcss -c resources/tailwind.config.js -i resources/tailwind.css -o target/resources/public/css/main.css
Rebuilding...
Done in 296ms.
real 0m0.904s
user 0m0.948s
sys 0m0.199s thank you for that helpful note! it might be that the download is throttled or otherwise "security firewalled" for some reason (that's my guess). On a second try of running the setup shortly after the first, it appears that bin/tailwindcss never got to download in full^: I see that its size is at 25M (as opposed to 45M for another run of the tutorial, but this time with the CSS working); and chmod 644 (as opposed to 744)!
Obviously with 644, it wouldnt run. I also tried running it directly (after an appropriate chmod); and got Killed: 9. I'm willing to bet that's because the file is incomplete.
^ like never; I did shut the laptop a few minutes after (I think) seeing that I was making no progress with the CSS problem.
MORE: as an experiment, I tried to basically simulate an incomplete download of tailwindcss in another tutorial directory ("dd if=... of=... count=..."), and then tried to run clj -M:dev dev. It would appear that there is no error recovery (besides setting the right chmod based on observation) if tailwindcss is not downloaded properly.
Another question… what is a good strategy for passing down the current user’s context to nested components? Is it [{:keys [session biff/db] :as ctx}] then db and ctx all the way down?
Yeah, anything that needs access to the database/config/whatever, you can just have it take ctx as a parameter. Alternatively you can have the parent query stuff from the database and then just pass the results to the child--you just have to decide which way makes more sense for the situation.
I'll be experimenting with a fancier/more organized way to go about this sometime... this year... but in the mean time, passing ctx around is what I'd do 👍
Any tips on setting user timezones? I could gather it from the user’s browser with js and then add it, say, via /app/set-timezone to their user document in xtdb. I just want to display things in the UI correctly for them.
I would store everything as GMT, and then use the browser's TZ to convert it at display time. There's not much sense in storing their TZ because they'll move around, DST will start/end, and who knows what else.
OK, that sounds like a plan. thanks! I am thinking hard about this one… I want to track things I do ‘per day’ so it’s interesting to think about what that means if one hops on a plane, for example.
I've been using this for personal tracking purposes. It's nice to have something sort of pre-built to do the job. Along with that I've been writing some code to make Heedy easier to deal with. https://heedy.org/
But yeah, if you want to track events like that and you travel a lot, recording the TZ of the event is a good idea.
Oh, nice! heedy looks neat… cool graphics, too.
I’ve been using ApexCharts which is rolled into Flowbite (built on top of Tailwind). https://flowbite.com/ and https://flowbite-admin-dashboard.vercel.app/
Per my other question in the channel, now figuring out the most elegant way to pass down ‘props’, if you will, to the chart components. But I digress.
Agreed with converting timestamps to the local timezone at display time. Here's one example of how to do that: https://clojurians.slack.com/archives/C013Y4VG20J/p1692808765328769?thread_ts=1692778099.752249&cid=C013Y4VG20J
👍