Fork me on GitHub
#clojurescript
<
2022-01-20
>
Taoufik Dachraoui11:01:11

I designed and implemented a new framework Ankbit Application Server, please have a look and any suggestions are welcome: https://www.youtube.com/watch?v=UPyEosj5zpY

🎉 1
emccue18:01:05

That looks really, really cool

Nazral11:01:41

is it possible to use definterface in clojurescript? Or something equivalent?

p-himik11:01:11

The underlying platform, JavaScript, has no interfaces, so no. What's the real problem you're trying to solve?

Nazral12:01:42

@U2FRKM4TW porting clojure code heavily relying on interfaces to clojurescript

p-himik12:01:42

Then it depends on why exactly a particular interface is used at a particular place. There are workarounds but I'm pretty sure there's no one specific workaround that would let you have all the things interfaces enable at once.

Nazral12:01:13

essentially there is a (definterface Foo (bar [x])) then a (deftype NFoo [^Foo y] Foo (bar [x] ...)) , and NFoo is used in many places with calls like (.bar nfoo somevariable)

p-himik12:01:47

I see. Usually people use protocols for that. But if you need an interface just to be able to use the dot form, then you can use Object instead:

=> (deftype X [] Object (bar [_] (println "bar")))
cljs.user/X
=> (.bar (X.))
bar
nil

Nazral12:01:31

Thanks for the help, I'll try that !

👍 1
Nazral16:01:36

Seems like it is working, thanks again !

👍 1
Asko Nōmm14:01:36

Hi! I have an odd issue where seemingly one core fn cannot be resolved, but others seem to work just fine. In this case all-ns gives an error of Use of undeclared Var app.components.icon/all-ns even though all-ns is supposed to be a clojure core function. Has anyone ever stumbled upon this and knows what I’m missing?

jkxyz14:01:07

You can't do runtime inspection of namespaces in ClojureScript because they get compiled away. So functions like all-ns don't exist in cljs.core.

jkxyz15:01:43

But I think you can get namespace data in macros using the analyzer: https://cljs.github.io/api/compiler/cljs.analyzer.api/#all-ns

octahedrion15:01:36

I haven't done any CLJS work for a while. What's the best way to use JS libs these days ? As far as I can tell: • shadow-cljs is the best for npm-installed dependencies, but doesn't have any obvious way to list those dependencies in your deps.edn or elsewhere so how do you know what npm dependencies the project depends on ? • CLJSJS allows you to list your dependencies in deps.edn, which I like because I like to see what all my dependencies are, but CLJSJS is out of date with most libs and requires quite a bit of work to add new dependencies (forking etc) • :foreign-libs is simple and you can see the dependencies, but you have to download them yourself, a minor inconvenience

Derek15:01:46

For your shadow-cljs bullet point, the NPM dependencies would be in your package.json and accompanying lock file (package-lock.json or yarn.lock)

octahedrion15:01:22

I'd prefer to keep matters as much under Clojure's control as possible though

Derek15:01:04

Not sure if still applicable but I’ve seen https://github.com/RyanMcG/lein-npm in the wild

octahedrion15:01:22

I'm using deps.edn

Drew Verlee15:01:35

shadow-cljs.edn can reference a deps.edn

Drew Verlee15:01:18

It makes some things harder though and is only worth if your using some other tooling in and around deps.edn, but it's not a big switch back and forth.

p-himik15:01:10

I always go with your first point. Managing JS dependencies should be done via JS tools. Otherwise it's a constant gamble on whether whatever mechanism you're using is recent enough to keep up with the current state of affairs in the JS world.

thheller19:01:22

IMHO the only viable option is to use the npm packages directly and keeping your package.json + lockfile in version control. whether thats npm or yarn doesn't matter much. also whether you let shadow-cljs handle the JS or something like webpack doesn't matter much either, your choice there

thheller19:01:14

one thing almost guaranteed to get you in trouble is ignoring package.json + lockfile and trying to "hide" them with something like lein-npm or similar stuff

octahedrion09:01:46

In the JS world it seems, as in the Python world, you install libs without reference to a version or namespace. In the Clojure world we specify libs by namespaced library name and version. It's this dichotomy which concerns me

p-himik09:01:26

That's incorrect - you do specify versions, both in the JS and in the Python world, but they are optional when you install something. By default, npm and yarn will simply use the latest release version if you omit it during installation, but the version must be present in package.json. There are two differences between JS and CLJS here though: • You have to install packages manually (there's no global analog to the .m2 folder, all node_modules are project-specific and are populated when you run the installation command) • Due to how version resolution works, there's an extra package-lock.json file that's necessary. You don't alter it manually but you do put it in your repo. During development, you use regular npm i which will change the lock file, during deployment you use npm ci which will use the lock file to ensure same exact versions are being used

thheller09:01:17

just to expand why you must keep the lock file. in npm it is very very common to use version ranges when declaring dependencies, most libraries do this. so even if you specify to depend on lib-a with exactly version 2.0.0, that lib may depend on lib-b version ^4.0.0. which basically means 4.0.0 or anything newer. so without a lockfile if you run install again you'll never know what you get. the lockfile ensures you always get the same.

thheller09:01:40

