Fork me on GitHub
#clojurescript
<
2018-06-19
>
bhauman01:06:16

@wilkerlucio in what environment are you testing, and or are you using any testing libraries?

bhauman01:06:45

because I don't get an assert type in any of my tests

wilkerlucio01:06:16

@bhauman now that you mentioned, I did included fulcro-spec, but wasn't using on the given example, but seems like it's leaking there, found it on fulcro-spec code

wilkerlucio01:06:27

thanks for bringing the question 🙂

sofra06:06:45

I got the new webpack support working ok following the guide (https://clojurescript.org/guides/webpack) but have not been able to get it to work in conjunction with lein-cljsbuild, anyone else tried this yet?

dnolen11:06:12

@sofra it would help to describe what problems you are ecountering?

dnolen11:06:48

lein run -m cljs.main ... should work

bhauman14:06:12

lein run -m cljs.main -- ... need the -- before the rest of the args

darwin12:06:37

@wilkerlucio unrelated note, maybe consider using the latest cljs-devtools, to get rid of that “MapEntry” types: https://github.com/binaryage/cljs-devtools/releases/tag/v0.9.10

👍 4
wilkerlucio12:06:00

@darwin thanks! one idea, had you though about giving some option to sort the map keys in the output?

Roman Liutikov14:06:50

👋 Been working on JS to ClojureScript transpiler. Should be useful for beginners to play with small code samples and see how it looks like in Clojure. Obviously it’s not gonna generate very idiomatic Clojure, but it tries to do so 🙂 https://roman01la.github.io/javascript-to-clojurescript/

👍 8
metal 8
the-kenny14:06:06

I'm in the process of moving to :npm-deps for our project at work. However, I'm running into an issue where one of the npm-deps is written using ES6 and using export default .... The optimization pass (right now simple) throws various errors like JSC_LANGUAGE_FEATURE. This language feature is only supported for ECMASCRIPT6 mode or better: modules. My first guess was setting :language-in and/or :language-out in the compiler options, but every combinations trigger other errors.es6 as in, es5 as our for example triggers the error that modules can only use either export default OR goog.provide, but the files in out/node_modules/<dep-name>/dep.js contain a goog.provide with a custom Clojurescript package path module$home$moritz$... at the top and the es6 export at the bottom.

the-kenny14:06:32

The dependency in question also includes non-es6 compatible code in a different subdirectory. The package.json specifies both: "main": "lib/index", "module": "es/index". es/ contains the es6 stuff, lib contains the "normal" stuff.

dnolen14:06:34

@the-kenny unless you’re willing to sink a lot of time to sort out these kinds of issues I would probably not go this route - what’s stopping you from just going the Webpack double bundle (now officially documented) route if you need to consume node_modules?

the-kenny14:06:35

@dnolen We wanted to try the npm-deps stuff. Just ran into this issue half an hour ago or so. If there's no simple fix we'll go back to the separate webpack bundle approach. Our major goal was simplifying the use of external libraries, especially related to externs. Right now we have a bundle.js which includes all javascript libs and re-exports them for clojurescript. This requires manual maintenance of our externs. We can't use cljsjs for most stuff as other non-cljsjs-packaged stuff has dependencies on it. Is your double-bundle something different than this simple bundle.js + app.js approach?

dnolen14:06:06

you don’t need to bother with externs

dnolen14:06:21

there may be some minor issues around externs - but this is way more tractable to fix quickly then :npm-deps

the-kenny14:06:24

I'll have a look, thanks 🙂 We really neglected the whole client side compilation story for way too long

dnolen14:06:57

:npm-deps requires too much coordination between practice, ClojureScript, and Google Closure Compiler for now - it’s promising but simply too fiddly

dnolen14:06:46

externs inference + global-exports removes nearly all of the major previous annoyances

the-kenny14:06:19

yeah, that was my impression too. Worked quite fine for most stuff, but the es6 stuff seemed like some major issue

dnolen14:06:22

and because foreign-libs can be overriden - you can build whatever you want and stuff like Reagent just works anyway

dnolen15:06:25

@the-kenny small favor, if you could produce a minimal case and file what you encountered that would be very helpful

dnolen15:06:31

so we don’t lose track of this :npm-deps issue

the-kenny15:06:01

@dnolen Oh yeah, absolutely. Got a preferred way of doing so?

dnolen15:06:25

just JIRA ticket, just do this in the most minimal way possible - no other tooling etc.

dnolen15:06:36

given your description this seems pretty straightforward

mikerod17:06:57

I got burned today by CLJS (I believe somewhat new) map entry introduction.

(into {}
      (comp (map (fn [[k v]]
                   [k (inc v)]))
            (filter (comp pos? val))) ;; <- `val` is going to fail, replace with `second` to fix
      {:x 1})

mikerod17:06:18

I get why it fails, val can only be called on a map entry. It makes writing transducers awkward

mikerod17:06:58

It used to not fail in fairly recent cljs versions. I’d have to track all that down to see why, just thought I’d post on the general concept. [org.clojure/clojurescript "1.10.312"]

mikerod17:06:46

then again, this is the same in CLJ, so I’m sure it is going to be written off as “intended behavior”. I guess a map-entry constructor would be nice, but that’s still extra stuff to miss

mikerod18:06:25

I think maybe a takeaway is that I should really reserve key and val usage to perhaps when perf needs. it doesn’t seem to be good in transducers because it can’t compose with functions like above where the “map entry” may be devolved to a 2-vector

flyboarder18:06:08

For anyone who is interested in following along:

johanatan20:06:37

is: (apply f #js [:blah :blaz]) discouraged?

johanatan20:06:04

[it seems to surprisingly work but i could see how some may have stylistic concerns about it]

johanatan20:06:51

@mikerod have you considered using specter for that transformation? potentially more concise and probably sidesteps the issue you ran into

mikerod20:06:59

@johanatan it was just a contrived example

johanatan20:06:34

still in whatever use case you may have wanted to avoid that situation for in the wild, specter could be a solution

mikerod20:06:41

I’m aware of specter though and know how it can possibly help in nested transformation cases etc

mikerod20:06:03

I don’t know that I’d think to use spector for a small composed transducer though

dnolen21:06:00

final argument has to be seqable

johanatan21:06:13

it seems to work though

dnolen21:06:19

that doesn’t really matter

johanatan21:06:24

ok, fair enough

dnolen21:06:47

@johanatan sorry was completely confused

dnolen21:06:58

that’s an array, yes

dnolen21:06:07

I hallucinated and saw {

dnolen21:06:26

array’s are seqable so yes that works and that’s expected

johanatan21:06:25

cljs.user=> (require '[goog.object :as gobj])
nil
cljs.user=> (gobj/get js/process.env "blah")
nil
cljs.user=> (defn getenv [v] (gobj/get js/process.env v))
#'cljs.user/getenv
cljs.user=> (import '[goog.string format])
nil
cljs.user=> (format "blah: %s" nil)
"blah: null"
cljs.user=> (format "blah: %s" (getenv "blah"))
[goog.string.format] Not enough arguments
	 replacerDemuxer (evalmachine.<anonymous>:78:13)
	 String.replace (NO_SOURCE_FILE <anonymous>)
	 Object.goog.string.format (evalmachine.<anonymous>:87:19)
	 (evalmachine.<anonymous>:1:13)
	 ContextifyScript.Script.runInThisContext (vm.cljs:50:33)
	 Object.runInThisContext (vm.cljs:152:38)
	 (Object._t)
	 (Object.lumo.repl.caching_node_eval)
	 (NO_SOURCE_FILE <embedded>:6127:273)
	 E (NO_SOURCE_FILE <embedded>:6128:269)
cljs.user=> (getenv "blah")
nil
anyone know what is going on with the above ^^ ?

johanatan21:06:17

further reduced:

cljs.user=> (format "blah: %s" (gobj/get js/process.env "blah"))
[goog.string.format] Not enough arguments
	 replacerDemuxer (evalmachine.<anonymous>:78:13)
	 String.replace (NO_SOURCE_FILE <anonymous>)
	 Object.goog.string.format (evalmachine.<anonymous>:87:19)
	 (evalmachine.<anonymous>:1:13)
	 ContextifyScript.Script.runInThisContext (vm.cljs:50:33)
	 Object.runInThisContext (vm.cljs:152:38)
	 (Object._t)
	 (Object.lumo.repl.caching_node_eval)
	 (NO_SOURCE_FILE <embedded>:6127:273)
	 E (NO_SOURCE_FILE <embedded>:6128:269)

johanatan22:06:53

this is my workaround for now (which works as expected):

(defn log-value [value-name value]
  (js/console.log (format "%s: %s" value-name (when value value))))

justinlee22:06:10

@johanatan I can repo in lumo. Even crazier:

cljs.user=> (defn always-nil [] nil)
#'cljs.user/always-nil
cljs.user=> (format "blah: %s" (always-nil))
"blah: null"

justinlee22:06:04

It seems to me that Can’t Possibly Be Happening (tm)

johanatan23:06:39

@lee.justin.m how is that "crazier"? seems expected to me

johanatan23:06:10

oh, because it's another function that returns nil?

justinlee23:06:11

right. it’s crazy that the getenv function does something different than a function that supposedly evaluates to the exact same thing

johanatan23:06:22

yea, i tried that test case as well during my initial testing

johanatan23:06:45

but the root of the problem seems to be gobj/get (whether it is wrapped by another function or not)

lilactown23:06:50

it’s maybe to do with undefined vs null in js?

justinlee23:06:21

(identical? (getenv "blah") (always-nil "blah")) => false hmm

johanatan23:06:26

@lilactown i tested the value returned from gobj/get against nil? and #(= % nil) and it behaved as expected

johanatan23:06:49

i.e., those are both true.

justinlee23:06:44

i really thought identical? on nil values would always be true

lilactown23:06:50

cljs.user=> (nil? js/undefined)
true

johanatan23:06:06

cljs.user=> (identical? nil nil)
true

justinlee23:06:37

ah good call:

cljs.user=> (identical? js/undefined (getenv "blah"))
true

johanatan23:06:42

cljs.user=> (format "blah: %s" js/undefined)
[goog.string.format] Not enough arguments
	 replacerDemuxer (evalmachine.<anonymous>:78:13)
	 String.replace (NO_SOURCE_FILE <anonymous>)
	 Object.goog.string.format (evalmachine.<anonymous>:87:19)
	 (evalmachine.<anonymous>:1:13)
	 ContextifyScript.Script.runInThisContext (vm.cljs:50:33)
	 Object.runInThisContext (vm.cljs:152:38)
	 (Object._t)
	 (Object.lumo.repl.caching_node_eval)
	 (NO_SOURCE_FILE <embedded>:6127:273)
	 E (NO_SOURCE_FILE <embedded>:6128:269)

justinlee23:06:58

it’s returning undefined which prints out as nil but apparently doesn’t work the same way

johanatan23:06:00

undefined needs to be coerced to an actual nil it seems

justinlee23:06:16

well that’s sneaky

justinlee23:06:05

okay well that all makes sense then

johanatan23:06:33

what's the best fix here?

johanatan23:06:48

have getenv return an actual nil when gobj/get returns undefined ?

justinlee23:06:48

i think that code would be more robust if it checked for the length of args and just printed out ‘undefined’ but at least i undersatnd

justinlee23:06:37

yes that’s what I would do. i’m still a bit mystified at where the type coercion is happening

johanatan23:06:53

i am not sure there is any coercion. gobj/get is just returning undefined

johanatan23:06:57

and it gets propagated up from there

johanatan23:06:09

(nil? js/undefined) probably returns true

johanatan23:06:31

as does (= js/undefined nil)

johanatan23:06:35

[just a guess]

justinlee23:06:58

this is what i mean by “coercion”:

cljs.user=> (nil? js/undefined)
true
cljs.user=> (identical? nil js/undefined)
false

justinlee23:06:04

i just find that suprising

lilactown23:06:17

nil? et. al. is defined in terms of coercive-=

lilactown23:06:26

which expands to

(core/defmacro coercive-= [x y]
  (bool-expr (core/list 'js* "(~{} == ~{})" x y)))

johanatan23:06:34

@lee.justin.m ah, yea. that's a bit surprising

lilactown23:06:23

(core/defmacro identical? [a b]
  (bool-expr (core/list 'js* "(~{} === ~{})" a b)))

justinlee23:06:31

i think that using js’s == is probably just fine almost everywhere. i think for nil it’s just a little surprising to me. not crazy, but a bit surprising, because cljs shields you from that terrible javascript coercion most of the time

lilactown23:06:43

so it’s the difference between == and ===

lilactown23:06:03

nil? vs identical?. I agree it is surprising