Fork me on GitHub
#clojurescript
<
2019-03-27
>
Nazral03:03:50

Hi! I have an issue where my cljs build now produce a goog not defined error, it started after I did a lein clean

Nazral03:03:08

the answers I found on google apply to shadow.cljs but I don't use it, and not sure how to fix it

Nazral03:03:22

I made sure I use the latest versions of clojurescript and cljsbuild

Nazral03:03:49

^ fixed it by re-enabling whitespace optimization in project.clj but that feelswrong

thheller08:03:51

@archibald.pontier_clo do you use a build config without a :main or :modules entry?

Nazral10:03:55

it has a :main entry

thheller10:03:49

are you loading the correct file? do you get any 404s when loading the page?

Nazral14:03:48

@thheller sorry for the late reply, no 404, and yes I am loading the correct file, enabling whitespace optimization in project.clj stopped the error without any other change in the code

mhuebert14:03:16

Is there any reason not to use syntax-quote at runtime? The docs say “Only intended for use in Clojure macros” (http://cljs.github.io/api/syntax/syntax-quote) but I’m not sure why. eg: https://www.maria.cloud/gist/c2282b77e2e47d71cb68b3becce8f84c?eval=true

bronsa14:03:00

I suspect it may have issues with properly namespace qualifying symbols in certain nested scenarios, as namespaces or vars don't exist at runtime in (non self-hosted) cljs

bronsa14:03:18

so I wouldn't say it's "only intended for use in macros", but with that gotcha

bronsa14:03:02

those are some very good docs btw, good job @shaunlebron

mhuebert15:03:35

that is true. that is also a problem when using syntax-quote in macros, as the clj namespace doesn’t know about vars in cljs namespaces.

shaunlebron16:03:16

@mhuebert it’s mainly a guidepost for me to say “syntax-quotes are built for macros and nobody uses them otherwise and perhaps they shouldn’t be”

bronsa16:03:13

@shaunlebron that's not true tho

bronsa16:03:30

using there's nothing tying syntax-quote to macros

bronsa16:03:47

and I do use it at runtime a fair bit :P

bronsa16:03:21

the entire tools.emitter symbolic bytecode is expressed through syntax-quoted templates

bronsa16:03:39

that's in clojure, not cljs, but doesn't really make a difference

lilactown16:03:04

`[:li ~@(when condition? [:li "foo"] [:li "bar"]) [:li "baz"]]
? 😛

lilactown16:03:24

someone posted an example like that earlier (I think in #clojure ?)

bronsa16:03:37

that was me :)

😂 4
lilactown16:03:15

I think that works just fine in CLJS too

shaunlebron16:03:14

so you’re creating a defmethod where the body’s code is generated at compile time, or rather evaluate time?

shaunlebron16:03:25

this is making my brain fold

shaunlebron16:03:23

I might ping @mfikes to see how much of this is possible in cljs before amending the docs

bronsa16:03:26

no no syntax quote has nothing to do with compile time or runtime

lilactown16:03:05

it's complicated because in Clojure you don't think about it as "compile time"

bronsa16:03:28

this has nothing to do with evaluation differences in clojure or cljs

bronsa16:03:30

it's the exact same

bronsa16:03:20

typing

`[~@(when x whatever) 1 2 ]
is literally a shortrand for typing
(vec (concat (when x whatever) (list 1) (list 2)))

bronsa16:03:30

at runtime there absolutely no difference

shaunlebron16:03:03

wow, just like matt’s example in maria, i did not know this

bronsa16:03:17

as a protip

bronsa16:03:22

take a syntax-quoted expression

bronsa16:03:24

stick a quote over it

bronsa16:03:30

and you'll see what it translates to at runtime

bronsa16:03:40

user=> '`[~@(when x whatever) 1 2 ]
(clojure.core/apply clojure.core/vector (clojure.core/seq (clojure.core/concat (when x whatever) (clojure.core/list 1) (clojure.core/list 2))))

💯 5
bronsa16:03:11

ok, it's not literally identical to what I pasted, but it's equivalent :)

shaunlebron16:03:44

i need to stare at this for a minute

shaunlebron16:03:41

too many questions

shaunlebron16:03:47

in different directions

shaunlebron16:03:00

how do i trace what’s going on

shaunlebron16:03:43

i inserted references to the reader code in the docs, maybe i have to look at them more closely

bronsa16:03:52

think about this in clojure not clojurescript, trust me that in this case there's no difference and it'll make it a bit easier to grasp

bronsa16:03:31

then sidestep the repl and play the repl manually using eval and read-string

bronsa16:03:49

user=> (read-string "`[~@(when x whatever) 1 2 ]")
(clojure.core/apply clojure.core/vector (clojure.core/seq (clojure.core/concat (when x whatever) (clojure.core/list 1) (clojure.core/list 2))))

