Fork me on GitHub
#clojurescript
<
2018-03-12
>
fmn00:03:28

How do you actually include assets file from a cljsjs repo using leiningen?

pmooser02:03:39

I'm trying to use cljs.js in a fairly naive way to have a bootstrapped repl, and what I'm seeing is that after I do a require, even though it appears everything succeeded, it still doesn't "know about" the loaded namespace. I can actually access vars and values, bu I get a warning in the JS console about using an "undeclared Var". Does this sound like any kind of specific mistake I'm making with cljs.js to anyone ?

pmooser02:03:49

Ah, it is internally throwing due to it already being provided.

pmooser02:03:19

It's surprising how challenging it has been to figure out how to build a simple embedded repl. Lots of stumbling blocks.

mfikes02:03:59

@pmooser Interesting. I’ve actually not looked at cljs.core/*loaded-libs* behavior in self-hosted, focusing mostly on cljs.js/*loaded*.

pmooser02:03:14

It's really not terribly clear (at least to me) exactly what the minimal required setup is to get a repl that doesn't break like this in subtle ways. I don't even receive the exception when the underlying closure library doesn't load the library - I only saw it because I had a breakpoint.

richiardiandrea02:03:26

Are you using the load-fn? 99% of the times the problem is in the things you return from it in my experience

pmooser15:03:41

I've tried using load-fn, and also (when trying with replumb) the read-fn equivalent. It looks like I'm expected to patch the google closure loading code to not throw if we load something more than once.

richiardiandrea16:03:57

Not clear what you are referring to here .. can you expand some more? Maybe I am missing something. Are you requiring node modules? Is it a shareable project?

pmooser16:03:26

No, unfortunately it's a proprietary work project, and it's not feasible right now to extract an independent case that can be reproduced.

pmooser02:03:48

@mfikes I've tried to look at cljs.js/loaded but I'm often seeing it not update after a require that 'appears' (to me) to be successful, but I suspect it's all due to this same issue, at least for now.

mfikes02:03:11

@pmooser Are you retaining the result of (cljs.js/empty-state) in a var and reusing it between evals?

pmooser02:03:22

Yes, I have a defonce in my namespace.

pmooser02:03:42

The node repl looks like it may be super informative for me.

pmooser02:03:54

Ah, sadly, it complains that CLOSURE_IMPORT_SCRIPT is undefined. That's what I get for traipsing around in code I don't understand at all. 😞

mfikes02:03:59

I forgot about *loaded-libs* completely

pmooser02:03:16

Ah interesting, yah!

mfikes02:03:51

Keep going! I think it took me 2 weeks to finally get Ambly working, and I think I gave up 3 times during the process. 🙂

pmooser02:03:08

Do you know offhand what causes CLOSURE_IMPORT_SCRIPT to get defined ?

mfikes02:03:45

It has been so long, archeology of the code is all I have: https://github.com/mfikes/planck/blob/master/planck-c/engine.c#L242

pmooser02:03:42

Heh, well thank you for the references and the encouragement! I am sure this is the right direction.

pmooser02:03:06

That is sort of perfect actually, and I found a similar snippet.

mfikes02:03:43

There have been more humans to have walked on the moon than have created REPLs from cljs.js, so…

pmooser02:03:14

Well, it gets to ALMOST working immediately - like it's almost SO easy.

pmooser02:03:36

It actually works really well until I start requiring things.

fbielejec13:03:28

say I have a function that returns a native JS Promise (`#object[Promise [object Promise]]`). I want this function still returning a promise, but I want the value that this promise resolves to, to be cljs-friendly (js->clj, keywordized keys etc). Can this be done?

orestis13:03:52

@fbielejec Add a .then callback to the promise, converting all you want to do in there?

fbielejec13:03:29

as in return a new Promise from the callback? That should do it.

Olical14:03:58

Has anyone noticed in ClojureScript 1.10.x that cyclic dependencies aren't being detected?

Olical14:03:09

I've just had one and it causes my build to run forever within figwheel.

gklijs14:03:36

@olical This was also an issue in 1.9 with parallel build, maybe in 1.10 the default is to build in parallel

Olical14:03:04

Ah, good call. That was the issue, now to resolve the cycle!

joelsanchez14:03:33

fyi

(ns user
  (:require
   [ :as io]
   [clojure.tools.namespace.dependency :as namespace.dependency]
   [clojure.tools.namespace.find :as namespace.find]
   [clojure.tools.namespace.parse :as namespace.parse]))

(def root (.getCanonicalPath (io/file ".")))

(defn source-root-for [x]
  (io/file root x))

(defn throw-if-circular-dependencies!
  "Throws an exception if the project has a circular dependency, at the specified source path."
  []
  (let [project-graph (atom (namespace.dependency/graph))]
    (->>
     (namespace.find/find-ns-decls-in-dir (source-root-for "src") namespace.find/cljs)
     (map (fn [decl]
            {:name (namespace.parse/name-from-ns-decl decl)
             :deps (namespace.parse/deps-from-ns-decl decl)}))
     (map (fn [{:keys [name deps]}]
            (doseq [dep deps]
              (swap! project-graph namespace.dependency/depend name dep))))
     doall)
    true))

gastove15:03:32

Morning, excellent ClojureScripters; I’m trying to debug a weird, an I’m having trouble even building an intuition about where to look. Goes like this: when I build my CLJS with :optimizations :none, my CLJS bundle is trying to look for its extra js modules (i.e. base.js, cljs_deps.js) in a path that’s mutated depending on the route requested. So, if I request, say, /about, everything works fine; if I request /monkey/about, /monkey is now prepended to the asset path, and everything breaks.

gastove15:03:29

What are the odds that someone else has seen this, or built this particular footgun for themselves before?

gastove15:03:35

(My casual guess is that I have done something really clever, but I’m still deeply in the “what even” phase of trying to figure out what.)

benoit15:03:15

@byrongibby Does your asset-path starts with a /?

gastove15:03:05

@me1740 there isn’t any chance you meant that question for me, is there?

gastove15:03:41

No worries 🙂 I get the same behavior whether or not :asset-path starts with a /

gastove15:03:23

I’m serving a CLJS single-page app from a CLJ server using http-kit; I have no idea if it’s possible some other thing is prepending bits to incoming requests.

benoit15:03:31

The fact that it only works at the root of your paths makes me think it is an issue of relative URI in the asset-path. I would look at the paths of your <script> tags in the html when you visit /monkey/about. You will also have to recompile the ClojureScript once you change the asset-path.

gastove15:03:08

Hrmm, lemme monkey with that a little more

gastove15:03:08

Yeah that… does not seem to be changing anything.

gastove15:03:11

With script tag: <script src="/js/compiled/voltron.js" type="text/javascript"></script> I still see requests coming in for {:* "/monkey/js/compiled/out/cljs_deps.js"}

gastove15:03:18

This is perfectly dynamic, you understand. If I now try to hit /i/am/the/walrus, I see {:* "/i/am/the/walrus/js/compiled/out/cljs_deps.js"}

benoit15:03:53

It's clearly not generating the right JavaScript paths. I would look at the build options you use until you can see the right paths being injected in your html file.

gastove15:03:58

I am indeed doing that! I am just… at a loss… for what could possibly be going wrong.

gastove15:03:11

My compiler options look like so:

gastove15:03:45

:compiler {:main voltron.core
                  :asset-path "/js/compiled/out"
                  :output-to "resources/public/js/compiled/voltron.js"
                  :output-dir "resources/public/js/compiled/out"
                  :optimizations :none
                  :source-map true
                  :source-map-timestamp true
                  :preloads [devtools.preload]}}

gastove15:03:31

What I don’t understand is why the CLJS compiler would have dynamic asset paths at all.

benoit15:03:00

I encountered the same issue a few days ago. Putting an absolute path in :asset-path fixed it for me. I was calling the cljs.build.api/build function directly though. Is it possible that whatever compilation tool you're using is fiddling with this parameter? Unlikely but who knows... Otherwise I'm out of ideas, sorry.

gastove15:03:09

Gads, I hope not. I’m using the lein cljsbuild plugin. Can go see if I’m using a current version.

gastove16:03:49

Yeah, current enough.

gastove16:03:16

…..okay…. so a thing that makes this make even less sense is that my compiled JS is using absolute paths:

if(typeof goog == "undefined") document.write('<script src="/js/compiled/out/goog/base.js"></script>');
document.write('<script src="/js/compiled/out/goog/deps.js"></script>');
document.write('<script src="/js/compiled/out/cljs_deps.js"></script>');

gastove16:03:51

The problem was browser caching, that’s wonderful --

gastove16:03:07

Setting an absolute path for :asset-path was the right answer all along.

gastove16:03:53

“The real software development was the caches we cleared along the way.”

kurt-o-sys19:03:02

I'm trying to get how the cljs repl works exactly (and when/where things are done). So, would this be accurate?

+
       host        |           JVM
                   |
+---------------------------------------+
                   |
       read        |
        +          |
        |          |
        v          |
   expand tagged   |
   literals        |
        +          |
        |          |
        |          |
        +-----------------> macroexpand
                   |            +
                   |            |
                   |            v
                   |         analyze
                   |            +
                   |            |
                   |            v
                   |           emit
                   |            +
                   |            |
                   |            |
       eval <-------------------+
         |         |
         |         |
         v         |
       print       |
                   |
                   +

dnolen19:03:05

@kurt-o-sys everything is on JVM side, only eval is on the host

kurt-o-sys19:03:59

ok, thx! What still confuses me are the tagged literals: they are expanded - not sure if I should call it like that - by plain functions (data readers). So, that's also on the JVM. Are they the same as/similar to edn tagged elements? If I'm not mistaken, edn custom tag parsers must/can be implemented on the platform they are read?

joelv19:03:53

hello everyone, what's the easiest way to to add twitter bootstrap to a reagent project?

souenzzo20:03:58

just inport on HTML

justinlee20:03:43

@joelv I don’t think you need to do anything special. Just include the css and JS from a cdn using a script tag and start using it.

kurt-o-sys20:03:50

@dnolen the REPL is actually more like a 'read-compile-eval-print-loop'?

dnolen20:03:25

@kurt-o-sys basically everything is JVM

dnolen20:03:39

the only thing we use the client for is eval, and some bootstrapping stuff

dnolen20:03:46

(how to load files, etc.)

dnolen20:03:31

well it’s the same as Clojure from one perspective

dnolen20:03:38

eval is compile

dnolen20:03:58

but in our case we can’t eval in our process

dnolen20:03:20

it’s not always true

kurt-o-sys20:03:23

right - trying to warp muy wrap my head around it, I'm getting close 🙂. oh, eval=compile, but eval != macro-expansion?

dnolen20:03:29

it’s true in the case of Nashorn & Rhino for example

dnolen20:03:47

eval is probably anything after reading

dnolen20:03:58

doesn’t matter macroexpand, compilation etc.

dnolen20:03:50

the only big picture difference is that Clojure can load some byte code into the JVM, ClojureScript has to send source to a JS engine

kurt-o-sys20:03:50

so, all after reading is eval, so macroexpand is part of eval, right? And macroexpand is ran on the JVM (since that's clojure code, not clojurescript)?

dnolen20:03:47

well yes … but it’s ClojureScript too, the whole compiler can compile itself into JavaScript

kurt-o-sys20:03:15

ok, that makes sense (mostly). I just stick with eval is partly ran on the JVM (macro's) and partly on the host (code after macro-expand), not taking into account cljs-in-cljs.

dnolen20:03:53

your diagram is closer to the mark

dnolen20:03:04

the only thing that the host is going to run is stuff generated by emit

kurt-o-sys20:03:19

ok, thx! That'll do.

kurt-o-sys20:03:50

(and maybe I should rename 'eval' with 'execute' or so?)

dnolen20:03:43

I think in the REPLs it’s js-eval or something

dnolen20:03:31

and the higher level stuff is eval-cljs or evaluate-form

kurt-o-sys20:03:58

ok. simplified: eval = macro-expand + js-eval|eval-cljs|evaluate-form (or something)

dnolen20:03:25

eval/eval-cljs/evaluate-form = macroexpand + analyze + emit + js-eval

dnolen20:03:57

eval/eval-cljs/evaluate-form = JVM[macroexpand + analyze + emit] + JS[js-eval]

kurt-o-sys20:03:28

thx! that clarifies it all.

jrychter21:03:47

@mfikes @dnolen You were looking for feedback on ClojureScript 1.10.145 (and the previous version). I think it is worth mentioning in the release notes that taking a val of something that didn't come from a map no longer works and causes an error. I had that bug in my code and it manifested itself after upgrading ClojureScript from 1.9.946.

jrychter21:03:27

(my code was taking a val of a two-valued vector)

jrychter21:03:37

I'm so glad I have client-side exception logging implemented (along with source map decoding on the server).

mfikes21:03:38

Right. (val [1 2]) is incorrect. (It will fail in Clojure as well)

jrychter21:03:25

It undoubtedly is, but it seems that ClojureScript 1.9.946 tolerated it, while newer versions do not. I'm not disputing the bugness, I just think it's worth mentioning.

dnolen21:03:43

@jrychter it’s questionable since I didn’t know that worked

jrychter21:03:48

And BTW, ClojureScript 1.10.145 works perfectly well for me in a largish app.

dnolen21:03:52

there’s lot of weird edge cases that are best not talked about IMO

dnolen21:03:06

@jrychter that’s good news

jrychter21:03:44

That may be true — ultimately it's up to you to decide. I'm just reporting.

mfikes21:03:52

Yeah, there is other incorrect code that ClojureScript 1.9.946 accepted. Another example is https://dev.clojure.org/jira/browse/CLJS-2476

jrychter21:03:28

And I'm quite happy with the new ClojureScript version, mostly because it includes a newer Closure Compiler, which implements the "@noinline" annotation. Thanks to this, I was able to nicely macroize Font Awesome icon paths and include SVG only for those icons that I actually use, in an efficient manner. Rather Awesome, if you ask me.

msolli07:03:07

This is indeed awesome – could you be persuaded to share the technique?

mfikes21:03:51

@jrychter You mention macroize... I wonder if :closure-defines and DCE works in that case. (Mostly curious, no need to try; just thinking about the side-effecting macros making code no longer cache-friendly. This works in "project" code, but can cause an issue if it is put into a JAR.)

jrychter22:03:19

@mfikes Oh, there is only a single macro, which references vars defined with @noinline. So yes, only the vars that are actually referenced are included, and only once.