Fork me on GitHub
#clojurescript
<
2018-03-21
>
justinlee00:03:12

also i should mention that i hate java with the passion of a thousand burning suns šŸ™‚ that part is not rational though

john00:03:58

Well, you know clojurescript. So while you may never use it, you also have the power to do some serious thread thrashing in the future, if you want šŸ™‚

john00:03:09

in whatever domains clojure eventually lives on

john00:03:16

the jvm is pretty good though

justinlee00:03:49

just as an example of what i mentioned before, take when i first started reading documentation on core.async so I could do some remote calls. the first thing any book or online resource will say is ā€œgo blocks run your process on a thread poolā€ or something like that. you know immediately thatā€™s completely wrong, so you have a little bit of work to do to figure out whatā€™s going on. there are often places like this where the most thorough sources are clojure oriented and so thereā€™s a little friction. this is all i meant.

dnolen00:03:51

right but the problem there is the content

dnolen00:03:01

not core.async

john00:03:14

Yeah, but Clojure is an abstraction. We may all be using it on some completely different host one day, where the thing isn't called a thread pool. Your point that there is friction in the docs as a result is true though

dnolen00:03:41

Rich specifically designed core.async (really through CSP) to be agnostic to the underlying threading model

dnolen00:03:46

but I see your point, older Clojure information (and thus more Google-able) is often missing the expanded context to include CLJS

john00:03:07

at the last conj I actually had a very interesting conversation with Guy Steele

john00:03:39

I tried to put him on the spot and I asked, "So, what's your favorite part about Clojure?"

john00:03:30

He said that he believed that Clojure "got concurrency right."

john00:03:10

The quadrants of coordinated/uncoordinated and synchronous/asynchronous

john00:03:49

And how atoms, agents and refs answer each necessary quadrant in the "right way"

john00:03:27

And that's pretty much the only thing I've ever heard Guy say that I've actually understood, so it must be right šŸ˜‰

mfikes00:03:20

If you are interested in the upcoming ClojureScript 1.10.x a recorded talk on it is now available https://www.crowdcast.io/e/virtual-clojure-meetup-3

leontalbot01:03:48

Thanks a lot for this @mfikes

JJ00:03:04

@mfikes you need to register?

mfikes00:03:29

I didn't registerā€”I just went in with my Google account.

mfikes00:03:57

I think they have some sort of oauth setup with perhaps Facebook and other identity providers

gfredericks00:03:04

what do I need to setup to use react-dom with advanced compilation?

gfredericks00:03:36

I tried :infer-externs true and that didn't change the outcome, only added a compiler warning

gfredericks01:03:22

(the warning is that goog is not defined in the externs)

gfredericks01:03:50

looks like if I switch my call from react-dom/render to js/ReactDOM.render then the :infer-externs works ĀÆ\(惄)/ĀÆ

grounded_sage01:03:01

I wasn't going to share this because I was trying to figure it out myself but the error said to report it.