otherwise it is not uncommon to end up with lib-b version 4.5.0 that broke lib-a in some way and now you entire thing is broken. lockfiles save you at least that headache.

octahedrion10:01:48

@U2FRKM4TW yes but think of the difference between what you do when you want to use a Clojure lib vs a Python/JS lib when you read the github page: for Clojure you will see a namespaced library name and version number x.y.z/lib-name {:mvn/version "a.b.c"} to paste into your deps.edn whereas for Python/JS you will see npm install lib-name or pip install lib-name

p-himik10:01:54

It's not a namespace, it's a group. It's just a way to make names more unique, that's all. JS is slowly moving in that direction as well. And yes, you don't have to specify versions when installing a JS/Python lib. But you can if you want to.

octahedrion10:01:50

uhh in Maven terms it's a group, in Clojure terms that symbol's namespace!

octahedrion10:01:55

(namespace 'org.clojure/clojure)
=> "org.clojure"

octahedrion10:01:17

anyway zoom out - I'm talking about the difference in development process here

p-himik10:01:59

For symbols - yes. :) But we're in the context of dependencies. Library org.clojure/clojure is a library with name clojure that belongs to a group named org.clojure. Symbol org.clojure/clojure has name clojure and namespace org.clojure. The fact that at least deps.edn and project.clj represent library names as symbols is not central here.

octahedrion10:01:37

yes yes I know

octahedrion10:01:47

can we talk about the actual point of the thread

p-himik10:01:17

FWIW, from my perspective the main points have been exhausted.

octahedrion10:01:23

ok no need to reply then

octahedrion10:01:24

maybe it would help if I put it this way: if you had the choice between the Clojure way of managing dependencies (`deps.edn`) and the JS way, which would you choose for JS dependencies in CLJS projects ? If you could use the Clojure method would you ?

p-himik10:01:24

Before answering that question, I would have to read up quite a bit on how exactly NPM does its thing, decide on what the implications of any potential changes to those algorithms are, study the implementation of the CLJ solution for JS dependencies, and assess how much of a risk using it would be. Given that I don't really want to do all that and that using NPM is perfectly fine the vast majority of the time, realistically I would probably wait for a good few years and study other people's experiences and analyses before adopting such a solution.

p-himik10:01:20

And if that CLJ mechanism for JS dependencies is CLJSJS then the answer is a definite "no". I used to use it ~4 years ago or so, and I'm glad I've stopped.

thheller13:01:26

@U0CKDHF4L that is a pointless question. we gotta use what is available, not what we wish was available. we provided a lot of information, you can make your own choice. FWIW compare the "dependencies" of package.json and :deps in deps.edn and they'll look very similar. no difference if you ask me.

p-himik14:01:17

I think that question has merit - if I were willing to put time and effort into improving the situation by creating new tools, I would've probably asked the same question. After all, you yourself created a new tool at some point - you didn't settle on what was available. :)

thheller14:01:26

well sure that is always an option too 😉

thheller14:01:51

but note that the problem here really isn't in the tool. it is the entire ecosystem. if nobody was using version ranges you'd have a similar setup as in maven.

p-himik14:01:37

But hypothetically, can't a tool treat a range as a fixed Maven-like version?

thheller15:01:38

no? maven also has ranges, just nobody uses them because they are bad

thheller15:01:11

also npm has different conflict resolution strategy. that would also need to change. really you have to replace all of npm to make any meaningful change 😛

p-himik17:01:27

Ah, of course! Thanks. I managed to completely forget that Maven supports ranges. 😅

Mitul Shah16:01:47

Hi, I have kind of an odd issue. I’m currently using a component library that has a dialog trigger which is a button under the hood. You can pass a prop called as-child:true which will merge all props into the child component. However, if you have another component as the child, it doesn’t seem to work. This works fine in React, so I’m wondering if I’m missing something. Here’s a simple example, and https://www.radix-ui.com/docs/primitives/components/dialog

(defn dialog [children]
  [:> Dialog
   [:> DialogTrigger {:as-child true :aria-label "Placeholder"}
    children]])

(defn share-dialog []
  [dialog
    [button {:class "bg-black text-white"} "Open"]])

lilactown17:01:36

try calling reagent.core/as-element on children before it's passed to the DialogTrigger

👀 1
lilactown17:01:52

hmm not sure then.

Mitul Shah19:01:05

So, since a HTML <button> works with it. It’s probably that I need a way to pass props into <Button> with something like a forwardRef

Drew Verlee05:01:37

What is compiling that code into react? It might need to to pass a js object not a clojure hashmap. Are there errors?

Mitul Shah21:01:19

this is what we’ve had to do lol.. it’s still not perfect as it fails with other radix components, but very close

Mitul Shah21:01:59

hoping there’s an easier way at this point

tomc21:01:48

Hi all, using the latest clojurescript, set up according to the quick start, I'm getting warnings when using goog.labs.userAgent.browser . Any idea why this is happening?

(require '[goog.labs.userAgent.browser :as gbrowser])
;; => nil
(gbrowser/isChrome)
;; WARNING: Use of undeclared Var goog.labs.userAgent.browser/isChrome at line 1 <cljs repl>
;; => true
It's interesting that I get the warning, but then the function works just fine. Note that in a project more complicated than a quick start this is causing builds to fail.