Fork me on GitHub
#clojurescript
<
2021-11-24
>
quoll03:11:14

If there is a function in Clojure that ClojureScript were to take on, and the Clojure implementation were to throw an exception on nil input, then should the ClojureScript implementation throw an exception as well?

quoll03:11:00

I’m asking, because I’m trying to port clojure.java.math into ClojureScript (and I’m asking Alex why that namespace has to be in clojure.java). Most functions have a 1:1 correspondence with the functions in js/Math. However, the function clojure.java.math/ceil will throw an exception when it is given nil. But (js/Math.ceil nil) will return 0. If I’m trying to duplicate Clojure, then should I throw an exception as well?

Alex Miller (Clojure team)03:11:38

if you're talking about the parse functions, please note that the Clojure implementations do not specify any behavior for non-string inputs so I'd say throwing an exception on nil there is non-normative

quoll03:11:04

no… I was adding to a thread when you responded. I’m good with the parse functions. It’s things like ceil

Cora (she/her)03:11:31

if I had a library that depended on that and was making it work for both clojure and clojurescript I think I'd want it to work the same

quoll04:11:12

That's what I'm thinking. It seems strange to throw an exception when I don't need to though. 🙂

Cora (she/her)04:11:44

it seems strange to return 0 for null with that function, too, though?

quoll04:11:56

The Mozilla JS docs specifically mention it for ceil, though not for floor (which also does it)

emccue04:11:01

i mean, not to be that person - but we have some “alt” clojure implementations like clojerl, upcoming clojuredart, clojure clr, etc. I don’t personally use them, but i would empathize with the goal of keeping what “clojure” is to a minimum

emccue04:11:23

since its already a fairly large task to port over the standard library

emccue04:11:55

and in all this time there wasn’t any “unifying math ops” clojure library that the community really stuck to i don’t think

quoll04:11:27

OK, but math libraries can be reimplemented on various platforms. Things like file system operations can't be, since some platforms don't have filesystems, and even if they do, the io operations tend to be tied closely to the platform implementations

quoll04:11:40

Every time I have to write #?() I shed a tear 🥲

seancorfield05:11:22

