Fork me on GitHub
#beginners
<
2023-01-09
>
Sachindra Ragul00:01:19

Hi. I’m new to clojure. Started with Kit framework. I’m unable to connect to clojurescript shadow-cljs repl. Anyone has experience with this?

Ben Lieberman00:01:14

Idk what your setup is like but I've had success starting a cljs repl in the terminal and then connecting to that in my editor

Ben Lieberman00:01:16

https://shadow-cljs.github.io/docs/UsersGuide.html#_repl the shadow users guide is helpful in my experience as well

Sachindra Ragul01:01:52

from kit docs, i could see npx shadow-cljs watch app starts the repl in port 7002. But what i’m seeing is this which is running on different port

Sachindra Ragul01:01:18

This port is different and when I try connecting to this port from emacs, I get “sync nEPL request timed out” error

Ben Lieberman01:01:40

I'm no expert in the matter but I do believe port 9630 is where the websockets for the app watch are running

Ben Lieberman01:01:38

Theres a #C6N245JGG channel tho where you will get better answers

2
Sachindra Ragul01:01:11

Thank you. I could already see some improvements from the links you have shared.

Ben Lieberman01:01:11

The last time I did CLJS I think i just used npx shadow-cljs clj-replin my terminal

Ben Lieberman01:01:39

I think there's a corresponding command for a cljs repl as well

Sachindra Ragul01:01:56

I just changed the ports. Its working now. Thank you!. Seems my machine is somehow interferring with the default ports given in kit framework

😎 2
skylize02:01:51

The 9630 port shown in your screenshot is not your app. That is the Shadow CLJS service. Opening that that port in your browser shows a Dashboard (which includes a link to the local address of your app when it's running). You typed Ctrl-C at the bottom of the screenshot, before either an NRepl server or an HTTP server had a chance to start.

Sachindra Ragul02:01:36

Yeah I got it figured out. Thanks!

👏 2
Mattias10:01:44

What is the state of Clojure editors (perhaps IDEs) in 2023? I was happy with Atom, now using VSCodium but want to leave it. Both because I’m not clicking with it, but maybe more for ideological reasons. I’m after something really simple. If I could have syntax highlighting and basic REPL integration I’d be happy. Don’t need refactorings or… almost anything. My specific situation is such that I spend the odd hour here or there doing Clojure and so ease of use and getting up and running quickly is helpful.

Adrien Blavier10:01:51

emacs my man

👍 6
parens 2
delaguardo11:01:13

almost every modern IDE have clojure packages with mostly the same set of features. I would recommend stick with IDE you know the most

👍 4
moe11:01:55

Doom Emacs without the evil-mode junk (just comment it out in init.el, uncomment (clojure +lsp), install clojure-lsp) and you should have a relatively smooth experience with clojure-mode, Cider & LSP

Mattias11:01:44

I’m partial to emacs (and have opinions on the “easy” part), have used it in the past (somehow at the same time I discovered muds…). I’m most often on a Mac, any special considerations with emacs?

Adrien Blavier11:01:41

I would just recommend reading the detailed install guide for mac on the doom emacs github page. If it looks too daunting or tedious, then pass

Mattias11:01:18

Great, thanks 😀

jaihindhreddy11:01:21

I haven't used emacs in many years, so can't compare, but I found Sublime Text 4 to be a very pleasant experience, with clojure-lsp providing autocomplete and linting (clj-kondo), and https://github.com/tonsky/Clojure-Sublimed providing syntax-highlighting and nREPL-connection.

2
sublimetext 2
dharrigan12:01:16

vim + conjure is the bees knees!

😎 4
2
dharrigan12:01:26

(coupled with clojure-lsp) 🙂

practicalli-johnny13:01:39

For the criteria specified in the original post, then all the common editors would suffice. I suggest SublimeText and ClojureSublimed is the simplest in terms of install / configuration

💯 2
👍 2
practicalli-johnny13:01:25

If opting for Emacs, I found https://github.com/d12frosted/homebrew-emacs-plus the most useful approach to install on the MacOSX Using a config for Spacemacs or Doom can simply the installation, assuming the features are congruent with your workflow https://practical.li/spacemacs/ https://practical.li/doom-emacs/

🍻 2
simongray18:01:17

Been using Intellij with Cursive since 2018 and it still works fine.

🙌 2
Rupert (All Street)08:01:55

One more vote for emacs from me - but I go with the approach of installing vanilla emacs then picking and installing only the packages that I need. The benefits to me (1) I find it's a smaller learning curve compared to a full kitchen sink copy of emacs like Spacemacs (that has loads of preinstalled packages/special key bindings/modes etc). (2) Most generic emacs help on the web (e.g. the kind found on stackoverflow) is more likely to be useful.

👍 6
Empyreans14:01:31

Hello clojurians. I'm using ClojureScript, shadow-cljs with a node.js repl to interface some npm libraries which return complex objects that I need to inspect. For example #object[t [object Object]] . I can (js/console.log x) it, but it only resolves the first layer in, and I want to explode and inspect the object further. Preferably, I would want to inspect this object in the browser. But I need to use node.js for access to my filesystem. What would be the preferable way to go about this? I thought about sending the object to a dev browser, but it seems like overhead.

2
Empyreans09:01:17

This question was posed after a long programming session became frustrating 🙂 The answer is to prepare the data and use js->clj

Hans Lux14:01:48

What in your experience is the best way to handle nil in a threading macro? I'm thinking of something like this (-> id (query-user-db) (if-nil? (respond-error "user not found") (respond-mapped-user))) ; receives user as parameter But maybe there is a smarter pattern, that I don't know.

👀 2
dpsutton14:01:16

To my eye the threading is not doing any help here. You want a simple conditional on (query-user-db id). I’d use if-let of if in this case

Hans Lux14:01:55

I shortened the threading a bit for this example. I am doing (-> (:id request) (->UserId) (query-user-db) (if-nil? (respond-error "user not found") (respond-mapped-user))) I like the readability of that, but maybe I should just pass the result to a conditional.

elken14:01:47

Maybe some-> can help

dpsutton14:01:43

(if-let [user (-> (:id request)
                  (->UserId)
                  (query-user-db))]
  (respond-mapped-user user)
  (respond-error "user not found"))

👍 2
👏 2
dpsutton14:01:23

(or (some-> (:id request)
            (->UserId)
            (query-user-db)
            (respond-mapped-user))
    (respond-error "user not found"))
but i don’t like this style as much

Hans Lux15:01:37

thank you very much. The if-let version reads nicely. Since some-> can only solve this in combination with the or I don't like it as much as the if-let.

skylize15:01:14

The behavior of if-nil?, to call an else-branch with its non-nil input, is definitely not intuitive or obvious. Your original code looks just fine to eyes, if you just replace that weird function with a normal if construction.

(-> (:id request)
    (->UserId)
    (query-user-db)
    #(if %
         (respond-mapped-user %)
         (respond-error "user not found")))