bronsa16:03:07

user=> (read-string "'`[~@(when x whatever) 1 2 ]")
(quote (clojure.core/apply clojure.core/vector (clojure.core/seq (clojure.core/concat (when x whatever) (clojure.core/list 1) (clojure.core/list 2)))))

bronsa16:03:12

this makes it clear why the quote trick works

shaunlebron16:03:43

that helps too, yeah

bronsa16:03:45

yes, the thing to grasp I guess is that syntax-quote delegates the templating at runtime

bronsa16:03:57

and it couldn't do it any other way!

👍 4
bronsa16:03:17

otherwise you could only syntax-quote forms containing constant values, which wouldn't be very interesting

bronsa16:03:47

when somebody says "x only works in macros", they forget that a macro is just (big handwaves here) (eval (the-macro-as-a-function args))

bronsa16:03:20

so if it "works in a macro", it must also "work" in a function, at runtime

bronsa16:03:31

because macroexpansion time is the runtime of a macro

bronsa16:03:49

and a macro is just a function

bronsa16:03:13

hope that makes sense

shaunlebron16:03:33

yeah that helps, my understanding is better

shaunlebron16:03:47

hard to keep the evaluation differences between clj and cljs in my head and to see how that affects this

bronsa16:03:05

it doesn't, modulo name resolution in syntax-quote

shaunlebron16:03:33

so it does, since that can certainly affect it

bronsa16:03:37

but even that is not a problem unless you're using syntax-quote inside a read-string

lilactown16:03:39

well, and that's a big if. if name resolution doesn't work as expected, then at the least I would want to understand exactly how

shaunlebron16:03:43

like resolving vars at runtime i think

bronsa16:03:56

yep but see my last caveat

bronsa16:03:42

so in clojure you can do

(read-string "`+")
and it will return clojure.core/+

bronsa16:03:01

because the namespace map is available at read-time being executed at runtime

bronsa16:03:17

that is different than doing simply

`+
`, where read-time is being executed at compile time

bronsa16:03:30

read-time at compile time in clojurescript has no differences than in clojure

bronsa16:03:32

it can get really confusing when you can nest stages like this (`read-string` is nothing but read-time available a-la-carte at runtime!), but this is what makes lisps so powerful :)

shaunlebron16:03:42

i think i need to hold on to the issue of name resolution, i don’t understand how read-string affects that

shaunlebron16:03:53

we’re talking about cljs now

bronsa16:03:00

cljs has read-string

shaunlebron16:03:05

either cljs-js or cljs-jvm

bronsa16:03:14

I'm talking about cljs-jvm

shaunlebron16:03:39

yeah, read-string is the runtime read-time thing

bronsa16:03:51

self hosted cljs does have reified namespaces and var I think so that makes it similar to clojure (but I never used it so I'm not sure)

shaunlebron16:03:59

but is read-string being invoked when syntax quotes are read you mean?

bronsa16:03:08

what is "it"?

bronsa16:03:36

let me backtrack a bit

bronsa16:03:14

you can think of (non-self hosted) clojurescript as: (cljs.emit/emit (cljs.analyzer/analyze (clojure.tools.reader/read-string <..>))) yeah?

bronsa16:03:28

this is all happening on the jvm, at compile time

bronsa16:03:47

let's say <..> is

"`+"

bronsa16:03:33

tools.reader on the jvm reads that, interops with the namespace map of the clojurescript analyzer which is available at compile time, and returns cljs.core/+ to the analyzer

bronsa16:03:55

but if you have

"(read-string \"`+\")"
instead

bronsa16:03:04

that read string is pure runtime

bronsa16:03:11

and is cljs.tools.reader/read-string

bronsa16:03:22

which does not have access to the namespace map

bronsa16:03:29

and so can't perform name resolution

shaunlebron16:03:24

wow yeah, this makes sense so far

bronsa16:03:53

ok, now all the examples that I shown you before can be explained and understood by replacing <..> with them :)

bronsa16:03:19

it's really tricky to keep it all in your head but when it clicks it's really simple

bronsa16:03:34

graphically it's much easier to follow

shaunlebron16:03:03

> but even that is not a problem unless you’re using syntax-quote inside a read-string

shaunlebron16:03:29

ok, i’ll try to come up with an example to put in the docs for this

bronsa16:03:36

:thumbsup:

shaunlebron16:03:00

thanks for that tour, crazy and helpful!

bronsa16:03:08

haha you're welcome

jaide18:03:06