Imagine a seasoned Clojure developer coming to ClojureScript for the very first time and wanting to build an SPA (backed by Clojure). What is considered "state of the art" these days in terms of a) libraries/frameworks and b) tooling? Temper that with someone wanting to avoid JS/node/npm as much as humanly possible. In addition, what are the options for a non-React-based approach (assuming they don't want to build native apps, just web apps)?

quoll06:11:02

sorry, I’m unfamiliar with SPA

seancorfield06:11:18

Single Page Application, sorry.

seancorfield06:11:07

(maybe I'm showing my age and they're no longer called that? I dunno, the front end scene moves so fast 😐 )

quoll06:11:44

I’m familiar with the term, but not the acronym 🙂

1
Arthur12:11:11

I am still a beginner, but as far as I can tell most single page applications are being built using shadow, reagent and re-frame - the whole “re-frame way of doing things/handling state” is just super good. I had a great experience building apps using these technologies so far. There isn’t much need to touch npm/node stuff using shadow. I’ve also heard lots of great things about Fulcro, but couldn’t yet give it a try.

1
Colin P. Hill13:11:40

Worth noting for anyone unfamiliar with that stack: Re-Frame is built on Reagent, which is built on React, so Sean's additional question at the end is open even if Re-Frame answers the rest

☝️ 1
Adrian Smith14:11:28

I think react server components are going to be the next big thing with wide adoption, it might be worth trying to see how far introp can go with react server component frameworks can go: Nextjs/Hydrogenjs If you're interested in future cljs stuff I would investigate fulcro and even further maybe hyperfiddle/proton If you just want to get building now with something that should last a while I'd still go with re-frame

Michaël Salihi17:11:28

If you want to write a SPA like you do a normal backend Clojure, Inertia may be interesting: https://github.com/prestancedesign/inertia-clojure

Michaël Salihi17:11:08

@seancorfield As an example of the simplicity to refactoring into SPA, I adapted your usermanager project with this adapter in not to much lines. • https://github.com/prestancedesign/usermanager-reagent-inertia-example • Here is diffs: ◦ For the backend changes: https://github.com/prestancedesign/usermanager-reagent-inertia-example/commit/9e4bfb86d610d7467ef506981da68ec597bd31f3 ◦ For the Reagent front-end implementation: https://github.com/prestancedesign/usermanager-reagent-inertia-example/commit/da60bc0f31b2d73ccd2ae9a95fae3dc862978211 You can think with Inertia that you use Reagent as a template engine and the app state continues to live on the back.

Michaël Salihi17:11:47

Last but not least, a more complete fullstack project example: https://github.com/prestancedesign/pingcrm-clojure LMK if you have some feedback or questions.

borkdude18:11:58

@seancorfield I recommend just learning reagent first and make some basic CRUD stuff

borkdude18:11:50

If you don't want to mess with npm, for learning, you could of course try https://github.com/kloimhardt/babashka-scittle-guestbook which lets you just edit an HTML page and run it directly ;)

borkdude18:11:07

But if you want to set up a CLJS project I'm sure you can find a template to get started. And then just read the Reagent tutorial.

borkdude18:11:25

For tooling, #shadow-cljs is a very popular solution which gets you going quickly. It has built-in reloading etc. But it does force you to use npm.

borkdude18:11:44

You can also go the figwheel route but it isn't as actively maintained nowadays

seancorfield19:11:50

I've worked with Reagent and re-frame in the past and liked the Figwheel Main workflow. As I said, this is more a hypothetical question about what other options there are for real apps.

borkdude19:11:05

Yeah, that additional question is interesting to me too. React does seem to be the mainstream option.

Chris McCormick22:11:26

@seancorfield when you say "wanting to avoid JS/node/npm as much as humanly possible" would you be ok with running one npm command? If so, you could do this to get started:

npm init shadowfront myspa
cd myspa
make watch
which will set up an SPA project using shadow-cljs and Reagent and then start the server. If you want a full-stack app written in cljs (e.g. backend in cljs too) you could check out #sitefox using a similar npm command:
npm init sitefox-shadow-fullstack myspa
the instructions for using it are printed on the screen and there will be a README in myspa .

👍 1
Chris McCormick22:11:44

@seancorfield just to add one other alternative to the mix which might be nice if you really hate JS - there is http://htmx.org which is available via: https://github.com/whamtet/ctmx "https://htmx.org/ enables web developers to create powerful webapps without writing any javascript."

1
👍 2
borkdude22:11:57

I also thought about mentioning that one. There is also https://alpinejs.dev/ which is "lite" approach

👀 1
cdeszaq00:11:11

I’m curious where the desire to avoid JS comes from when the goal is to build a web app where JS is the runtime. It would be like trying to build a complex, performant, Clojure-based service with a minimal deployment artifact size, but avoid Java/JVM as much as humanly possible. Such a thing seems odd, so more info about where the constraint is coming from might help surface other options. Clojure’s roots as a hosted language seem to be naturally against that desire. Clojure is at its most powerful when used as a high-level language for thinking / solving problems while leveraging the host language/runtime for the heavy, undifferentiated lifting and plethora of existing libraries. Why avoid the host instead of embrace it?

👍 1
Michaël Salihi05:11:33

Good suggestion @UUSQUGUF3 Yeah it's even possible to run webapp with htmx + babashka so fast! https://github.com/prestancedesign/babashka-htmx-todoapp

Chris McCormick12:11:15

@UFBL6R4P3 really cool, thanks for sharing!

👌 1
Michaël Salihi14:11:33

Thank to you @UUSQUGUF3. BTW many of your projet, like more recently Sitefox are awesome! ;)

🙏 1
borkdude10:11:06

I saw this project now as well: https://www.solidjs.com/ Never heard of it, but asciicinema appears to be using it (they switched from CLJS to pure JS for performance)