And if you did need to explicitly check for nil (in contrast to a possible false), that would simply mean changing if % to if-not (nil? %), which still keeps the user-exists case in the passing branch where it intuitively belongs.

escherize19:01:13

If you have long bits of error prone code, failjure is pretty cool for monadic error handling: https://github.com/adambard/failjure#ok--and-ok-

Hans Lux19:01:34

looks promising, thank you for the hint.

Hans Lux20:01:15

@U90R0EPHA that is a very good point you are making there. That is simpler, nicer to read and easier to unterstand. But it does throw a compiling error.

skylize22:01:52

Yep. That makes sense; since I forgot to giftwrap the anonymous function 🎁.

(-> ...
  (#(if %
        ...)))

2
🙂 2
oly16:01:32

I am trying to resolve an old issue where I can't run some code inside a jar file, @alexmiller mentioned that I may need to define the ServiceImpl in the jar manifest, not coming from java I missing terminology, I am not sure what an impl is or where I can find out what I need to add to the manifest file. The service in question is bing ads, I have been running it from the clojure cli instead of the built jar but hoping someone can point me at anything that will help me fill in the blanks in my knowledge.

pavlosmelissinos16:01:28

What is the question? 🙂

oly16:01:49

well I guess if I need to add a service impl to the manifest, under what setting and how would I find out what the correct value would be 🙂

pavlosmelissinos16:01:25

Do you have a repro or a link to the original issue?

oly16:01:32

com.microsoft.bingads/microsoft.bingads {:mvn/version "13.0.13"}
This being the offending library that will not work in an uberjar

