Fork me on GitHub

Is it possible to somehow :refer some of the JS objects located in the JS namespace? It would make my CLJC code much more readable


i.e. so that I can just go Element rather than

#?(:clj Element :cljs js/Element)


#?(:cljs (def Element js/Element))?

👍 3

^^ makes sense


thanks @thheller - think I’ll go with that.


I think (:require ["$Element" :as Element]) also works using the new $ stuff


Ah, interesting. Maybe a bit too cutting edge, but I’ll keep it in mind.

Noah Bogart15:08:14

are there any recommended resources on how to structure a project that contains both backend clojure and frontend clojurescript files with deps.edn?


I have :server and :client aliases. keeps things clear wrt dependencies and avoids bloating uberjar with clojurescript etc

👍 3

and I just have src dir, with ns names making it clear that it's server or client specific code, e.g. foo.client... , foo.server..

Noah Bogart16:08:38

clj/ and cljs/ directories in src? Cool

Noah Bogart16:08:42

Oh interesting


well, you could have those as package names, but I have run into problems with having those as src dirs, esp when it extends to src/cljc , the project grows and you can accidentally have the same ns name appearing in both.

👍 3

For any project that is starting to get bigger I like to separate early so I usually follow a mono repo structure outlined here: I will often incubate libraries inside of their respective domains (backend or frontend) and then separate out if needed


I use version 4 right now with bb tasks and its solid


one simple way is src/clj and src/cljs

👍 3
Noah Bogart16:08:30

And then making the :paths point to one the other as the base?


or just :extra-paths for ClojureScript

👍 3

ClojureScript is built so most deps can separated from the service part


I don't really understand the claim there - never had any problems


the point of splitting them is because your service most definitely does not need to consider those files


also if you're going to AOT JAR the service, and put the files on a CDN etc. etc.


managing the classpath for these kind of usecases is important


In anycase, I don't know what shadow-cljs has to do w/ managing a JVM classpath in the big picture


shadow-cljs is also a build tool so it has nothing to do w/ your service part


Splitting by file type definitely makes it harder to look at things at a glance. > the point of splitting them is because your service most definitely does not need to consider those files How could a Clojure service consider CLJS files? How would putting CLJ/CLJS files together hinder that? > if you're going to AOT JAR the service A good point. I've never dealt with it myself, but I imagine excluding all *.cljs files should be trivial. Assuming it's bad for you to include CLJS files in there for whatever reason. > put the files on a CDN You mean, putting CLJ[S] files on CDN? But why? And if you mean the resulting JS bundle, then how is it affected by paths in any way?


personally I find it useful to have separate classpaths between client and server since I've run into dependency conflicts between my build tool (shadow-cljs) and server


Separate classpaths != separate directories for your source files.


Of course shadow-cljs should have its own classpath when building stuff. IIRC it's documented.


I just don't understand what is made harder?


why should my web browser stuff be mixed in w/ HTTP stuff


maybe that makes sense - maybe it doesn't


anecdotal - but I haven't worked on a project where combining the files made any more sense


For example, I have an app with three main parts in it - all three have their own separate root namespaces. All have their own front- and back-end code. Separating those by file type would split code for a single cohesive part into multiple places on the file system - so now e.g. grep is not as useful. Or tree. Or any other way you might want to work with files from a single cohesive unit.


Sure I can see that kind of project layout


but I certainly can not understand any claim for it being better - nor have I encountered a case where searching for stuff was seriously hindered by splitting the files - I'm just questioning the claim that there's something wrong src/cljs src/clj - it can be perfectly fine


It might be because of the how macros need to be used in clojurescript (


If you had to seperate all file types in different folders, it seems like that would be pretty clunky. Unless you ignored the convention and actually added .clj files inside your cljs folder, but at that point you are probably doing it more by app, or backend vs frontend, not necessarily by file type


Nobody used the word "seriously" before. :) > can not understand any claim for it being better Doesn't my example of using CLI tools show that? Even just grep X src/proj/part1 in comparison to grep X src/*/proj/part1 is better. It's not just two characters - it's additional cognitive load. Now you also have to have thoughts like "what's the right directory to put this file?" And if you migrate some file from CLJ or CLJS to CLJC, now you have to move it. Moving files is easy, but what if you made a change there? Now Git thinks it's a new file. And so on, and so forth. Superficial separation by file type and some optional semantics that are not always there, introduces problem points - conceptually, regardless of whether we're speaking of Clojure or not.


thinking that macro files wouldn't go in src/cljs


src/cljs src/clj could be src/server src/client - so maybe just talking past each other


Server/client is a tad better separation. But still - where do you put all the common code now? What if some code was used only by the server but now becomes common? All the same arguments apply as before. Except for maybe having client code in a backend jar, which is a questionable downside, I really don't see any issues with not splitting stuff either.


For common stuff you would just add a src/common folder to the class path for both. IME the grep thing isn't a big problem, people usually search in their IDE/editor anyway.


That was a rhetorical question. :) The point is - now you would have to think about things you wouldn't have to think about otherwise.


> people usually search in their IDE/editor anyway Different people can have drastically different workflows.


It's all extra hustle and extra cognitive load - but what actual, tangible, benefits does such an approach bring? My questions above have not been answered.


haven't had many cases for common dirs because if there's that much shared logic - it usually gets lifted in a lib


Needing to think about more stuff isn't something that only favors your structure though, @p-himik. For example, with your approach it seems like it would be harder to categorically rule out some backend-specific stuff getting executed on your frontend, because it is just a require away. By separating the front and back, that is impossible.


but yeah, I can see cases where that wouldn't happen, just haven't run into


generally when there is a true shared lib and it has to work in two different places, it's some reusable chunk that will need to appear in some other application / repo


> categorically rule out some backend-specific stuff getting executed on your frontend I struggle to imagine a situation like this that also wouldn't explode during compilation, but perhaps it is a point.


I will say - I don't have much insight into how Clojure / CLJS sharing works in the wild - for me it's obvious for libs - upstream deps


Perhaps we write our projects differently. Mine have a sizable amount of common code that's very project specific where it makes no sense to lift it in a lib.


but probably lots of use cases I just haven't encountered in the application itself


I want my malli schema to validate a url, is there a library for that? thank you 🙏


I found goog.string.linkify/URL_RE_STRING_ Looks like the regex I need


with a handy EMAIL_RE_STRING_ next to it 🙂


and more completely:

   (re-pattern goog.string.linkify/URL_RE_STRING_)


Aaandddd not what I was looking for. looks like this too accepts everything that comes after protocol:// as valid. But I guess there is no a one sized fits all solution, and I can use lambdaisland/uri to check for different conditions according to what my app needs.


(s/def ::url (s/with-gen (s/and string? (partial re-matches #"(http(s)?:\/\/.)?(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)"))
                         (partial gen/fmap #(str "" %) (s/gen string?))))
just an example


(s/def ::email (s/with-gen (s/and string? (partial re-matches #"^[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,63}$"))
                           (partial gen/fmap #(str % "") (s/gen string?))))


Thanks a lot! This is quite educational for me :)

👍 3