cdeszaq15:11:14

I’d love some clean bindings from Cljs to solidJS if anyone builds/runs across some. “reagent using solidjs” would be rather nice I think.

borkdude15:11:05

@U02MRUJUREH Perhaps helix by @U4YGF4NGM could provide a good start, since that is a lite wrapper around React

cdeszaq15:11:06

Good idea! I’ll poke around with that as a starting point the next time I get a few moments. If anything comes of it, I’ll be sure to share.

lilactown18:11:46

was thinking about this last night. it looks like solid does something at compile time to wrap their JSX forms in a reactive context which would probably have to be replicated at macro time. but a helix-like binding to solidjs seems like a fun project 🙂

👀 2
seancorfield05:11:18

(this isn't me, it's a hypothetical person -- I'm genuinely surveying what's on offer, based on those criteria)

quoll06:11:23

The hypothetical person you’re describing is me 🙂

quoll06:11:11

Though I’ve recently acknowledged that I need to learn React. I’ve started, but haven’t gotten very far yet

seancorfield06:11:23

I started with cljs back in 2013/14... it was pretty much Om or nothing. Then Reagent appeared. We did a p.o.c. at work with Om, then rebuilt it with Reagent, then decided cljs wasn't really ready for primetime and gave up on it.

seancorfield06:11:16

I revisited things in late 2020 or early 2021 (time is elastic) and looked at Shadow and Figwheel Main which were both light years ahead of what was around in 2014. And it seemed that re-frame was the latest "best practice". But I'm curious as to what is available other than React-based stuff. Hoplon was pretty interesting when it came out but I don't know how well-maintained / popular it is these days.

seancorfield06:11:47

I had a feeling I'd seen a few recent announcements of cljs stuff that didn't use React and wondered how widespread that sort of thing is.

thheller06:11:28

I'm "working" on something and once Life stops getting in the way I'll finish it and document it. It is working but not documented as of now, so absolutely not widespread. I think I'm the only one using it in production and I only know of 2 other people playing with it otherwise

quoll06:11:31

Most of the world is enamoured with React these days, though I keep hearing about a few others, like Vue and Riot

thheller06:11:50

the JS world has many other large players. Svelte, Angular of course and not to forgot the everlasting jQuery

thheller06:11:11

> Most of the world is enamoured with React these days

thheller06:11:41

IMHO that is sort of a distorted look if you look from the CLJS perspective since that is the only option that works to be used from CLJS

thheller06:11:59

Vue is bigger these days overall I'd say

thheller06:11:38

but the react model itself is larger overall since there are other libs that do similar stuff

thheller06:11:08

its definitely the largest when looking at react-native

quoll06:11:25

I don’t actually look at it from the CLJS perspective. I’m looking at it from the perspective of my peers who mostly all work in UI, and what they report that they’re using. React still seems to dominate. But a number of them talk about Vue

quoll06:11:51

At least in the DC region, this describes most of the people I know in WWC who aren’t doing Python/datascience

thheller06:11:28

yeah no doubt react is large

quoll06:11:36

I know someone mentioned another framework recently, but I can’t recall it (it’s 1:30am, and my head hurts)

Cora (she/her)11:11:03

