Fork me on GitHub
Ashley Smith10:07:04

So I met my goals and learned a lot about reagent and setting up a web application. But now I want to learn how to make a standard webSITE. I know I could just write HTML and stuff, but I've fallen in love with reagent's (or is it hiccup's) way of describing HTML. Is there any way I can make a website using clojurescript that isn't a web app? As far as I understand it, a website's information can be picked up by a search engine, but because the use of react is all a javascript thing, it's not really the same thing? I guess I can make a web app without a login button though.. My thinking was, I wanted to practice making a forum just to test myself - but a web app may not be what I'm looking for as people won't be able to share the URL if it's all on one page, right? Or have I got this wrong?


If your web app URL’s have a # in them, they should work for sharing with other people. But you’re right about search engines not “seeing” the pages of a Single Page App very well — they don’t render the JS, they just look for regular HTML tags.


It’s easy to do web sites in Clojure, though, using hiccup, which is the [:div.class ... style of coding that reagent uses.


(Technically, reagent is using its own imitation of hiccup, but the syntax is the same.)


Embarrassingly, it’s been a while since I’ve done that, so apologies if I misremember anything, but the general idea is that you include the hiccup lib in your project dependencies, and then when a user goes to a URL like /site/home, the handler on the server side returns something like (html [:div [:h1 "Welcome to my home page!"]])

Ashley Smith10:07:03

@manutter51 ah I see. Right now I have a front end and a back end, whereas that sounds like just doing everything on the backend? I guess you could split the logic part into one program and the website into another program

Ashley Smith10:07:14

right now I have a clojure backend with a react front end so

Ashley Smith10:07:10

I have however just seen this: I know it's not got enough HTML to be seen by search engines, but at the same time, it does use multiple URLs. I think I could go with that compromise

Ashley Smith10:07:29

I need to think about it sure but I do like my current setup, an app that spans multiple routes would be nice


Yeah, React is more for Single Page Apps, but as long as you’re using URLs with the hash tag in them, you can bookmark them or share them or do whatever you like.

Ashley Smith10:07:40

that one I linked isn't using # s though, it seems like a regular website

Ashley Smith10:07:55

but its not really reloading any pages when you clikc things, it feels fast


Hmmm :thinking_face:

Ashley Smith10:07:27

I might go into the re-frame and re-agent channels to see what their opinion is


The advantage of using # is that it’s officially the URL for an HTML “fragment,” which is older than JS-based web apps, so the server knows what to do with it.

Ashley Smith10:07:07

yeah, like jumping down the web page, right?


You can actually set up reagent/re-frame not to use the #, and it works as long as you start from the right page, but then you get 404 errors if you try to go directly to any of the other pages first.


You could work around that by setting up your web server so that each of those URLs returned the same page, but that would be a lot of extra work on the server side.


Yeah, like jumping down the web page.

Ashley Smith10:07:22

I think I'm going to poke around a little more 🙂


Actually that ReForum app does hit the server every time you switch pages — you can see it in the Network tab of the browser dev tools.


There's no jdbc channel, so I'll ask here: Using java.jdbc and postgres, is there any way to use the "RETURNING" clause so I get back the row after updating? I tried among other things:

(rdb/execute! db [ "UPDATE books SET value1 = 1 WHERE id = ? RETURNING *") id])


I figured it out, execute also accepts :return-keys as an option and by passing true to it you get all of them back... so

(rdb/execute! db [ "UPDATE books SET value1 = 1 WHERE id = ? RETURNING *") id] {:return-keys true})
Works as expected, probably don't need the returning part.


the jdbc channel is #sql


Oh that's useful, thanks!

Alex Miller (Clojure team)15:07:59

I can't answer your question, but want to mention that another place to ask questions like this is


seems like a good idea.


Damn, can't. No github, only gitlab.

Alex Miller (Clojure team)15:07:49

thx, good to know - I will probably add other auth sources so good to know what people are using

Mario C.15:07:57

I am a little confused with the "compile-time" statement. What exactly is compile-time constant? Aren't they values that are determined at compile-time? If thats the case why use a conditional if you know the value already?

Mario C.15:07:28

Generally speaking most values I am working with are determined at run time


they are literally hard coded into the bytecode


they need to be known when compiling


and yes, things that aren't literal embedded values in your code, are run time data


but the number 10 inside a form, clearly is known when compiling that form - it's not open

Mario C.15:07:40

Okay got it. I can think of reasons to use it now

👍 4

@mario The first argument to case is an expression that is evaluated at runtime. The actual case branches must have compile-time literal values, so that case can perform a very fast compare-and-branch.


there are some funny gotchas with how case handles conditions

user=> (case 'quote 'foo :found :not-found)


And that one happens because...? (I haven't had my coffee yet)


that clause is actually (quote foo) - matching either the symbol quote or the symbol foo - reader expanded, but not evaluated


Oh duh! Of course. And I'm pretty sure that one's caught me out at least once...

Alex Miller (Clojure team)15:07:05

those funny gotchas are all explained in the case doc string

Alex Miller (Clojure team)15:07:21

which nobody ever reads apparently


who needs docstrings when you’ve got 🙂


@alexmiller while there's enough info between the reader documentation and the case documentation to know 'q as a case clause is actually (quote q) I think it's pretty easy to read it and fail to make that connection


it's a bug I've seen multiple times in the wild

Mario C.15:07:16

Okay so its the case branches that matter.. Idk how I could misread that. :man-facepalming: I thought it was the test value


is down? I haven't been able to reach it


ah - typing in my browser goes to http, which just spins forever

Alex Miller (Clojure team)16:07:15

this is a known issue, will fix it with a redirect if I can easily do so (but I don't think I can at the moment)


Oh duh! Of course. And I'm pretty sure that one's caught me out at least once...


How to read Clojure source code (the compiler)? Is there a guide or some Lisp's creators paradigm or a book on topic. Or I just to stare more into code 😄 Please advice!


this is afaik the list of some books which inspired Rich to write clojure. I think you can find some good books on lisp


this is big


it helps to understand the breakdown (typical to lisps) of read / eval / print, and the idiom of interface-only inheritance


I don't know of a specific guide though


also clojure's "eval" step mainly generates byte code

👍 4

Depending upon your learning style, adding System.out.println() calls sprinkled at various points in the compiler and trying to compile things may help you to learn what is going on more quickly.


They can also get pretty noisy pretty quickly, since if done unconditionally, can cause lots of printing simply while starting a new REPL.

✔️ 4

@kurva Use intellij and set breakpoints during analyze() and emit() then step through


It is informative to mute the breakpoints, start debugging a REPL, then unmute the breakpoints & type something into the REPL

✔️ 4