Fork me on GitHub
#cljs-dev
<
2017-02-28
>
shaun-mahood00:02:08

Jira etiquette/testing question - I've tested CLJS-1868 compilation on both Windows and Mac, for both :none and :advanced, and I've confirmed that it compiles and the new paths look good. The closure libraries are included and under :none they show up in the out folder as expected, but I haven't actually programmed anything that uses them, only tweaked the quick start files. Is this enough to say that it works for me on Jira, or should I try writing some code that actually uses the included cloure libs first?

thheller00:02:51

so I just tried upgrading my work project to latest CLJS 494 and it didn't work, then tried 473 and 456 also no luck.

thheller00:02:03

at first I though I ran into the async issue but that isn't it I guess

thheller00:02:55

also the usual :pseudo-names makes the bug disappear, talking about :advanced here.

thheller00:02:31

someone else on #clojurescript mentioned something like this today as well

thheller00:02:28

the last time I had an issue like this was about with protocol detection, but we fixed that

anmonteiro00:02:13

@thheller did you upgrade from 1.9.229?

thheller00:02:42

293 was the last version I used

anmonteiro00:02:51

it’s a big bump from 293 to 456, you think you can bisect?

anmonteiro00:02:08

by big bump I mean there were a lot of commits

thheller00:02:19

its too late for me to dig into this now, will try some stuff tomorrow .. just completely surprised the usual :pseudo-names debug option doesn't work as it disappears

anmonteiro00:02:22

sounds good, keep me posted

thheller00:02:33

it looks like something was optimized away, but there should be more people reporting this if that were the case

thheller00:02:19

hmm so had an idea

thheller00:02:31

the check that failed is {:pre [(ifn? x)]} ... removed that :pre and just test (when-not (ifn? x) (js/console.log "x is not ifn" x))

thheller00:02:28

