Fork me on GitHub
#clojurescript
<
2018-03-22
>
evangeline06:03:23

hi all, i've been struggling with writing regex that validates if the input is a linkedin url. writing a really simple regex expression into the cljs repl works, eg

(def r #"http")
however, this doesn't seem to work, eg
(def r #"https:\/\/www\.linkedin\.com\/in\/.*")

evangeline06:03:48

this is the error i get:

#object[SyntaxError SyntaxError: Invalid regular expression flags]
	 figwheel$client$utils$eval_helper (jar:file:/Users/evangeline/.m2/repository/figwheel/figwheel/0.5.3-2/figwheel-0.5.3-2

evangeline06:03:44

the weird thing is everything works for me in a clj repl/clj file, but breaks when it's in cljs repl/cljs file. any advice would be awesome 🙂

rauh07:03:04

@evangelinechengg You don't need to escape / in regex created with the reader #

evangeline11:03:53

got it, thanks!

rauh07:03:26

I guess that might be a bug in the REPL then. It should also result in the same error

vinai07:03:23

I'd like to try out the aot-cache in a project that uses lein for the build config. The cljsbuild compiler options are

{:main cljs.user,
          :preloads [devtools.preload],
          :asset-path "/js/compiled/out",
          :output-to "resources/public/js/compiled/app.js",
          :output-dir "resources/public/js/compiled/out",
          :source-map-timestamp true,
          :aot-cache true,
          :closure-defines {re_frame.trace.trace_enabled_QMARK_ true}}
When starting up figwheel (0.5.15) repl I get the error message
Found unrecognized key :aot-cache at path (:cljsbuild :builds 0 :compiler)
Must be one of: ...
Do I have to use a non-stable figwheel release?

vinai07:03:01

A :validate-config false in the figwheel configuration resolved the problem. It now builds, but other issues are happening. Because of time running out I'll go back to :aot-cache false for now.

rickmoynihan12:03:56

Is anyone using integrant with cljs? https://github.com/weavejester/integrant It seems that load-namespaces is only available in the clojure implementation… which appears to be because require is unavailable in clojurescript. Is that right? I’ve seen that lumo however does let you do require; but it appears that lumo implements require as a macro, which obviously means that it behaves very differently to in clojure where it’s a function. My motivation is that I’d like to use integrant to componentise things (so they’re not in the ns require tree), but are in a configuration file… but it seems this is going to be awkward. Also I’m not entirely sure on the point of integrant working with cljs if it can’t load-namespaces.

rickmoynihan12:03:13

I suspect this is because of clojurescript using the clojure compiler…

rickmoynihan12:03:38

i.e. I’d have to require every namespace in the app to load it… which is duplication.

rickmoynihan12:03:34

I guess I’d have to make load-namespaces a macro to work with lumo… macro contagion.

dnolen13:03:59

@rickmoynihan Clojure tools that rely on reified vars and namespaces are unsuitable for ClojureScript

dnolen13:03:06

I would not bother

rickmoynihan13:03:10

@dnolen: Yeah, I think this is what I’m finding 🙂

borkdude13:03:31

Upgraded our front-end to the newest cljs, so far found no regressions.

dnolen13:03:50

@rickmoynihan there are some very restricted things that aren’t challenging, cljs.test is a good example

dnolen13:03:11

we just mimic the API, but as macros

borkdude13:03:11

I had to explicitly bump the tools.reader version, but I don’t know if it’s related to cljs.

dnolen13:03:29

for typical usage this is not a big deal

rickmoynihan13:03:38

yeah i understand

rickmoynihan13:03:20

or at least I understand why it might be necessary to resort to hacks like this… as in cljs the read/compile/eval cycle is split across languages, so I can see why require actually needs to trigger compilation (by triggering the reader) and therefore needs to be macro so it happens at the right time. i.e. implication of having two different environments. Is that more or less right?

dnolen13:03:12

require doesn’t trigger compilation

dnolen13:03:27

we need distinguish what the REPL does from how the compiler actually works

rickmoynihan13:03:00

sure — but require triggers load which triggers the eval cycle right? In clojure anyway?

dnolen13:03:39

right, it triggers loads of files, because that’s possible anywhere

dnolen13:03:55

in ClojureScript you cannot require in random locations

rickmoynihan13:03:17

yeah which is what I’m finding. And that’s why it has to be a macro… i.e. to force contagion

dnolen13:03:20

the REPL has special treatment of require to mimic expectation

rickmoynihan13:03:32

and force that it happens at compile time when clj env is available?

dnolen13:03:38

@rickmoynihan that’s not true

rickmoynihan13:03:46

ahh ok. Interesting.

dnolen13:03:47

we need to rewind - abandon your understanding of Clojure

dnolen13:03:55

ClojureScript uses Google Closure

rickmoynihan13:03:05

Ok brain wiped.

dnolen13:03:05

Google Closure only supports static require at the top of a file

dnolen13:03:21

that’s the limitation that everything is designed around

dnolen13:03:47

in ClojureScript require is just goog.require

dnolen13:03:54

and all of it’s limitations

rickmoynihan13:03:10

in javascript is that true of google closure too?

dnolen13:03:22

it is how Google Closure works

dnolen13:03:32

we’re not inventing stuff here

rickmoynihan13:03:02

ok understood. So google closure is actually javascript with this extra restriction.

dnolen13:03:19

absolutely

rickmoynihan13:03:45

ok… so guessing for closure to do its analysis… it treats goog.require more like a syntax directive / special form… i.e. at compile time it inspects each file for those so it knows the extents of the project for dead code elimation etc.. This is the sense in which it is a “static require”, right?

rickmoynihan13:03:05

i.e. though it might evaluate the require expression as javascript, it does so outside of normal evaluation. (though I guess it could also evaluate it later on at runtime - but if it did they’d likely be a different implementation as the purpose would be different)

rickmoynihan13:03:43

Ok… So I’m assuming you’re going to say that clojurescript also requires (ns foo (:require [foo.bar :as baz]) to be at the top of the file… and that it basically compiles into goog.require.

dnolen13:03:32

ClojureScript is AOT-centric due to Google Closure compiler

dnolen13:03:42

this is a fundamental difference with Clojure

dnolen13:03:05

which means that ClojureScript REPLs are bit of a heroic effort to simulate expecations

dnolen13:03:29

but we can’t do everything

rickmoynihan13:03:09

So what I don’t understand is what magic you can possibly do to make the require macro work… i.e. if you need to emit a require at the top of a file. How would this work:

(if true
   (require '[foo.bar])
   (require '[foo.baz]))

rickmoynihan13:03:50

sorry forgetting require macro is lumo

dnolen13:03:52

has to be real top-level

rickmoynihan13:03:06

I can see how it can work then… as you just start a new file

dnolen13:03:12

lumo, planck etc. are just different, they are bootstrapped

dnolen13:03:30

but as a general rule they don’t break the rules - otherwise CLJS wouldn’t be portable

rickmoynihan13:03:07

do you get an error if you use a require inside a condition?

rickmoynihan13:03:20

not sure how that would be possible — at least from inside require itself.

dnolen13:03:23

I think there’s a basic check

rickmoynihan13:03:49

I guess it would need to be handled in the reader/compiler somehow as a special case?

rickmoynihan14:03:25

Anyway thanks for the brain transplant 🙂

grounded_sage14:03:32

Is anyone here familiar with React Native and React Dom when used from Rum?

Roman Liutikov14:03:46

@grounded_sage anything specific? I might help

grounded_sage14:03:43

@roman01la my question is in #cljsrn

grounded_sage14:03:23

Basically on the tail end of getting React Native for Web to be in a usable state

Roman Liutikov14:03:14

I know nothing about RN for Web. But in Rum there’s no special syntax for JS React components, just call them as if you would do it in JS

grounded_sage14:03:07

Essentially the API of RN4W is designed to reflect RN. That way you can write components that can render on either Web or Native.

grounded_sage14:03:12

I'm just not familiar with RN so I'm not sure how to go about the mounting part as the AppRegistry.runApplication isn't the way it is done on all the CLJS RN examples I can find.

grounded_sage14:03:17

This worked fine for me in reagent.

["react-native" :as react-native :refer (Text View)]))

(def ViewR (r/adapt-react-class View))

(defn app []
  [:div
   [ViewR {:style {:background-color "red" :height "100%" :width "100%"}
           :accessibility-role "main"}.......

grounded_sage14:03:09

But there is no way to adapt the react class without doing frustrating hacks which weren't working for me. So I am going the remove Sablono entirely approach that the Rum RN people do.

sundbp14:03:32

I’m using cljs in a nodejs setting. I’m looking for a way to make a synchronous http post request. In my case I’d like to initialize some state with a JWT token at startup (in e.g. a mount defstate). I can only find async versions.. Any ideas?

thheller14:03:04

not possible in node

sundbp14:03:34

figured.. annoying

thheller14:03:29

you could go crazy and use the node child_process package with spawnSync to run curl or so 😉

thheller14:03:54

but really everything in node is async so better get used to it

sundbp14:03:22

every time it takes me a few days to switch modes.

JJ14:03:52

@thheller well, not everything 🙂 they have sync versions of some stuff

thheller14:03:23

@grounded_sage looks like you are passing a cljs object directly to a JS fn

grounded_sage14:03:40

Ah ok. Probably something to do with what I did here.

(defn ^:export init []
  ;; init is called ONCE when the page loads
  ;; this is called in the index.html and must be exported
  ;; so it is available even in :advanced release builds
  (do
    (mount AppRoot)
    (.registerComponent AppRegistry "app" (fn [] root-component-factory))
    (.runApplication AppRegistry "app" #js{:rootTag (. js/document (getElementById "app"))}))

  (js/console.log "init")
  (start))

grounded_sage15:03:11

I decided to follow more closely the RN approach and just tear out Sablono with :exclusions

lwhorton15:03:22

i’m not sure i fully understand DCE in the closure compiler. if I used https://github.com/binaryage/cljs-oops instead of externs files, for example - how does the compiler know what I’m actually using?

darwin16:03:43

@lwhorton string names (generated by cljs-oops) are equivalent to externs, AFAIK externs are not used to help DCE to do a better job, @lee.justin.m just wrote a piece which might be relevant https://gist.github.com/jmlsf/f41b46c43a31224f46a41b361356f04d

lwhorton16:03:51

I think the part i’m confused about is the new-ish :npm-deps config, and the “auto resolution” of common node module formats… how the heck does the compiler know what you use and dont use? how does that relate to externs, etc?

alex-dixon16:03:03

Was about to ask a question about using JS in CLJS 😄 Seems I’m the third today at least. There’s a bit riding on this --- I might (finally) be able to use CLJS for a project at work. — so I can use all the help I can get…apologies for any redundancy. Situation is basically I’d like to use 20-30 React components written in JSX and ES6 (and their dependencies) from CLJS using Reagent and Reframe. I’m leaning toward trying out shadow-cljs but wanted to check here regarding any advancements in 1.10 that I might be able to use

mikerod17:03:55

another possibility is to use the “double bundle” style https://github.com/pesterhazy/presumably/blob/master/posts/double-bundle.md

mikerod17:03:13

if you are trying to use packages that aren’t in CLJSJS already (or not up-to-date enough/broken etc)

mikerod17:03:26

That let’s you stick more to your familiar ecosystem. Just have to do a step with webpack

mikerod17:03:46

I’m leaning towards using this approach myself going forward (at least for now). Shadow seems interesting, I’m just not sure I want to dive all the way in on that as of now.

mikerod17:03:02

I also, like to have a good both clj/cljs setup, I think shadow would be more specific to just cljs

mikerod17:03:17

just giving you other ideas though. Not against anything here

grounded_sage04:03:17

I've been playing with Shadow. It's a very nice experience so far. It essentially just changes the cljs building step. So it can be incorporated into the other build tools if you want to keep using Leiningen and Boot etc.

lwhorton16:03:38

thanks for that link @darwin

JJ16:03:52

@darwin shadowcljs has its own extern inference?

darwin16:03:40

but better ask @thheller, I haven’t used shadow-cljs yet

JJ16:03:50

Shadow can infer externs from them, which is a real advantage over some other approaches relying on the built-in compiler's extern inference.

JJ16:03:57

from the .md

thheller16:03:23

@devicesfor yes it does its own inference

JJ16:03:52

ah interesting

justinlee16:03:44

@alex-dixon the little writeup I did definitely does not include any improvements that may be coming down the pipe from 1.10

lwhorton16:03:13

can someone point me to an example of using lein w/ a foreign-lib packaged as a umd via node_modules? do I add node_modules to my resource-paths so that I can configure a lib like follows:

:foreign-libs [{:file "node_modules/recharts/umd/Recharts.js"
                   :file-min "node_modules/recharts/umd/Recharts.min.js"
                   :provides ["recharts"]
                   :global-exports {recharts Recharts}}]

justinlee16:03:03

@lwhorton I no longer use lein so I don’t really know the answer to your question, but I remember having trouble getting the paths to work and the way I solved it when I was using foreign-libs was to copy the umd builds into a “lib” directory in my source tree and just do it that way. One other thing: you might add a “./” in front of those paths to see if it just works because the compiler documentation has that. Shouldn’t make a difference but…

lwhorton17:03:26

third party stuff is such a bummer

justinlee17:03:59

It’s this exact kind of stuff that makes lein a troublesome tool for me. It’s almost impossible to track stuff down because the way it is all declarative.

lwhorton17:03:25

so you roll with boot, or shadowcljs?

lwhorton17:03:40

im hesitant to use shadow if only because its kind of the new kid and I dont want to be the one to work out the problems

justinlee17:03:01

it’s actually been around for a while and thheller is there to answer questions

lwhorton16:03:02

I guess I don’t understand the distinction between a source and a resource 😕

joelsanchez16:03:54

;; CLJ
(clojure.string/lower-case 7)
=> "7"
;; CLJS
(clojure.string/lower-case 7)
#object[TypeError TypeError: s.toLowerCase is not a function]
fine...

mfikes17:03:15

I've assumed that both of the programs above are incorrect, and that it only accidentally does something in Clojure.

mfikes17:03:49

(Clojure wan'ts a CharSequence.)

mfikes17:03:33

@lwhorton Both source files and resources are loaded from the classpath, FWIW.

🎉 4
mfikes17:03:40

Point 4 in the clojure.string namespace document is relevant to the above. https://clojure.github.io/clojure/clojure.string-api.html

jmckitrick17:03:21

I don’t understand why I see :scope "provided" on cljs dependencies. I don’t see a difference either way in my projects. When is it useful?

juhoteperi17:03:26

@jmckitrick By default boot (and I think lein) don't include files from provided scope in uberjar. And the Cljs lib files are not useful in uberjar as Cljs has been compiled into JS.

jmckitrick17:03:02

So it gives me a smaller build. Thanks!

juhoteperi17:03:27

Based on Lein docs, it doesn't care about dependency scopes, but Leiningen profiles, so maybe this doesn't work with Lein.

john18:03:15

I need a way to reliably inject a cljs repl into any given web page

lwhorton19:03:11

a long while ago I remember cljs didn’t support runtime resolve of namespaces, is that still the case?

lwhorton19:03:00

it’s probably really awkward to do that with how :advanced munges namespaces, right?

mfikes19:03:37

Yeah... they are potentially completely DCEd in a sense

nathanmarz19:03:00

when creating a MapEntry object manually in cljs, should the last param be nil? e.g. (cljs.core/->MapEntry :a 1 nil)

mfikes19:03:01

FWIW, there is a "static" cljs.core/resolve. You'd need to use self-hosted, and eval to have a true resolve (Planck has one in planck.core/resolve)

mfikes19:03:56

@nathanmarz Yeah, that is the mutable __hash field.

mfikes19:03:23

If you don't need outright blazing speed, perhaps something like (defn map-entry [k v] (first {k v})) suffices, without actually having a nice MapEntry constructor

mfikes19:03:15

(I don't know what the story is on directly constructing core types... whether the basis parameters are private or subject to change, etc.)

nathanmarz19:03:42

hmm, this is for specter so need it to be as fast as possible

nathanmarz19:03:06

this is for producing a new map entry object with updates to its key and/or value

mfikes19:03:22

Yeah, well, the last param to MapEntry can be nil. IIRC that's done all over the place in cljs.core

nathanmarz19:03:36

is that just a cache for when the hash does get computed?

mfikes19:03:55

Yeah, I think most of the types work that way. It is a cached mutable field that is lazily computed

nathanmarz19:03:46

ok cool, thanks for the help

mfikes19:03:48

cljs.user=> (.-__hash (->MapEntry 1 2 nil))
nil
cljs.user=> (.-__hash (doto (->MapEntry 1 2 nil) hash))
1185709346

mfikes19:03:59

Oh @nathanmarz If you are going down that path, there are other types that satisfy map-entry? that you may want to support when updating a key or value: cljs.core/BlackNode and cljs.core/RedNode

mfikes19:03:22

(They come out of the sorted-map impl.)

mfikes19:03:55

I wonder what you'd do in that case, as they might be entangled with their left and right fields. Perhaps you would convert a RedNode or BlackNode to a MapEntry so that you end up with a value that still satisfies map-entry? but has a new key or value

mfikes20:03:57

I suppose you are after the idea of maintaining the shape and type of a structure, unlike clojure.walk/walk which converts map entries to vectors

nathanmarz20:03:38

yea, those specifics of map entry differences don't matter for specter, my issue was prompted since the behavior of records with respect to mapentry seems to have changed in 1.10

nathanmarz20:03:13

basically converting to a lazyseq when doing a conj onto a record now errors

mfikes20:03:20

Yeah. And, I think MapEntry as a type does exist in 1.9.946, so perhaps such code may not absolutely require 1.10

nathanmarz20:03:59

ah indeed, that's good to know

mfikes20:03:16

@nathanmarz What is an example of a conj with a record that fails?

mfikes20:03:32

Maybe we have a bug in 1.10, if it differs from Clojure behavior.

nathanmarz20:03:30

cljs.user=> (defrecord Foo [a])
cljs.user/Foo
cljs.user=> (def f (->Foo 1))
#'cljs.user/f
cljs.user=> (conj f (list :a 2))
Error: :a is not ISeqable
    at Object.cljs$core$seq [as seq] (/Users/nathan/opensource/specter/.cljs_node_repl/cljs/core.js:4441:8)
    at Function.cljs.core.seq_reduce.cljs$core$IFn$_invoke$arity$3 (/Users/nathan/opensource/specter/.cljs_node_repl/cljs/core.js:7982:26)
    at Function.cljs.core.reduce.cljs$core$IFn$_invoke$arity$3 (/Users/nathan/opensource/specter/.cljs_node_repl/cljs/core.js:8155:29)
    at cljs$core$reduce (/Users/nathan/opensource/specter/.cljs_node_repl/cljs/core.js:8105:25)
    at cljs.core.pr_str.cljs.user.Foo.cljs$core$ICollection$_conj$arity$2 (repl:148:25)
    at cljs$core$_conj (/Users/nathan/opensource/specter/.cljs_node_repl/cljs/core.js:1637:13)
    at /Users/nathan/opensource/specter/.cljs_node_repl/cljs/core.js:7987:98
    at Function.cljs.core.seq_reduce.cljs$core$IFn$_invoke$arity$3 (/Users/nathan/opensource/specter/.cljs_node_repl/cljs/core.js:7988:3)
    at cljs.core.List.cljs$core$IReduce$_reduce$arity$3 (/Users/nathan/opensource/specter/.cljs_node_repl/cljs/core.js:10371:29)
    at Function.cljs.core.reduce.cljs$core$IFn$_invoke$arity$3 (/Users/nathan/opensource/specter/.cljs_node_repl/cljs/core.js:8141:13)

nathanmarz20:03:25

that doesn't work in clojure, but it used to work in cljs

mfikes20:03:54

Yeah, I vaguely recall something surrounding that corner case...

nathanmarz20:03:36

yea, it's no big deal

nathanmarz20:03:50

glad that MapEntry is now in cljs

mfikes20:03:01

I think what I recall is making sure (conj f [:c 2]) works

mfikes20:03:55

Cool. I've been pondering what use might be found with the new MapEntry stuff. I assume that if nothing else it makes some code that is shared between Clojure and ClojureScript perhaps more uniform.

nathanmarz20:03:35

and makes doing blind walks cleaner

mfikes20:03:53

And I suspect for Specter the "shape preserving" stuff might be better

mfikes20:03:27

Or whatever you call that aspect: Where you maintain the type of the nested data structure.

nathanmarz20:03:18

doesn't affect that really, since that's already handled one level above that by whatever navigator is operating on the data structure as a whole

mfikes20:03:24

Ahh, that reminds me. Nobody seems to have complained that (empty (first {:a 1})) now returns nil