and typescript is by far the most dominant flavor (I'm a big fan, myself)

cdeszaq16:11:37

In many ways, those SPA frameworks mentioned above are solving problems that CLJS solves at the language level. If you look at an application as a bunch of events, logic to handle them, some logic to make network calls (in many cases), and some logic to render stuff to the screen, the only “hard part” that CLJS doesn’t really solve directly or easily is converting data structures into efficient DOM updates (which is what “render stuff to the screen” means for a web app). With that lens, Reagent is doing exactly that by leveraging React as a library in much the same way any other host-level library would be leveraged to do heavy lifting anywhere else in the Clojure(Script) ecosystem. If you boil it back, any DOM-Diffing/Updating library which offers fairly easy interop w/ CLJS would work fairly well, since that’s the bulk of what Reagent is using React for. Some of the other mentioned frameworks do / don’t fit that mold, but React does so quite well and is therefore a fairly natural choice to fill that gap.

zeitstein16:11:26

> https://github.com/thheller/shadow-arborist https://github.com/thheller/shadow-experiments I'm aware of this and would be excited to hear more about it, @U05224H0W! Svelte is a joy to use (and I feel it's really going to take off), but it's "magic" can get in the way (also, mutability...). SolidJS is another interesting approach, and closer to React. Don't have much experience with Fulcro, but it seems incredibly well put together so far.

👀 2
Cora (she/her)17:11:28

any of the ones that depend on compiler tricks to work, like Svelte, are unlikely to end up usable by CLJS, imo (if that matters to you)

Cora (she/her)17:11:50

anyways, I'm very much a polyglot and I feel like type checking via TypeScript on the frontend so dramatically improves development that it's worth using something other than clojurescript. I can't stress how good typescript is

zeitstein17:11:42

> any of the ones that depend on compiler tricks to work, like Svelte, are unlikely to end up usable by CLJS, imo (if that matters to you) Right, I was hoping SolidJS would be more amenable.

cdeszaq17:11:29

> type checking via TypeScript on the frontend so dramatically improves development that it’s worth using something other than clojurescript How does TS compare to Spec? In my experience TS is good for fairly basic data-oriented checking, but I end up spending more time and verbosity getting the signatures right than actually implementing the logic whenever I’m doing higher-order, more functional work and processing data.

Cora (she/her)17:11:14

> How does TS compare to Spec It doesn't, really. TS is miles better, especially with editor integration. It really shines on the frontend because code on the frontend is so volatile. It's incredibly helpful to know when changes in one part of the app affect another part of it. It dramatically reduces the number of tests needed to catch regressions and lets you focus on just testing bits relevant to the feature instead of exercising the whole thing.

Cora (she/her)17:11:58

I don't find I have as much of a need for these things on the backend, things are more straightforward and there are fewer moving parts and less necessary coupling

Cora (she/her)17:11:42

I didn't think it was a good idea, TS, until I started doing big frontend apps in it and suddenly you could see how much it mattered to have that safety net.

Cora (she/her)17:11:20

I don't find I spend much time on getting signatures right anymore and the gains are huge. relatively small investment for huge gains.

Lu20:11:50

I've been using TS in prod for 6 months and I can say that once the whole “types” concept clicks, you become much more productive. When the types are placed in strategic places, TS can infer most of the argument types so there's no need to type everything . Also, the autocompletion on any prop is the killer feature for me.

Cora (she/her)21:11:07

also, as long as you validate invariants for data coming back from API calls then having the shape of the data available literally anywhere in the application is just amazing. it makes for nice exploration of APIs, too, when you can just use intellisense to look for functions you can call

Cora (she/her)21:11:04

remix is a just released framework for frontend that has the data fetching and variant validation built in, it's pretty slick https://remix.run/

👍 1
Cora (she/her)21:11:49

we usually use nextjs and we use next to proxy to our Clojure APIs in development so there's no CORS madness

Cora (she/her)22:11:16

I'll probably try out remix soon just because it's so batteries-included

tony.kay23:11:00

So, disclaimer, I’m the author of Fulcro. I would first say that avoiding npm and React seem like bad ideas from a business perspective. You’re going to want to be able to use pre-written components. Writing everything from scratch seems quite a poor idea IMO. I use Big.js for isomorphic bigdecimal support, toast components, cljc.java-time (which uses js-joda), dropdowns…there’s a lot of logic and CSS to get these things right, and eschewing them puts you at a distinct disadvantage. Fulcro is built with a graph-based full-stack story in mind. Sure, it’s easier to get going with other things that are front-end only, but then you end up writing quite a bit of logic when your application needs to talk to the world (which it inevitably does). There are real hard problems there: tempid resolution in the context of in-flight network requests, sequential transaction behavior (in what order do mutations arrive at the server?), dealing with a queue that has semantics that are sane for reads vs writes when combined in an async environment. The list goes on. It’s sort of like how state machines rarely get used: not because they’re a bad idea, but because by the time you realize you need it you’ve written 1000s of lines of code that you don’t want to throw away, so you don’t end up porting. Easy to get started, but hard to evolve. When you have a full-stack design and patterns for the application as more of a data model that layers the UI on top, then all sorts of nice things fall out, which is how I came to the rapid-app dev tools for Fulcro, which can generate the network API, and many basic reports (and most forms, even when nested) from that data model with just configuration options. All without layers of hairballs. The main downside right now is not enough documentation on RAD, and possibly too much documentation on Fulcro 😛 It is true that you can’t jump in as easily.

1
seancorfield00:11:51

@U0CKQ19AQ I've promised myself that one I will look at Fulcro... I will say that when I originally tried to build stuff with cljs, back in 2013/14, I used Om for the first version of the app and didn't like it, then I rebuilt it with Reagent and liked that a lot better. I looked at cljs about a year ago and settled on re-frame and Figwheel Main that time and liked it better. But I see the JS tooling my front-end team mates have to deal with (our front end is React.js etc, not cljs) and I just shudder at the giant mess that whole ecosystem is...

tony.kay00:11:48

I agree npm is a mess. Choosing carefully from what is there is certainly important. npm install hairball is definitely much more probable. I do mostly business app programming. Forms and reports are 90% of the stuff. The other day I was working with someone that had been using other cljs front-end things and I said, “well, let’s put together a form for that (using RAD).” About an hour later he said “Wow, when you said let’s put a full-stack form together I thought we were in for a day’s work, since that’s what I’m used to”. That’s where the lack of docs on RAD is a sad misfortune. It may not fit your needs for various reasons (it currently has the best out-of-the-box experience on greenfield stuff using Datomic). Just saying “it works really well for me”, but I guess you’d expect me to say that 😄

seancorfield00:11:19

Our backend is and will continue to be Percona (MySQL) for the foreseeable.

tony.kay00:11:32

so, I did write an alpha SQL db plugin for RAD. To be honest all a plugin does is generate ID-based resolvers for you (which you usually want to augment by the time you get to prod for security) and implements the logic for saving forms. Fulcro’s forms send a minimal diff of what changed on the form, which is pretty easy to morph to database updates/insertions. The saves come across as:

{[:account/id id] {:account/name {:before "Joe" :after "Sam"}}
 [:user/id id2] {:user/accounts {:before [] :after [[:account/id id]]}}}
etc. A flattened description of all of the “entities/rows” that changed. Pathom makes the data resolution story pretty dreamy as well.

tony.kay00:11:26

so, really, Fulcro usage isn’t any different, but if you were using RAD it would require a bit of setup. The Datomic plugin is like 400 lines of code? An SQL one is a bit harder because of how joins/constraints work (e.g. can you check constraints only at commit, or do you have to do a sort of the changes to get the order right).

zeitstein08:11:26

Speaking as somebody who has been learning Fulcro for the past week – it is not as daunting as it might seem. Sure, you open the https://book.fulcrologic.com/ and see 37 chapters and... 🙂 But, chapters 2-4 are enough to start with and do a great job of giving an overview and teaching the core concepts step-by-step. I did have to actually think and synthesise the information, but it only took 2-3 days. (If that's not working for you, there's https://www.youtube.com/playlist?list=PLVi9lDx-4C_T7jkihlQflyqGqU4xVtsfi and https://fulcro-community.github.io/main/index.html.)

dnolen13:11:16

@seancorfield non-React - you can just rely on Google Closure Library (GCL)

2
seancorfield19:11:23

I would imagine that leans heavily on JS interop and requires quite a bit of JS knowledge?

cdeszaq23:11:21

ClojureScript largely just exposes GCL as a massive blob of standard library functions. They are often called via the host interop mechanisms (similar to calling Java stuff from Clojure), but you largely don’t need deep JS knowledge to leverage it highly.