the console message display the object as x is not ifn function (a) { ... with the full code of the function

thheller00:02:28

so (goog/isFunction x) returns false ... I have no idea what is going on. going to sleep.

anmonteiro05:02:07

It addresses the first part of the solution proposed in this design doc: https://github.com/clojure/clojurescript/wiki/Enhanced-Node.js-Modules-Support

anmonteiro05:02:17

the patch makes is possible to supply a :npm-deps entry in the compiler options, such as:

{:npm-deps {:react "15.4.2"}}
and then require react directly from a CLJS namespace. e.g.:
(ns foo.core
  (:require [react :as React]))

(def foo (React/createElement "div" nil "Hello, World!"))

anmonteiro05:02:55

the compiler will install the supplied node modules automatically

anmonteiro05:02:09

I appreciate people trying out the patch and reporting back!

richiardiandrea05:02:19

This plus boot-pack-source solves my packaging requirements thanks 😀

anmonteiro05:02:04

There might be one hiccup along the way with some modules: you might encounter this Google Closure Compiler issue: https://github.com/google/closure-compiler/issues/2308

anmonteiro05:02:40

^ the fix for that hasn't been included in the February release and some modules may crash the compiler

anmonteiro05:02:00

if you know how to build the Closure Compiler, use a master checkout

thheller09:02:58

@anmonteiro did a git bisect to find the bad commit

thheller09:02:01

git bisect bad
de05b15568c848a1d4f80a44bdffd486abd05150 is the first bad commit
commit de05b15568c848a1d4f80a44bdffd486abd05150
Author: António Nuno Monteiro <[email protected]>
Date:   Mon Nov 7 12:07:32 2016 +0100

    CLJS-1768: cljs.spec perf tweaks

    This patch implements the changes in the following commits:

    
    
    
    

:040000 040000 f8eee4c6e8289c5ec539c478e67c48d0de485f84 f261f856c8492bd4880be536186ccc8ad3fe3557 M	src

thheller09:02:30

no idea why that would cause my app to fail as it fails at a point where spec isn't involved at all

thheller09:02:00

will try to reproduce outside my app now

thheller09:02:43

verified just for sanity git reset --hard de05b15568c848a1d4f80a44bdffd486abd05150 breaks while git reset --hard de05b15568c848a1d4f80a44bdffd486abd05150~1 works

thheller09:02:23

must be emitting something that confuses the closure compiler

thheller11:02:57

@anmonteiro sorry for wasting your time, your commit wasn't causing this at all. I messed up my externs and somehow that made it look like that commit was causing it.

thheller11:02:35

Had some Google Analytics externs that went missing, somehow the ga variable must not have been touched before that commit

thheller11:02:22

should have been my first clue to look for externs when :pseudo-names worked, guess I shouldn't try to debug those things at 2am

thheller11:02:17

for giggles the the function that was replaced by ga was goog.isFunction which caused by {:pre [(ifn? x)]} to fail 😛

Roman Liutikov12:02:25

That’s probably not related directly to ClojureScript, but is there a way to make JS stack traces show source mapped ClojureScript code in stack frames?

Roman Liutikov12:02:43

I thought browsers can do it already. But if not, this probably could be achieved via stacks rewriting, the way it’s done in React.

darwin13:02:20

@roman01la I believe DevTools developers try to do their best to do this whenever possible

darwin13:02:03

obviously, if you handle error objects yourself and printing them somehow directly this transformation is not present

Roman Liutikov13:02:16

@darwin Yes, but I’m interested if there any evidence that source mapped stack frames are supported or not.

darwin13:02:10

AFAIK it is definitely NOT supported from the ECMAScript, so DevTools tries to be smart and transform presentation if they detect you happen to be printing a stack-trace

darwin13:02:19

if you interact with js/Error object in your code for example and processing .-stack by hand it won’t be source mapped, but if you console.log it, DevTools will detect it is a strack trace and try to present it source-mapped

darwin13:02:55

not sure about this particular case, but it definitely works when logging js/Error or exceptions for example

darwin13:02:28

another place is when DevTools present some error or exception on their own (without you explicitly logging it), similar heuristics apply

thheller13:02:23

@roman01la source mapping is exclusively coming from the devtools, the runtime itself doesn't do any mapping at all

Roman Liutikov13:02:53

@thheller I believe it’s possible to change function names in stack frames via fn.displayName prop

Roman Liutikov13:02:01

that’s how it is done in React I guess

thheller13:02:35

do you have an example of what you mean?

thheller13:02:43

displayName usually was just a way to name a function for devtools

thheller13:02:14

IIRC FireBug was the first to use that

thheller13:02:14

but again .. devtools only

Roman Liutikov14:02:04

@thheller yeah, exactly, instead of this clojure$string$includes_QMARK_ it would be nice to see this clojure.string/includes?

Roman Liutikov14:02:24

looks like displayName is the way to go

thheller14:02:35

hehe I wanted something like this a very long time ago

thheller14:02:18

(pr-str name)
=> #<function cljs.core/name line:5876>

Roman Liutikov14:02:24

I know this is kind of unnecessary when you used to read stack traces, but would be a nice to have for novice devs

thheller14:02:13

I wanted that because accidentally printing functions was annoying as hell

darwin14:02:31

btw. Dirac DevTools tries to do demunging

thheller14:02:43

but it really isn't feasible

Roman Liutikov14:02:37

@darwin what about cljs-devtools?

darwin14:02:38

well, cljs devtools tries to present user-friendly names when formatting, if I remember correctly

thheller14:02:42

the analyzer doesn't know about every fn that is created

thheller14:02:00

so you still end up with a bunch of anonymous functions

darwin14:02:05

but logging is not the only place where names are presented

darwin14:02:31

that is why in Dirac I try to beautify function names in the DevTools UI everywhere

thheller14:02:38

also the closure compiler didnt like this

thheller14:02:20

since there were a bunch more names it hard to process but I really don't remember the details

thheller14:02:25

way too long ago now

thheller14:02:11

also source maps are a way better solution 😉

thheller14:02:32

not sure how well this works

anmonteiro16:02:08

@thheller no problem, glad you figured it out. Kinda interesting how goog/isFunction ended up being replaced by ga too 🙃

thheller16:02:03

the fact that everything worked with 1.9.293 is so strange, the externs where missing there as well. guess it replaced a function I didn't reach but then at some point that was shifted.

thheller16:02:11

weirdest few hours of debugging ever 🙂

samueldev19:02:13

so im encountering some funny behaviour w/ cljs spec

samueldev19:02:25

annnd my code snippet upload is failing 😞 stupid s3

samueldev19:02:36

(ns foo
  (:reqire [my-project.domain.specs :as specs]
               [cljs.spec :as s]))

;; for reference: the predicate on :specs/thing is just `string?`

(js/console.info "Incorrectly used other-ns-spec evaulates to:" :specs/thing) // => :specs/thing

;; ^ it correctly fails to identify that as the `thing` spec from the `specs` namespace and assumes the literal keyword ":specs/thing"

;; but..

(s/valid? :specs/thing "") // => true
(s/valid? :specs/thing {}) // => false

;; ^ it correctly identifies & validates when doing an s/valid

samueldev19:02:21

is there some magic going on under the hood to correct that mistake when doing validations?

samueldev19:02:56

this isnt causing any problems, its just a common mistake my team members themselves making when still learning :: vs : that im curious to know if is working as intended

anmonteiro19:02:16

@samueldev you should be using ::specs/thing for the keyword to be expanded as :my-project.domain.specs/thing

samueldev19:02:38

@anmonteiro yup I understand that now - but am curious as to why the validation passes (it seems to correct the mistake for you, and understand what you were trying)

favila19:02:49

@samueldev Are you sure that s/def is ::thing and not :spec/thing?

favila19:02:58

can you paste the def?

samueldev19:02:33

@favila >< that was the mistake

samueldev19:02:40

sorry to bother! working as intended and no confusion now. sorry again.

samueldev19:02:31

ok @favila @anmonteiro i dont think im crazy

samueldev19:02:33

look at this better example

samueldev19:02:52

(s/def ::this-is-a-test-map-spec
  (s/keys :req-un [:blah/asdf :blah/fdsa]
          :opt-un []))

(js/console.log "1:::::::")
(def val1 "")
(js/console.info (if (s/valid? ::this-is-a-test-map-spec val1)
                   true
                   (s/explain-data ::this-is-a-test-map-spec val1)))


(js/console.log "2:::::::")
(def val2 {:asdf "" :fdsa {}})
(js/console.info (if (s/valid? ::this-is-a-test-map-spec val2)
                   true
                   (s/explain-data ::this-is-a-test-map-spec val2)))


(js/console.log "3:::::::")
(def val3 {})
(js/console.info (if (s/valid? ::this-is-a-test-map-spec val3)
                   true
                   (s/explain-data ::this-is-a-test-map-spec val3)))

anmonteiro20:02:22

what about it?

samueldev20:02:28

sorry had to edit

samueldev20:02:24

in ^ that example code, the output is thus: https://puu.sh/uo7l0/a231485d14.png

samueldev20:02:34

1 fails accordingly: its not a map

samueldev20:02:39

3 fails accordingly, the map is missing keys

samueldev20:02:40

but 2 passes

samueldev20:02:50

even though there is no "blah" namespace being imported

anmonteiro20:02:11

@samueldev uh…`:req-un [:blah/asdf :blah/fdsa]` this doesn’t make sense to me

anmonteiro20:02:32

you’re saying “these unnamespaced keywords are required”, but you’re passing namespaced keywords

Alex Miller (Clojure team)20:02:47

the namespaced keyword is the name of the spec

Alex Miller (Clojure team)20:02:56

just the name part is used to match the key

anmonteiro20:02:20

OK I’m probably not the best person to be answering spec questions 🙂

samueldev20:02:05

i guess im saying i would expect #2 to fail

Alex Miller (Clojure team)20:02:31

Is there a spec for :blah/asdf ?

anmonteiro20:02:34

it has :asdf and :fdsa which are required

samueldev20:02:46

there is no blah namespace being imported

samueldev20:02:51

nor a :specs/blah defined

Alex Miller (Clojure team)20:02:52

then as @anmonteiro said, it’s meeting the spec

Alex Miller (Clojure team)20:02:08

the spec requires those (unqualified) keys to exist, and they do

samueldev20:02:43

is :blah/asdf going to make it look for the key :asdf? i guess im just misunderstanding

Alex Miller (Clojure team)20:02:54

that’s what the “-un” part means

samueldev20:02:56

i would think that :blah/asdf would only look for :blah/asdf

Alex Miller (Clojure team)20:02:45

(s/keys :req [:blah/asdf :blah/fdsa]) will look for a map with keys :blah/asdf and :blah/fdsa

samueldev20:02:57

^ as i would expect

Alex Miller (Clojure team)20:02:01

(s/keys :req-un [:blah/asdf :blah/fdsa]) will look for a map with keys :asdf and :fdsa

samueldev20:02:25

okay. so basically i can effectively think of the -un as trimming anything but the last part of the keyword (anything after a /) ?

Alex Miller (Clojure team)20:02:38

in both cases, keys will try to validate the value for those entries with the specs for :blah/asdf and :blah/fdsa

Alex Miller (Clojure team)20:02:07

the / is the divider between the qualifier and the name of the keyword

samueldev20:02:59

okay. that was my confusion then. i assumed that :blah/asdf would not do any "trimming" and would look for explicit :blah/asdf - i understood it was only parsing qualifiers VS keywords when using :req

samueldev20:02:30

my bad 🙂 thanks so much for the clarification guys

samueldev20:02:39

if i have :blah/asdf and :blah2/asdf, how does it resolve?

samueldev20:02:52

also in the above examples i perhaps wasnt clear: :blah/asdf and :blah/fdsa are not defined anywhere

dnolen20:02:00

they don’t need to be

dnolen20:02:03

keywords aren’t resolved

Alex Miller (Clojure team)20:02:25

if you have two :req-un specs that share the same name, the result is undefined (so don’t do that)

samueldev20:02:16

so

(s/def ::this-is-a-test-map-spec
  (s/keys :req-un [:blah/fdsa]
          :opt-un []))
Does not throw an assertion error, but
(s/def ::this-is-a-test-map-spec
  (s/keys :req-un [:fdsa]
          :opt-un []))

does

samueldev20:02:48

i would expect the latter case to work given the above assessment

Alex Miller (Clojure team)20:02:14

in both cases, you are expected to provide a fully-qualified keyword that refers to a spec

Alex Miller (Clojure team)20:02:12

keys does two things: 1) checks that required keys exist (fully-qualified for req, unqualified for req-un) and 2) checks that the value for every key is valid according to the spec