java.lang.IllegalStateException: EXPR_RESULT 35 [length: 3] [source_file: /Users/wade/Desktop/rn4w/node_modules/react-native-web/dist/vendor/Animated/AnimatedImplementation.js]
     java.lang.RuntimeException: INTERNAL COMPILER ERROR.
                                 Please report this problem.
                                 
                                 EXPR_RESULT 35 [length: 3] [source_file: /Users/wade/Desktop/rn4w/node_modules/react-native-web/dist/vendor/Animated/AnimatedImplementation.js]
                                   Node(NAME add): /Users/wade/Desktop/rn4w/node_modules/react-native-web/dist/vendor/Animated/AnimatedImplementation.js:35:4
                                 var add = function add(a, b) {
                                   Parent(VAR): /Users/wade/Desktop/rn4w/node_modules/react-native-web/dist/vendor/Animated/AnimatedImplementation.js:35:0
                                 var add = function add(a, b) {
                                 
     clojure.lang.ExceptionInfo: EXPR_RESULT 35 [length: 3] [source_file: /Users/wade/Desktop/rn4w/node_modules/react-native-web/dist/vendor/Animated/AnimatedImplementation.js]
    from: :boot-cljs

grounded_sage02:03:48

Ah I see @mfikes is this something I did wrong or because the Node ecosystem isn't quite there yet with the CLJS/Closure ecosystem?

grounded_sage02:03:03

For reference I am attempting to use the React Native for Web library.

grounded_sage02:03:45

I'm actually watching you Clojure meetup talk right now btw haha.

mfikes02:03:00

Dunno. But I suspect that a problem like that can be produced independently of ClojureScript, running the standalone Closure compiler against the offending JavaScript.

grounded_sage03:03:52

Ran the closure compiler against the directory and it worked

grounded_sage03:03:17

The error doesn't show when I don't require it into a namespace. So I believe it is something to do with requiring it into the namespace

grounded_sage03:03:10

Most likely an error on my end but I'm not sure what this could be. Not much written material about using NPM deps that I can find.

restenb04:03:29

how do you interact with javascript callbacks when working in clojurescript?

restenb04:03:13

if you for example have javascript like this

restenb04:03:42

how do I interact with doc.on('end' ...) in order to retrieve that value in result when it is available?

zentrope04:03:09

(.on doc "data" #(.push chunks %)) ?

zentrope04:03:31

Hm. doto might work.

restenb04:03:00

i'm trying to generate pdfs on a node server using macchiato

zentrope04:03:11

(doto doc (.on 'data' (fn ā€¦)) (.on 'end' (fn ā€¦)) (.end))

zentrope04:03:53

Does Buffer not have a constructor?

restenb04:03:19

i might have to just leave the js as is and rather interact with the callback function from cljs

restenb04:03:17

since this is all async operations, i can't just declare a buffer and then return it

zentrope04:03:33

(defn gb [] (let [buffer (Buffer.)] (doto doc ā€¦..) buffer))

restenb04:03:33

need to return it in the (.on "end) call

zentrope04:03:32

When doc.end returns, the buffer might still be ā€œin processā€ somehow?

restenb04:03:10

when doc.end triggers the printer is done writing data to the buffer

restenb04:03:28

all that's left is concat it, convert it to a b64 string and return it

justinlee04:03:31

you return it in the ā€œendā€ callback, so all you need is (.on doc "end" gb) where gb is the function @zentrope defined above

restenb04:03:56

but i'm pretty new to all this stuff so I get confused easily šŸ™‚

justinlee04:03:37

the Buffer. is the clojure syntax for new Buffer which may be confusing. i actually prefer to write (new Buffer)

zentrope04:03:44

Yeah, pass in a function that you call once the buffer is converted, or a channel (core.async).

justinlee04:03:39

oh yea it i suppose you might prefer to use a channel instead of mutating the chunks global. iā€™m not sure what exactly you want to accomplish. but either way thatā€™s how you deal with js event callbacks.

restenb04:03:54

essentially trying to convert that code I pasted to cljs, wrapping it in a function that will return the buffer in the end callback

restenb04:03:20

trying out your suggestions now

zentrope04:03:15

I donā€™t think you can just return the value because the wrapping function will terminate before that value is produced.

zentrope04:03:30

So, you have to use a callback to get the value (or some such async method).

zentrope04:03:24

Using it would be like (get-me-the-buffer (fn [buffer] ā€¦)).

zentrope04:03:10

Then, in the callback, update your central state atom (if thatā€™s what youā€™re doing).

restenb04:03:33

i thought about using an atom, maybe that's just as easy

justinlee04:03:10

the atom is going to be the most straightforward translation because mutating a global is what the original pasted code does

restenb04:03:46

i'm essentially trying to do this

justinlee04:03:53

although it occurs to me that you probably want to mutate the javascript object itself

zentrope04:03:54

In a react-ish browser app, thereā€™s usually a ā€œstateā€ atom from which the UI is generated. If youā€™re doing some sort of node thing, then ā€¦ I donā€™t know.

restenb04:03:22

yeah this is node, using macchiato to run cljs on a node server

zentrope04:03:51

Line 40, theyā€™re using a callback.

restenb04:03:56

i want to generate pdfs on a server and return them as a http/post response

restenb04:03:20

figured i could wrap the response body as a readstream

justinlee04:03:48

wait a sec isnā€™t there a clojure native pdf maker

zentrope04:03:52

Line 48, they create a callback that then fixes up the response.

zentrope04:03:16

I think so, but it depends on JVM libs, doesnā€™t it?

restenb04:03:46

i'm not aware of anything clojure-specific

restenb04:03:54

it's an option, but i already have cljs code for generating the pdf with pdfmake

restenb04:03:05

the thing is we're trying to move pdf generation from the client to a server

restenb04:03:45

this is trivial in pure js as all you have to do is follow their examples with use a node express app and the node http server

restenb04:03:12

in order to not have to interact with javascript i've been trying to write that createBinary function with cljs instead

restenb04:03:31

but I guess another option is to keep that in js and wrap the callback in a go block

benzap04:03:30

yeah, i you could just keep it in Javascript, and call it from within cljs

zentrope04:03:10

You might try shadow-cljs which (I think) keeps pretty close to the NPM ecosystem.

restenb04:03:32

i've been trying macchiato, seems to work fine

zentrope05:03:51

Itā€™s a build system, not a replacement for macchiato

benzap05:03:45

oh, so you're trying to build a nodejs web server using cljs, with machiatto? You are also trying to talk to a PDF generation library, which is a dependency on npm?

zentrope05:03:05

Thatā€™s the picture Iā€™ve gotten.

benzap05:03:30

yeah, shadow-cljs is probably the easiest way to pull in the dependency, and use machiatto

zentrope05:03:57

Theoretically, at that point youā€™re just doing a direct transliteration.

restenb05:03:01

(def pdfmake (node/require "pdfmake"))

restenb05:03:29

using cljs.nodejs works just fine on my local setup

benzap05:03:18

@restenb that is the easiest way to pull in your dependency, but the builds tools have recently been including the ability to pull in npm dependencies to appear correctly in the cljs module system

benzap05:03:40

ie. (require ["pdfmake" :as pdf])

benzap05:03:02

or in your ns-form, (ns (:require ["pdfmake" :as pdf])), etc

benzap05:03:25

it's still a bit experimental, so using the node/require is your best bet for now

restenb05:03:33

you can define :npm-dependencies with macchiato too i think, i haven't looked into that

restenb05:03:03

idk, noticed something in project.clj

benzap05:03:15

I thought macchiato was a web server resembling the ring-based clojure stuff, built in cljs for node?

benzap05:03:29

you're using leiningen

restenb05:03:38

:npm {:dependencies [[source-map-support "0.4.6"]]

restenb05:03:49

this is in the default project.clj

benzap05:03:55

shadow-cljs is an alternative to leiningen, which is purely cljs-based

benzap05:03:28

the idea behind it was to provide a lower barrier of entry for people wanting to try out cljs, without requiring the buy-in of Java (with tools like leiningen, boot, clj, etc)

benzap05:03:57

but if you're already at a point where you have your clojurescript compiling, than that's great

benzap05:03:36

just make sure that you include your cljsbuild target as :nodejs, are you able to run your compiled code on node?

restenb05:03:09

yes it all seems to work fine

restenb05:03:20

the default macchiato setup even has figwheel

benzap05:03:32

oh nice, yeah you should be set šŸ™‚

benzap05:03:51

the pdfmake stuff can be added in the :npm :dependencies area

restenb05:03:52

you just call lein build and then node mystuff.js and you're set

zentrope05:03:53

Yeah. Just use the callback, exactly like that example code does.

benzap05:03:18

and you should be able to node/require it without issues

benzap05:03:39

don't think you necessarily need to include it there, you could always manage your own package.json with npm

benzap05:03:47

it's just pulling the dependencies out of node_modules

restenb05:03:00

i know the pdf generation itself works, but i want to avoid saving the pdf to disk before serving it

benzap05:03:13

ah, so you want to store it as a bytearray?

benzap05:03:29

You'll have to look at how Node handles those situations

benzap05:03:38

and perform an interop within cljs

restenb05:03:45

trying to generate it into a Buffer and then returning that as the response wrapped as a stream

restenb05:03:10

got stuck on the buffer part

zentrope05:03:19

Isnā€™t that exactly what that code is doing?

restenb05:03:35

so i tried to translate that code to cljs

benzap05:03:07

I'm not familiar with machiatto, but I know it follows closely to clojure ring-based servers. There should be a similar Ring Response object in machiatto with similar functions for assigning byte data to the response body

zentrope05:03:27

res.send(binary)

restenb05:03:46

yeah i'm pretty you can just wrap it as a file in macchiato

restenb05:03:00

(defn file "accepts a path to a file, and returns a response with the body set to the file stream." [path] {:status 200 :headers {} :body (fs/read-stream path)})

restenb05:03:16

since the body is a read-stream it shouldn't matter if it's a path or a buffer

zentrope05:03:50

Oh, so you DO want to save it to a file?

restenb05:03:03

not on the server generating it, no

benzap05:03:08

Does pdfmake generate a bytearray from it's generated pdf?

restenb05:03:44

yes, it's just a b64 string i think

zentrope05:03:49

I think thatā€™s what heā€™s trying to do.

zentrope05:03:30

I donā€™t see why that doesnā€™t work as a straight translation into CLJS.

benzap05:03:35

looks like you're going to deal with callback hell

benzap05:03:14

you could just do a direct translation, and replace the express parts with machiatto

benzap05:03:31

personally, i'd try and self-contain the generation in a core.async go block

restenb05:03:48

that's why i was thinking about keeping the actual buffer generation as js, and then wrapping the callback from cljs with a go block instead of trying to translate it

benzap05:03:10

all the power to you, I see nothing wrong with that

restenb05:03:32

something like this should work

restenb05:03:07

(go (let [c (chan 1)] (.generatePdf pdfDate (fn [err, res] (go (>! c res))) (<! c)))

restenb05:03:33

although it looks pretty awkward at first glance

zentrope05:03:36

Oh, so you want to move that to a different framework. light dawns ;)

zentrope05:03:09

Could you make the function take a response object?

zentrope05:03:41

(defn gen-pdf [response] ā€¦. (response {:body buffer})) ?

benzap05:03:43

@restenb similarly, you could return the channel c to a response, and pull out the data

zentrope05:03:24

Oh, right. You have to hand that response to something, rather than write to it. Ah, well.

restenb05:03:52

if i have the buffer i can just do something like this i think

restenb05:03:55

(defn get-pdf-response [req res raise] (-> (r/file (report/create-pdf report-data res)) (r/content-type "application/pdf") (res)))

benzap05:03:09

`(defn generate-pdf [content] (let [success (chan 1) error (chan 1)] (go (>! success (heavy-lifting content))) [success error]))`

restenb05:03:18

and have create-pdf be wrapped in a go block reutnring the buffer

restenb05:03:33

then i tried doing it all from cljs and ran into problems implementing this

restenb05:03:35

doc.on('end', function () { result = Buffer.concat(chunks); callback('data:application/pdf;base64,' + result.toString('base64')); });

restenb05:03:19

as the buffer is what needs to be returned in the callback

zentrope05:03:30

Isnā€™t result.toString() the buffer?

zentrope05:03:40

Or did you want to do something different?

zentrope05:03:45

Maybe call (.toString result), then return the buffer?

zentrope05:03:05

Assuming .toString resolves everything, even if you throw it away.

zentrope05:03:55

(.on "end"
     #(let [result (Buffer/concat chunks)]
        (callback result)))

zentrope05:03:00

That didnā€™t work?

benzap05:03:07

the callback needs to be your response, or it needs to be where you pass your result into the channel

zentrope05:03:44

Maybe paste in your WIP. :)

restenb05:03:32

messing with it. not that familiar with core.async either

benzap05:03:54

so i'm keeping the chunks in a javascript object, it's just easier to work with javascript objects when working with javascript libraries

benzap05:03:41

but essentially, this will process everything, and throw the result in the result channel, you can either pull from it with take!, which uses a callback, or you can grab the value from it within a go block with <!

benzap05:03:16

(take! result (fn [chunks] ....)

restenb05:03:29

yeah i was trying something like that

benzap05:03:00

I guess the big issue is pulling the async result into machiatto, which i'm guessing uses callbacks

restenb05:03:27

anyway, let me try and sew this together and see how it goes

Desmond05:03:39

hi, i am working on a demo involving moving code between a client with clojurescript and a server with clojure. what would be the simplest way to get going with a basic form and a few buttons in cljs? i've used om-next a bit and while it has some big wins it doesn't seem like the easiest solution. i want this to be easy.

Desmond05:03:56

any ideas?

restenb06:03:58

i use reagent and re-frame for GUI with hiccup for HTML

Desmond05:03:23

i got re-frame up very quickly. thanks for the tip.

zentrope06:03:34

RUM is a nice alternative.

danielcompton09:03:27

I wrote about how to serve ClojureScript files in development without running into weird caching issues: https://danielcompton.net/2018/03/21/how-to-serve-clojurescript

šŸ‘ 8
thheller09:03:42

@danielcompton Cache-Control: max-age=0, no-cache, no-store, must-revalidate and skip everything else

thheller09:03:22

etags seem like total overkill

danielcompton09:03:51

You wouldnā€™t need all of those directives, your header would have the same effect as Cache-Control: no-store

danielcompton09:03:36

I found a noticeable page load time boost from using ETags, because the browser didnā€™t need to re-download the file every time

thheller09:03:02

during localhost development?

danielcompton09:03:55

On todoMVC with re-frame + re-frame-10x it went from 2.3s to 1.5-1.7s to reach DOMContentLoaded

danielcompton09:03:14

Just compiling a real world app now for a comparison

thheller09:03:43

hmm do you have the project somewhere so I can compare with my setup?

thheller09:03:57

1.5s still seems pretty slow

danielcompton09:03:38

yeah itā€™s a slow laptop

danielcompton09:03:01

What is it about fetch that is better for loading lots of files?

thheller09:03:41

by default the closure debug loader uses script tags. which means the browser must download and eval the code before continuing with the DOM

juhoteperi09:03:26

Why would waiting for DOM affect anything in this case as the code must be evaluated anyway before the app can do anything?

danielcompton09:03:21

On our real world app, we get 10 second loads instead of 13 second loads

danielcompton09:03:48

I think the next frontier for ClojureScript dev performance is HTTP2

thheller09:03:57

shadow-cljs already has that šŸ˜‰

danielcompton09:03:00

because the browser will only open 6 requests per connection

danielcompton09:03:13

Well for Figwheel then šŸ™‚

thheller09:03:28

and yes its pretty neat but configuring trusted SSL certs for dev is a nightmare

rauh09:03:59

The problem might be figwheel here. Last time I checked the import/reload code it loaded js files consecutively. It should instead just add all N js files as script tags and let the browser download them in parallel and then execute them consecutively

thheller09:03:18

@rauh I think we are just talking about initial load here

rauh09:03:29

Oh, I see

rauh09:03:57

Yeah so then HTTP/2 will make a huge difference. I have it setup with openresty and it reduced it by like a factor of 3-4x IIRC

thheller09:03:13

yeah its pretty good

Roman Liutikov09:03:37

@danielcompton Iā€™ve never had this issue bc I always have DevTool open with cache disabled šŸ™‚

rauh09:03:53

Jup, 338 requests, 8.8MB transferred, Load: 1.44 seconds. It's super quick

danielcompton09:03:57

@roman01la šŸ™ˆšŸ™‰

šŸ˜… 4
thheller09:03:54

uhm no gzip? šŸ™‚

thheller09:03:33

151 requests, 896 KB transfered, finish 533ms, load 66ms

thheller09:03:42

buts thats async in a dummy test project which doens't do much

Roman Liutikov09:03:48

280 reqs, 15.8 MB, 6s

thheller09:03:06

I think gzip should help a bunch

rauh09:03:11

No I found gzip/brotli slowed it down a bit, not by much but it's loopback so no reason for gzip I guess

Roman Liutikov10:03:18

I guess http2 and gzip can be done with figwheel via custom Ring handler?

thheller10:03:40

gzip yes, http2 no. thats a server thing.

šŸ‘ 4
thheller10:03:33

http-kit doesn't support http2 or ssl IIRC

rauh10:03:08

If browser just supported h2c... that'd be so nice

rauh10:03:38

Then getting Http/2 would be much simpler...

thheller10:03:47

yeah ssl is the most annoying thing for http2 during dev

thheller10:03:03

if you get the cert setup properly it works fine

thheller10:03:08

but getting that setup is horrible

thheller10:03:50

and immediately breaks if you want to access from a remove dev setup, ie. not localhost if the cert is localhost

timo13:03:27

Hi there, I couldn't find a solution on following problem: when running lein with-profile test doo phantom once phantom fails with

ReferenceError: Can't find variable: Map

   in onError
Error encountered performing task 'doo' with profile(s): 'dev,test,test'
Subprocess failed

timo13:03:09

Anyone has a hint on that?

roosta13:03:51

You need to add a plus before your profile

lein with-profile +test doo phantom once

šŸ‘ 4
timo13:03:28

sorry for digging deeper, but it doesn't work and I am missing the clue. now it gives me

;; ======================================================================
;; Testing with Phantom:                                           
                                                                                                        
ReferenceError: Can't find variable: Map                                                                
                                                                                                        
   in onError                                          
Error encountered performing task 'doo' with profile(s): 'base,system,user,provided,dev,dev,test,test'  
Subprocess failed                                                           

roosta13:03:15

Hmm, when I replied I quickly realized that my answer might not have been the root of your problem. It seems to me that the issue is not necessarily related to your build process

roosta13:03:52

rather something in your test code, but I honestly have no clue.

roosta13:03:54

the way i normally call doo is something like lein doo phantom test where test is your test cljs build

roosta13:03:41

in your original text you don't seem to pass a build. Are you relying on the test profile alone?

timo14:03:16

yeah I think so...I am using luminus and read it like that in the docs I guess...

timo14:03:27

I am still new to that

roosta14:03:36

Seems you are calling doo like the template says. My best guess is that there is something wrong in your test code. A reference error seems to indicate that, but I could be wrong. It also seems like the js compiles since you get that far, which again points to an error in the actual code. Thats the best I got, hope you figure it out. Sorry I couldn't be of more help.

timo14:03:29

thanks! I will try to ask in luminus-channel if I don't find anything.

mfikes13:03:34

There is a new guide covering the ClojureScript ns form and all it has to offer: https://clojurescript.org/guides/ns-forms

šŸ‘ 4
thheller13:03:31

@mfikes it doesn't mention (:require ["react-dom/server" :as x]) yet

mfikes13:03:06

@thheller Right, the original content was written back in early 2016, which I think was prior to string requires. Someone familiar with that feature should submit a PR covering it.

thheller13:03:48

never saw that guide before. thought you just wrote it. I'll see about making a PR to add the string requires.

mfikes13:03:20

I did recently author the guide, but the original content it is based on is older blog posts that pre-date string requires.

grounded_sage13:03:37

I'm getting inconsistent errors across build tools and it's got me very confused.

grounded_sage13:03:52

When I require react-native-web using NPM deps on Lumo it works fine. When I do it with Leiningen I get Undefined nameToPath for react_native_web then when I am using Boot I get an error from the GCC.

mfikes13:03:21

@thheller Expanding on that, there should probably be a guide covering NPM dependencies, if there isn't one.

thheller13:03:32

well for that it first needs to work more reliably in CLJS

thheller13:03:47

@grounded_sage I'd suggest you try shadow-cljs where this works much more reliably

grounded_sage13:03:28

Forgive my ignorance but what does shadow-cljs give me @thheller?

thheller13:03:56

working npm deps for one? but also everything other build tool would give you

grounded_sage13:03:39

Ok cool I will definitely check it out. Can I use Figwheel etc with it?

thheller13:03:13

no, but it provides everything figwheel would provide on its own

petterik13:03:17

I wanted to try to run tests on every save with cljs.main. Here's where I'm at:

clj -A:test -m cljs.main -co "{:watch-fn lime.tests/-main}" --watch "test" -c
1 problem and 1 inconvenience. Problem: The :watch-fn can't be specified as a compiler option via the cli? Symbols are not resolved to functions and code (fn [] (prn "hey")) are never eval'ed, i.e. "PersistentList cannot be cast to IFn". Inconvenience: Cannot watch more than one path at a time?

petterik13:03:45

ClojureScript 1.10.217

mfikes13:03:57

@petterik Hrm. Perhaps that's the only compiler option with a non-edn value...

mfikes13:03:09

@petterik Perhaps it could be easily expanded to work like :preprocess in :foreign-libs (take a symbol that gets resolved to a function as in your example). I'd suggest an enhancement JIRA.

petterik13:03:06

@mfikes I'm not familiar with :preprocess, but I can create a JIRA and include your comments?

petterik13:03:54

Cool, yeah, sounds good

mfikes13:03:04

It would seem easy to have the compiler check of :watch-fn's value is a symbol, and if so, conditionally behave like :preprocess does.

šŸ‘ 4
petterik13:03:15

It'd be nice to be able to pass clojure code as well šŸ˜‰

petterik14:03:12

But taking a symbol works for my case at least

mfikes14:03:17

Yeah, cljs.main reads in compiler options as EDN right now.

lwhorton17:03:20

am i missing a really obvious clojure.string/format function? i found format in an older cljs version, and also goog.string/format in an older gcc version

lwhorton17:03:39

but both of them have changed; format is no longer in cljs.core, and itā€™s goog.string.format/format ā€” whatā€™s idiomatic?

mfikes17:03:09

Alternatives are str, cljs.pprint/cl-format, Cuerdas

lwhorton17:03:39

ā˜ļø cuerdas was exactly what i was looking for!

zentrope17:03:05

Strange. I have an old app Iā€™ve updated deps for and suddenly ā€œvalsā€ in CLJS doesnā€™t work.

mfikes19:03:06

There is a new reference page covering the stable JavaScript API exposed by the ClojureScript standard library: https://clojurescript.org/reference/javascript-api

justinlee19:03:02

@mfikes Iā€™m slightly confused by that page. It says that ā€œClojureScript defines types that have stable, publicly-consumable JavaScript APIsā€ but then all of the examples are in clojurescript.

justinlee19:03:02

Is the idea that you can call .indexOf from javascript on a clojurescript vector?

mfikes19:03:29

Perhaps there is a better way to describe the concept...

mfikes19:03:25

The idea is that, any ClojureScript value satisfying the sequential? predicate also defines JavaScript functions as defined on that page. Thus you can reliably use JavaScript interop to call those functions without being in a position of calling private API.

mfikes19:03:12

Feel free to contribute to the page to clarify. https://clojurescript.org/community/contributing_site

mfikes19:03:56

An converse example: If you do (.-cnt [1 2]), then your code is in danger of potentially breaking.

justinlee19:03:56

I get it now. Iā€™ll just submit a small patch. Feel free to ignore if you donā€™t like my wording.

mfikes19:03:22

Cool. By the way, I don't accept or reject the patches.

mfikes19:03:37

I'm a contributor just like you šŸ™‚

justinlee19:03:59

Well I just mean Iā€™ll offer my friendly suggestions however is best for you. šŸ™‚

šŸ‘ 4
jmckitrick20:03:59

So @lee.justin.m you almost have me convinced to try shadow-cljs in my project, but is there a way to integrate it into the lein build? Or will I need 2 steps to build a project? Itā€™s a jetty backend and a Reagent frontend.

hlolli20:03:12

@jmckitrick shadow-cljs is in most part a replacement for lein cljsbuild, less painful in the long run I'd say, shadow-cljs prevents gray hairs

justinlee20:03:24

@jmckitrick Yes it is pretty nice to manage everything with shadow, but you donā€™t have to. You can run shadow from lein and let lein deal with the cljs dependencies (you still deal with npm dependencies using normal tools and a package.json) https://shadow-cljs.github.io/docs/UsersGuide.html#Leiningen

justinlee20:03:57

I havenā€™t done the lein integration so you should hop into #shadow-cljs for help if you get stuck

hlolli20:03:56

btw to answer the question, you need 2 steps to build a project, with or without shadow-cljs given that you're useing clojure and clojurescript. I actually don't build the clojure, just start it with lein ring plugin, but you can and some recommend that you build clojure into a .jar and start it all with java -jar

jmckitrick20:03:03

Iā€™d really miss the figwheel integration. Especially with cider.

hlolli20:03:21

you wouldn't miss that šŸ˜‰

hlolli20:03:47

but cider is still bit more manual at this stage, you'd need to require nrepl yourself

jmckitrick20:03:55

Well, I get the hot-reloading, plus cider integration lets me jump around my code like regular clojure.

justinlee20:03:28

you get hot-reloading with shadow too. heā€™s got his own implementation that works great and gives you the heads up compiler errors and all that jazz

jmckitrick20:03:58

I saw them in the terminal, but not in the browserā€¦.

justinlee20:03:20

i donā€™t know about emacs, but now that i switched to cursive i get full integration (docstrings, jump-to-definition, etc.) so I know that shadow is at least capable of those things (doesnā€™t work with atom, sadly)

hlolli20:03:59

the "hud" was added into shadow like 1-2 months ago, maybe you should try it again?

jmckitrick20:03:17

I just built the project 5 minutes ago šŸ˜‰

jmckitrick20:03:47

I installed shadow about a week ago.

hlolli20:03:03

maybe we should take this to #shadow-cljs but basically you get error that is printed in the terminal but not into the browser?