oly16:01:08

so basically if I run with clj -M:run it works but as soon as I build an uberjar it fails

oly16:01:31

unfortunately its not a public repo its an internal company project, this is the error I get when running from an uberjar

Exception: #error {
 :cause Cannot invoke "org.apache.cxf.jaxws.spi.WrapperClassCreator.generate(org.apache.cxf.jaxws.support.JaxWsServiceFactoryBean, org.apache.cxf.service.model.InterfaceInfo, boolean)" because "wrapperGen" is null
 :via
 [{:type java.lang.NullPointerException
   :message Cannot invoke "org.apache.cxf.jaxws.spi.WrapperClassCreator.generate(org.apache.cxf.jaxws.support.JaxWsServiceFactoryBean, org.apache.cxf.service.model.InterfaceInfo, boolean)" because "wrapperGen" is null
   :at [org.apache.cxf.jaxws.support.JaxWsServiceFactoryBean generatedWrapperBeanClass JaxWsServiceFactoryBean.java 670]}]

oly16:01:50

One of those problems I looked into ages ago never got very far so had to use a work around, hoping I can bring the job in line with all my other jobs

pavlosmelissinos16:01:42

it tries to call the generate method of org.apache.cxf.jaxws.spi.WrapperClassCreator for a null object, therefore you get that exception. This shouldn't return null but it does when you run the code from the jar: getBus().getExtension(WrapperClassCreator.class); I don't know what that means though (any idea what getBus() does?)

oly16:01:12

no idea, looking at https://cxf.apache.org/ makes me think it may read some kind of definition file that's not in the jar perhaps

pavlosmelissinos16:01:16

Ohh, getBus is a method of AbstractServiceFactoryBean which WrapperClassCreator extends, that's why it can access it directly (haven't touched Java in ages, totally forgot about inheritance 😐)

oly16:01:18

well this is where I struggle with clojure, never touched java so when it comes to interop and terminology It can be a struggle.

oly16:01:50

came to clojure from php and python languages mainly.

pavlosmelissinos17:01:49

Unfortunately this particular case is 100% Java, so as the saying goes, you ask for a banana but you also get the gorilla and the whole forest.

pavlosmelissinos17:01:58

I'm not sure why Clojure the JVM gives that stacktrace though. If a class definition was missing I'd expect a different kind of error. (something like class not found or something)

simongray18:01:08

> Ohh, getBus is a method of AbstractServiceFactoryBean which WrapperClassCreator extends, that's why it can access it directly this sounds like satire 😂 @UEQPKG7HQ

😂 4
Hans Lux18:01:14

Does it use the ServiceLoader to get the service impl? If so, you need to provide an implementation via a configuration file in META-INF/services The file in the services folder has to have the fully qualified name of the Service interface it implements. The content of the file is the fully qualified name of the Class that implements the service. For example The file in Meta inf is: META-INF/services/com.superb.java.Service The content of the file is my.superb.ServiceImpl ServiceImpl obviously implement Service. This works for clojure implementation with :genclass. Hope that is somewhere near you problem 🙂

oly13:01:40

@U04HGPMQJJG this sounds like it could be a possibility I will dig and see what I can find out, but this is the sort of thing I got the impression I may need to do.

oly15:01:20

is there any info on how you modify the content of MET-INF should i just create the files, or perhaps do I pass in some param to tools build config ?

Alex Miller (Clojure team)15:01:48

The write-pom task takes a map of props to set in the manifest (and you should use that vs making it yourself as the format is weird)

Alex Miller (Clojure team)15:01:20

I’m talking about the manifest file itself

Alex Miller (Clojure team)15:01:41

If you need other files, then yes you would need to either copy or make those yourself

oly16:01:38

okay thanks for that info @alexmiller does tools build give a way todo this or do you just create META-INF/services/file in your project and it gets included when the jar is built ?

Alex Miller (Clojure team)16:01:00

tools.build expects you to copy/create files that should end up in the jar in your classes directory, so the build process can either copy from somewhere (using copy-file or copy-dir tasks) or even spit it directly from the build process if that makes sense

oly16:01:36

okay great think I have some idea what to do I will give it a try thanks 🙂

oly16:01:07

if nothing else I am learning a bit more about jar and tools.build

2