favila20:02:33

@samueldev Said differently, :req-un and :opt-un are the only exception to the spec rule that "Map specs should be of keysets only" https://clojure.org/about/spec#_map_specs_should_be_of_keysets_only

favila20:02:20

It only allows one kind of aliasing: an un-namespaced key to a spec with a matching name part.

favila20:02:31

rather than arbitrary keyword to the spec

Alex Miller (Clojure team)20:02:41

I don’t see how that’s an exception

Alex Miller (Clojure team)20:02:08

it’s still a map defined by its key specs

favila20:02:32

the same keys could be mapped to different specs

favila20:02:43

depending on the spec for the map

Alex Miller (Clojure team)20:02:23

every map spec still defines only one spec for that key though

favila20:02:52

yes but {:foo "x"} could be e.g. :bar/foo or :baz/foo spec depending on what spec you choose to conform the map to

Alex Miller (Clojure team)20:02:34

yes, but you must choose. whichever you choose, the map spec specifies the key spec

favila20:02:37

but the key in the map and the key for the spec do not match

Alex Miller (Clojure team)20:02:10

but that doesn’t violate the point being made in that section

Alex Miller (Clojure team)20:02:23

which is that a map spec is built up of key specs

Alex Miller (Clojure team)20:02:05

and the specs used for values in the map are not specified by the map spec but by the spec identified (whether exact or partial match) by the key

Alex Miller (Clojure team)20:02:44

I’m disagreeing with "the only exception to the spec rule"

favila20:02:27

> I.e. in such approaches the schema for a map might say :a-key’s type is x-type and :b-key’s type is y-type

favila20:02:46

I'm saying :req-un and :opt-un is a very limited way of letting this property in

favila20:02:31

(i.e. the field name and the type name differ)