This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-08-13
Channels
- # beginners (28)
- # boot (3)
- # clara (9)
- # cljs-dev (127)
- # clojure (82)
- # clojure-belgium (3)
- # clojure-italy (7)
- # clojure-russia (2)
- # clojure-spec (4)
- # clojure-uk (2)
- # clojurescript (351)
- # data-science (3)
- # datascript (1)
- # datomic (24)
- # fulcro (15)
- # jobs (3)
- # juxt (16)
- # off-topic (2)
- # onyx (18)
- # parinfer (1)
- # pedestal (3)
- # perun (6)
- # re-frame (14)
- # spacemacs (20)
So, it seems that the callback for cljs.loader/load
does not get called unless you remember to require cljs.loader
in the namespace that is getting loaded, even though that namespace doesn’t use it. Is this expected, and if so, I think this should be added to the docs.
expected, and I think it’s in the guide?
perhaps it’s not
@tony.kay feel free to PR the website https://github.com/clojure/clojurescript-site
@anmonteiro Do you not end up with the same singleton or something? It was very surprising to me, and I’m not exactly a beginner.
I don’t understand the question
can you clarify?
do you mean the moduleManager thing?
I don’t understand why it is necessary to require cljs.loader in a namespace that does not use it. Obviously it causes a dep graph to complete (though it would seem to me that the module config should be able to supply that needed fact)
if a namespace should be loaded as a module it needs to require the loader
otherwise you can not require it
Bad developer experience 🙂 Why can’t the compiler just figure that out from the module configs?
TBH I don’t recall the exact reason
but I remember David mentioning there’s one
I think in some advanced cases you may want to manage the loading yourself
and injecting the loader would prevent that
^ but I’m not sure about this
Well, I’ve spent several hours banging my head on module loading problems. I think I’ve finally got it, but subtle things like that are the kind of thing that lead people to try Clojurescript and just give up because the experience sucks.
The code looks simple enough. Nice and trivial. You read the docs and think: yeah! I want that. Then spend a day hitting problems.
glad you figured it out
there’s definitely space for improvement with regards to docs and developer experience
@tony.kay I would suggest starting a discussion about this on the website repo
that too
@anmonteiro Is the compiler supposed to walk the dep graph for a module, or are we always supposed to list all ns explicitly in the config?
the former
Yeah, I had to do the latter because of some dynamic resolution that the compiler couldn’t see
i have the same exact issue as here https://dev.clojure.org/jira/browse/CLJS-2290?focusedCommentId=46576&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-46576
@ashnur if in your case target is not :nodejs
why are you trying to require fs
or path
?
@anmonteiro it's not me who is trying, but an npm module.
so that module may not be suitable to work in a browser
@anmonteiro that's why i was asking how to shim these. like with browserify or something
I don’t know, maybe you need to bundle it with Webpack or browserify
or require only certain files that don’t need fs
?
i've been using browserify for many many years now so i am not used to check if a module is written for node or browser, it just works:tm:
i am assuming - perhaps incorrectly - that pre bundling some js files and loading them will not give me the same optimizations that i might get now using only :npm-deps
correct
thanks for the help @anmonteiro!
Hi folks! I have the above code snippet which I use to log in via Facebook. As you can see this is async javascript code ported over to clojurescript. What would be the changes that would make the code more idiomatic?
I am looking into core.async
channels, however I don’t quite understand how to use them here.
Honestly the snippet looks fine to me - hard to improve upon
Don't introduce core.async just because you can
IMO it should be used only when other alternatives have been shown to have real problems in your code, problems which require core.async's primitives, like channels
Thanks @pesterhazy!
Is this a bug? Wrong number of args (-1) passed to: macros/session*/fn--57416
And should the error not surface when the parameters of the function are (`[& args]`)?
oke am i doing something wrong?
ajax.cljs post
to server and when i use :body
it's #object[java.io.ByteArrayInputStream 0x5aec0e6e java.io.ByteArrayInputStream@5aec0e6e]
is that normal ?
what do i do now?
@alex-dixon that means that you somehow got hand of a macro without the metadata indicating it's a macro, so that it got called like a function
this can happen when you use the var of a macro
what happens is that when a function has :macro true
in it's metadata map the clojure compiler adds two args to the beginning of the arg list, &env
and &form
representing local bindings and the raw form of the macro invocation, then it captures the result of calling the macro, then compiles the output of the macro
Well. Apparently I just realized I don’t know how to use alter-meta!. And still don’t
so, if you call a macro that doesn't have that metadata on it, you end up with a "negative argument count"
Calling it from a cljs repl on an interned var free of macros doesn’t seem to be working how I expected
because a macro with two args is really called with 0 args, etc.
oh wow even with the deref I am getting the correct 0, hmm...
I’ve passed the amount of time I told myself I would spend on this but…
(def ^{:cool true} foo "hey")
(var foo)
(alter-meta! (var foo) merge {:cool "yes"})
(println "Foo meta" (meta (var foo)))
=> Foo meta {:cool true, :ns precept.app-ns, :name foo, :file /Users/alexdixon/precept/test/macros/cljs/precept/app_ns.cljs, :end-column 23, :column 1, :line 61, :end-line 61, :arglists (), :doc nil, :test nil}
Would expect :cool to be “yes”…what am I missing?
@alex-dixon that code would work in jvm clojure...
(just tested it)
Yeah…
Just updated to 854 which should be the latest and getting the same behavior
well I believe merge takes the value of the left argument in the event of a keyword collision
like I said, that code works correctly in clj - merge goes with rightmost
@gcast the easy way to remember is that for many vararg clojure functions, (f a b c) is the same as (f (f a b) c) - thus it needs to prefer the rightmost arg (see for example str, *, -, /, or, and, conj)
right - even if not written with reduce (which most of them are), they keep that semantic
@tony.kay certainly nothing is final wrt. the behavior of cljs.loader
, but my assumption was that people would commonly use the loader via routing, in that case you never know which thing will load which thing - so you would include the loader in every entry point anyway
@tony.kay also if that was a significant time sink (I’m also curious what else you hit), then we should talk about that more.
it would be pretty simple to warn on attempting to load a module that doesn’t require cljs.loader
there an equivalent to jquery’s document ready? I have some JS loaded with an async tag and I can’t depend on the script loading before the DOM so goog events DOMCONTENTLOADED is not an option
Is anyone here in the habit of clojure-spec-ing their app states? How thorough do you tend to go with the specs? Every bit of the structure or just the leafs?
Anyone here using mach? https://github.com/juxt/mach
I have this weird problem. Reagent is rendering"Hello World" -- yet that string appears no where in my html / clj / cljs files.
(set! (.-onload js/window)
(fn [& rst]
(. js/console log "onload window called")
(init)))
is this the correct way to get (init) to be called on startup? if not, what is the corrcet way (it's not working for me)@dnolen I would think you’d only include cljs.loader
in those things that actually call it. Routing is exactly what I was building, and the “leaves” never need to load anything else. Thus, my callback not getting called when those were loaded just left me scratching my head and thinking I’d made some “silly” typo or mistake. The other thing I hit was related to using it in devcards or perhaps because I am building a reusable routing component. I am not sure exactly why I had to add so much to :entries
. It could be that because I’m triggering the routing through an Om mutation that it could not figure out the dependency graph info? The namespace for routing was required, but the routing namespace wasn’t known when it tried to look up “loader”. My suspicion was that the compiler couldn’t analyze the dependency graph from the requires, but I didn’t understand how that works very well from the documentation. I expected to be able to add my “entry points” for the modules to the config and have the rest derived, but I had to add a lot more to :entries
than I expected, and I had to essentially tinker until I figured that out. I still would have expected it to work. Perhaps that is a bug?
The cljsbuild config that worked is: https://github.com/fulcrologic/fulcro/blob/develop/src/main/fulcro/client/routing.cljc#L297
:main
in my case is the main route that is dynamically loaded. But I had to explicitly add the routing namespace to the :entries
(which is where the call to load comes from…through an Om mutation). I was expecting that to get picked up through requires (the namespace that triggers the mutation requires the routing namespace).
I’m gathering now that perhaps the analysis works by looking for just requires of cljs.loader
? The documentation led me to believe that loader
was just a utility component to triggering/tracking loads. It was not clear to me that it was more (e.g. something used by the analyzer?).
anyways the point is fundamentally you must require cljs.loader
if you going to be loaded by cljs.loader
because you must call set-loaded!
When I’ve written module code before, you had to add something to the namespace to trigger the event that signaled completion.
wanrings end up in the console with lots of other messages .Certainly helpful. Clear comment in the docs that is needed are good too
The thing is code flow: I, as a developer, would understand an explicit call to set-loaded!
as a requirement for the callback to trigger. It is a traceable code path. A require
is for library loading. Overloading it to augment your code with a hidden action is not remotely expected.
which is to separate your personal frustration from something that should work for people that aren’t going to read docs
I’m disagreeing because had your guide set set-loaded!
at the bottom of a source file I would have not hit an issue
I’m wanting something that works when you read the docs. I don’t give a rats ass if people cause themselves problems by not reading anything. I read your guide. One simple comment about set-loaded would have kept me from having any problems. And I’ve written module loading before with Closure.
That will probably do it. I understood there was “magic” going on somewhere. I just didn’t realize it was in the require.
@tony.kay but thanks for trying it and wading through it, the feedback is in fact very welcome
Fulcro now has a completely dynamic UI routing system with module loading integration…and it is about to have automatic i18n locale loading.
@dnolen So am I right in saying that, in order to call load
a namespace must be explicitly listed in a module in the compiler config’s :entries
( it cannot just be derived by the require graph)?
If I don’t put namespace A into an explicit module in compiler config, then loaded
is unset when it calls the load for :m
My understanding was that the compiler would derive all the stuff needed for a module through the require graph
Concrete: namespace “router” is a namespace that loads various modules. The module name is given to it by parameter. Thus, it might load any number of modules. When you call the load
macro, it tries to derive the module that you’re loading from. Right so far?
one of the namespaces is a reusable library component whose task is to load things (e.g. routing)
another library element loads locales (i18n). Separate concern. Separate library even.
ok but then doesn’t it sound like appending set-loaded!
for you when you require cljs.loader
a problem? It does to me
I assumed set-loaded was idempotent…once the thing is loaded it doesn’t hurt for it to be called
it is idempotent … but it might not be true the module is actually loaded (if there are multiple entries)
I was assuming it was in the derivation of what module things went with in the dependency graph.
without the the magic set-loaded!
thing, cljs.loader
becomes a fully generic useful programmable thing
so, I have a question: what is required in :entries
now? Just the entry point of a module, or everything you want to try to force to be in that module.
Could also add an additional compiler config entry to indicate exactly which namespace is the rep for the module
So, one more possible problem: pinning to a module. Is it true you must pin something to a module if it is going to call load? I.e. that ns cannot end up in cljs_base?
ok. I was seeing an issue where I was having to pin my router to a module, even though it was acceptable to be in base
oh, I see. So the router is going to have to be in an explicit module in the compiler config
That was the root of my confusion. I didn’t see how you could implement the latter well without it bleeding into the former…so I was assuming it was part of it.
that was part of the reason I didn’t dig into the source…I assumed it was a mountain of madness of dep resolution 🙂
IIRC the magic wasn't there to start with, right? It was only added after some discussion
yeah, shadow-cljs does some stuff here, but perhaps it can work around these issues w/ injection
nvm. still thinking about the magic, and I agree it is better just to have explicit calls to set-loaded!
I added a comment in CLJS-2321
not sure about the cljs_base issues, but it might be as easy as reverting CLJS-2157
@anmonteiro yeah that’s what I was looking at - thanks for adding the comment
@tony.kay the magic that remains which is probably what you’re getting at is that cljs.loader
will remain a magic ns
https://github.com/clojure/clojurescript/blob/master/src/main/cljs/cljs/loader.clj#L19
And a library author will have to tell ppl to explicitly place certain namespaces into a module (those that call load)
I’ve left the module loader
assertion alone, seems to me that should be fine - but maybe you’ll demonstrate otherwise
I’d like to cut a release tomorrow, gotta head out for now but I will check back in later
@dnolen OK, I tested it out. The explicit calls to set-loaded!
work fine, as I’d expect. When I use figwheel, it does throw an exception, but even then it does work. I suspect figwheel is going to need a little tweak. The exception, for general interest was:
ioc_helpers.cljs?rel=1502666299392:42 Uncaught TypeError: goog.net.jsloader.load is not a function
4 at figwheel$client$file_reloading$reload_file_in_html_env (file_reloading.cljs?rel=1502666284269:208)
5 at figwheel$client$file_reloading$reload_file (file_reloading.cljs?rel=1502666284269:250)
6 at figwheel$client$file_reloading$blocking_load (file_reloading.cljs?rel=1502666284269:269)
7 at file_reloading.cljs?rel=1502666284269:279
8 at file_reloading.cljs?rel=1502666284269:277
9 at figwheel$client$file_reloading$state_machine__54034__auto____1 (file_reloading.cljs?rel=1502666284269:277)
10 at figwheel$client$file_reloading$state_machine__54034__auto__ (file_reloading.cljs?rel=1502666284269:277)
11 at cljs$core$async$impl$ioc_helpers$run_state_machine (ioc_helpers.cljs?rel=1502666299392:35)
12 at cljs$core$async$impl$ioc_helpers$run_state_machine_wrapped (ioc_helpers.cljs?rel=1502666299392:39)
13 at ioc_helpers.cljs?rel=1502666299392:48
However, I was hoping a specific library-centric scenario would end up working, but it does not. It is possible that I misunderstood you.
- Library ns L issues loads. It is required by all namespaces in this example (and it does end up in cljs_base
).
- Entry point ns E is in :entry-point module E :modules {:entry-point { :entries #{E} ...
- Module M (to be loaded by L), is in modules {:m {:entries #{M} …
If I force L
into the entry point module (`:entries #{E L}`), then it works. As I said, I may have misunderstood you. If that is how it is supposed to work, then it does. I thought you had a solution for stuff that issued loads from library code in cljs_base (like a top-level module for cljs_base that was always considered preloaded).
The specific error I get when L
is not specifically pinned is: `Assert failed: Module does not exist
(contains? module-infos module-name)`. This is what I was talking about when I said the loader
would not be defined, since the namespace L
was not pinned.^ this error message also looks a little strange
because the module name looks null
in Module does not exist
2 spaces where a name should be
or :cljs_base
no?
https://github.com/clojure/clojurescript/blob/master/src/main/cljs/cljs/loader.clj#L19
that tries to look up which module the ns is in, but L isn’t pinned, so it isn’t in one as far as the data structure is concerned
that’s why I was referring to there being the need for some kind of “default” module that we know is loaded
oh yeah that totally makes sense
I don’t know if that’s supposed to work, but makes sense to me that it should
however, it does seem a little odd to me that library code would dictate split points
the library isn’t dictating anything…it’s just ending up in base because it is used by things
but the library is calling cljs.loader/load!
, no?
right. that’s what I find might not be idiomatic, if there’s a word for it
shouldn’t it be up to application code to take care of loading?
It depends on who knows that is in cljs_base. If only Google Closure knows whats in base, then there’s nothing to be done. But if cljs builds that, then it does know what is in the base module.
and that could just be placed in the deps thing that is being generated for cljs.loader
I guess there’s some distinction here of splitting vs loading that David was speaking of earlier that I’m not really getting yet
I think CLJS knows what’s in base
loading is standalone. It just loads things that are defined. It does, however, tried to load things in dependency order.
right. In case it is supposed to work, there might be a bug here wrt cljs-base
there is the possibility that I’m msising something. What if L
was placed into a module explicitly. In that case, it will work because that is the design (and you better do the proper calls to set-loaded!
. But the assumption is that a caller of load
should be in something that was already properly loaded…e.g. a module with an invocation of set-loaded!
. But your 3rd party is the app writer using cljs AND a library L. For them, L
is just going to end up in cljs_base. It would be nice if they can just use it, and an implicit set-loaded!
has already happened for the cljs_base “preload”