(fn [cb]
      (let [id (atom -1)
            frame (fn [] (reset! id (requestAnimationFrfame
                                     (fn []
                                       (cb %)
                                       (frame)))))]
        (frame))

jaide18:03:52

Having trouble running this code. I get an error that (frame) call is undeclared

Eric Scott18:03:28

Hey I'm trying to write a unit test with this clause: (is (thrown? js/Object (ig/unique #{:just-me :no-theres-me-too!})))

Eric Scott18:03:50

But it's failing:

hipster coder18:03:46

Testing for a thrown error?

Eric Scott18:03:20

yes. Should I be specifying some type other than js/Object?

hipster coder18:03:35

What does the unit test say?

hipster coder18:03:42

Fail with what?

Eric Scott18:03:01

(js/Error. "Non-unique")

hipster coder18:03:29

So at least JS is throwing the error

hipster coder18:03:52

Its just that the test isn't wrapping around it, catching it

Eric Scott18:03:20

That's right. The test is failing when it should fail if there isn't an error

Eric Scott18:03:20

Its clj sibling works fine: (is (thrown? Exception (ig/unique #{:just-me :no-theres-me-too!})))

hipster coder18:03:25

Ya... my first thought

hipster coder18:03:35

The js object namespace is wrong

hipster coder18:03:05

Because the docs say it will check if error is thrown on exact class you give it

hipster coder18:03:39

js/Object most likely is not the parent namespace of Exception being thrown

hipster coder18:03:26

You'd think it would be... like Ruby. Everything is an Object. But JS breaks all the rules. I never assume in JS

hipster coder18:03:07

Can you change js/Object to Exception... just like the working test

hipster coder18:03:41

The JS throws error as.expected. but the test isn't seeing it thrown on the js/Object namespace

Eric Scott19:03:05

So I'm trying this:

Eric Scott19:03:07

(.log js/console "blih") (try (/ 1 0) (catch js/Object e (.log js/console (str (type e))))) (.log js/console "bleh")

Eric Scott19:03:28

And what's showing up is this:

Eric Scott19:03:29

Firefox 66.0.0 (Ubuntu 0.0.0) LOG: 'blih' Firefox 66.0.0 (Ubuntu 0.0.0) LOG: 'bleh'

Eric Scott19:03:22

I was hoping I could get it to tell me what type the error was.

hipster coder19:03:45

So you can catch the specific error?

hipster coder19:03:57

More granular than Exception

hipster coder19:03:54

The exact exception is probably burried in the e variable

hipster coder19:03:17

Instead of type e, just console log the e

hipster coder19:03:06

str is just returning the top text from e object... browser, ubunutu... looks like a header string

hipster coder19:03:28

Need to go inside e, more levels

Eric Scott18:03:51

FAIL in (utility-test) (cljs/test.js:373:11) (thrown? js/Object (ig/unique #{:no-theres-me-too! :just-me})) failed with

hipster coder18:03:53

I think you need a ( in front of function call

hipster coder18:03:13

Otherwise, it is a parameter to a function

Eric Scott18:03:22

(is (thrown? js/Object (ig/unique #{:just-me :no-theres-me-too!})))

hipster coder18:03:10

It is testing for an error to be thrown?

schmidt7318:03:29

@jayzawrotny as far as I am aware let in cljs is a let*. This means that the name frame is not bound to a value until the expression (which references frame) is evaluated.

schmidt7318:03:38

Do you see the circularity in that?

jaide18:03:32

Yes, it’s trying to eval all the forms but the frame symbol is not bound at that point yet.

schmidt7318:03:13

Look at letfn

lilactown18:03:14

would letfn fix it?

schmidt7318:03:39

Yeah letfn allows this.

schmidt7318:03:59

@jayzawrotny you have the reasoning for why it isn't working correct.

jaide18:03:16

I understand, thanks!

schmidt7318:03:21

@jayzawrotny you can also do (let [f (fn fact [n] (if (= n 0) 1 (* n (fact (- n 1)))))] BODY)

schmidt7318:03:36

that is give the function a name in the lambda expression

schmidt7318:03:56

usually letfn is used for mutual recursion between functions in a let statement.

schmidt7318:03:28

A function can refer to itself in this way: (fn foo [x] .... (foo ...) ...)

jaide18:03:47

Oooh I didn’t know that, that could work too then.

schmidt7318:03:52

@jayzawrotny it is probably a better way to do it.

jaide18:03:38

Yeah seems to be working. Thanks!

lilactown18:03:16

@eric.d.scott what's ig in this case?

Eric Scott18:03:08

The namespace where the function 'unique' lives. Expects a singleton, and throws an error otherwise

lilactown19:03:50

have you tried using js/Error instead of js/Object?

hipster coder19:03:38

Print out the entire e in the console

hipster coder19:03:53

I am sure the exact namespace is inside var e

hipster coder19:03:31

str is just giving you a browser agent header

Eric Scott19:03:50

Yes I actually started with js/Error, then saw cases where people claimed js/Object was the way to go.

hipster coder19:03:54

Javascript doesn't use a class inheritance system... its a prototypal

hipster coder19:03:20

Not everything inherits from Object in JS

hipster coder19:03:38

Like Ruby does... where everything is an Object

hipster coder19:03:06

I will verify that, right now, for you

hipster coder19:03:14

here is an example, to find out who is the parent of an object, e being the object in this case…

hipster coder19:03:17

set hidden field message_receiver_id = 2 var t = “” undefined t.isPrototypeOf ƒ isPrototypeOf() { [native code] } t.isPrototypeOf ƒ isPrototypeOf() { [native code] } t.instaneof undefined t.instanceof undefined typeof t “string”

hipster coder19:03:51

We don’t recommend catching errors on Exception in Ruby because it will catch all errors, when the test is targeting very specific errors

dnolen19:03:11

@eric.d.scott I don't understand why js/Object is preferred here, and would probably disagree w/

dnolen19:03:15

claims otherwise

dnolen19:03:56

for catching anything there's (catch :default e ...)

hipster coder19:03:36

@dnolen loved the talk on clojure.spec

hipster coder19:03:42

👍 👍 👍

bago19:03:06

hi guys, sorry if stupid question but i worked sometime now on clojure but i can’t say i am exactly a guru 🙂. So i have this regular expression in a cljc file #"(?i)<\/?((script|style|input){1})(\s?[^<>]*)>" in the js file it becomes: /<\\/?((script|style|input){1})(\s?[^<>]*)>/i that… 🎉 gives me this error:

var x = /<\\/?((script|style|input){1})(\s?[^<>]*)>/i
VM1576:1 Uncaught SyntaxError: Unexpected token {

bago19:03:17

am i doing something wrong?

bago20:03:10

in clj it works very well, this file has been a clj file for some time now and it always worked, i turned it into a cljc and i got this problem in js

bago20:03:16

if you wonder:

[org.clojure/clojure "1.10.0-alpha7"]
[org.clojure/clojurescript "1.10.238"]

bago20:03:28

thanks, i did some googling but i couldn’t find anything, probably wrong keywords

kwladyka20:03:41

Issue: cookies don’t save http://dev.localhost:8080/authentication - ring server http://dev.localhost:9500/log-in - re-frame SAP I send JSON from SAP to server by https://github.com/Day8/re-frame-http-fx, cookies don’t save in web browser If i run directly http://dev.localhost:8080/authentication cookies save in web browser I added

(-> (handler request)
        (header "Access-Control-Allow-Origin" "")
        (header "Access-Control-Allow-Credentials" "true")
        (header "Access-Control-Allow-Headers" "Content-Type, User-Agent"))
and
(wrap-session {:store (jdbc-store postgres/db {:table :sessions})
                     :cookie-name "auth-session"
                     :cookie-attrs {
                                    :http-only false
                                    :same-site :lax
                                    :secure false ; https
                                    ;:domain "dev.localhost"
                                    ;:max-age 1800
                                    }})
Am I miss something? Am I doing something wrong about cookies security or there is an issue about how I use https://github.com/Day8/re-frame-http-fx and cookies? Any hints how to debug it / solve it? I stuck with it. I have to miss something.

kwladyka20:03:25

When I add [:img {:src ""}] cookies save so it is about https://github.com/Day8/re-frame-http-fx and goog.net.XhrIo (`XMLHttpRequests`) queries

kwladyka20:03:01

yeah… I missed :with-credentials true in ajax request… parrot

kwladyka20:03:20

*I don’t recommend to set all this options in server for security reason. I set them to find the issue.

Eric Scott21:03:27

@nathantech2005, @dnolen Thanks for your help. I finally wound up going with the following:

Eric Scott21:03:29

(defn erroneous-unique [] "Couldn't get (thrown?...) to work" (try (ig/unique #{:just-me :no-theres-me-too!}) (catch :default e :error))) (deftest ... (is (= erroneous-unique) :error) ...

kwladyka22:03:28

@eric.d.scott I am not in topic, but why not (is (thrown? …)) ?

kwladyka22:03:50

There are also fn to read data from exceptions

hipster coder22:03:46

am I allowed to ask a question about raw Javascript? We can thread it. I am looking for a send method in JS… to dynamically make a method call on an object.

dpsutton22:03:06

var method = "log";
console[method]("bob");
bob

👍 5
hipster coder22:03:11

exactly what I was looking for

Eric Scott22:03:41

@kwladyka - the problem was getting the throw? clause to key on the error class. Nothing I tried made it happy, and the test kept failing.