This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2020-06-01
Channels
- # announcements (2)
- # babashka (10)
- # beginners (133)
- # calva (28)
- # cestmeetup (1)
- # chlorine-clover (31)
- # cider (21)
- # clj-kondo (29)
- # cljs-dev (252)
- # clojure (60)
- # clojure-europe (24)
- # clojure-nl (3)
- # clojure-spec (13)
- # clojure-uk (17)
- # clojurescript (47)
- # conjure (20)
- # datascript (2)
- # datomic (4)
- # figwheel-main (4)
- # fulcro (71)
- # helix (16)
- # jobs (1)
- # meander (56)
- # mount (1)
- # off-topic (15)
- # pathom (25)
- # re-frame (17)
- # reagent (5)
- # remote-jobs (1)
- # shadow-cljs (92)
- # sql (10)
- # tools-deps (71)
- # xtdb (14)
Would it make sense for tools.deps to be extended to have a CommonJS Package Registry resolver?
It would be a little tricky, since it would need to support package.json parsing to manage transitive deps as it does now for pom.xml with Maven registries
But if it did, one could depend on NPM deps freely. And one could have a ClojureScript lib with NPM dependencies. And tools.deps would be able to do a full dependency closure on all of it and resolve conflicts, pull down the defined versions, etc.
Npm works differently to tdeps expectations because of hierarchical dependencies. Also, clojurescript doesn't search the classpath for node dependencies.
And ya, I would assume the resolver would make symlinks into a local node_modules folder, or to be honest, it be nice if the compiler did look them up in the classpath, and when :bundle target is chosen it would go and create the node_modules symlinks needed for the js bundler to run over afterwards.
I don't see much issue here. NPM seems pretty standard, it's got packages with versions, which can depend on other packages and optionally their versions if provided a package.lock
At any rate, the compiler is just trying to re-implemented what looks to me like a worse version of tools.deps bit for cljs specifically. So I feel that effort would make sense to be consolidated into tools.deps
https://github.com/vouch-opensource/krell/blob/master/src/deps.cljs I can't find docs, but krell uses this feature
OK so I the behavior I see when using the :bundle
target is that cljsjs
libraries are not connected to the required namespace symbol. When using reagent
for instance, in the expression (:require [react])
the react
symbol does not get bound to the cljsjs/react library when the react npm package has not been installed to node_modules.
what I see is an npm_deps.js
with no entries, and in the compiled code I see reagent.impl.component.node$module$react = require('react');
Folks probably need to understand the ins and outs of all this more as we move forward
So install-deps is inly intended to work for libraries that declare npm-deps by default
Huh, what's the problem?
the issue is that Reagent I believe both declared a dep on Maven dep and a NPM dep for the same library
deps.cljs is only used if install-deps is enabled?
@juhoteperi we pinged you to find out something we answered already
but I don't see how it wouldn't pick up cljsjs/react
, it appears we do use node_modules
as the source of truth
B) node.js require
emitted even though A) means it cannot be indexed under :node-module-index
FWIW in shadow-cljs I completely dropped support for foreign-libs because I didn't want to deal with "mixing" dependencies. one library depending on cljsjs while the other going to npm directly. you might want to do the same for :bundle
builds?
in anycase what you're observing seems like an impossible situation - from looking over the code
I just wrote a stub library that maps the most common cljsjs package pack to a regular require and exposing the global
making :bundle
work w/ everything that came before isn't that hard and is in the spirit of not breaking stuff that used to work
And here is another question: is this code broken or are we supporting it? https://github.com/JulianBirch/cljs-ajax/blob/master/src/ajax/xml_http_request.cljs#L29
but in the end that just means another thing for people to hook onto that they probably shouldn't
yeah I’m going to advise they use goog.global.require
to not trigger the bundler, and use a different way to detect nodejs
its not a problem since I don't extract js/require
calls in the code for normal builds
the problem only appears if you try to extract js/require
calls when trying to feed them to the other bundler
oh right .. well I don't pass anything to a bundler so the "rogue" require
call does nothing
its only for react-native builds that I actually extract js/require
calls from the code since that will go through metro
and this case is particularly interesting because I don’t see how to make this code work at all now, if its getting passed to a bundler
well its not a problem in shadow-cljs so doesn't require fixing. no clue about :bundle
.
but conditional requires are not fun to work with at all so I'd like there to be a better solution. just not sure how.
I don't have any interesting ideas that I'd be willing to implement or see implemented at the moment
problem is that it likely won't understand the cljs.core/*target*
conditional. I have only seen this work for actual const
locals and process.env.NODE_ENV
you can always ignore the xmlhttprequest
require via webpack config when building for the browser
yeah I have something similar in shadow-cljs https://shadow-cljs.github.io/docs/UsersGuide.html#js-resolve .. for some npm packages there is just no other way without manual intervention
That means that libraries couldn't change their underlying library without breakage. But that's js too
you could legitimately sprinkle your code with js/require
knowing you will use a bundler
btw, above I wasn't shooting down ideas to fix it - just stating I don't have any good ones
Can anyone here shed some light on an aspect of the compiler analysis state cache? In particular, in the following JS console inspect snippet,
• why isn't the macros
field at the "top" level (same level as extrerns
?
• how can you have multiple null
keys in the map and what does that entail??
• what does edit
mean?
6: {ns: null, name: "cljs.core.async", str: "cljs.core.async", _hash: -159169011, _meta: null, …}
7:
meta: null
cnt: 16
root:
edit: {}
bitmap: 221921953
arr: Array(24)
0: null
1: {edit: {…}, bitmap: 34603008, arr: Array(8), cljs$lang$protocol_mask$partition1$: 131072, cljs$lang$protocol_mask$partition0$: 0}
2: {ns: null, name: "externs", fqn: "externs", _hash: 221720677, cljs$lang$protocol_mask$partition0$: 2153775105, …}
3: {meta: null, cnt: 3, arr: Array(6), __hash: null, cljs$lang$protocol_mask$partition0$: 16647951, …}
4: null
5:
edit: {}
bitmap: 3211264
arr: Array(8)
0: {ns: null, name: "use-macros", fqn: "use-macros", _hash: -905638393, cljs$lang$protocol_mask$partition0$: 2153775105, …}
1: {meta: null, cnt: 2, arr: Array(4), __hash: null, cljs$lang$protocol_mask$partition0$: 16647951, …}
2: {ns: null, name: "excludes", fqn: "excludes", _hash: -1791725945, cljs$lang$protocol_mask$partition0$: 2153775105, …}
3: {meta: null, hash_map: {…}, __hash: null, cljs$lang$protocol_mask$partition0$: 15077647, cljs$lang$protocol_mask$partition1$: 139268}
4: {ns: null, name: "macros", fqn: "macros", _hash: 811339431, cljs$lang$protocol_mask$partition0$: 2153775105, …}
5:
meta: null
cnt: 3
arr: Array(6)
0: {ns: null, name: "go", str: "go", _hash: 1493584872, _meta: null, …}
1: {meta: null, cnt: 8, arr: Array(16), __hash: null, cljs$lang$protocol_mask$partition0$: 16647951, …}
2: {ns: null, name: "alt!", str: "alt!", _hash: 1759993452, _meta: null, …}
3: {meta: null, cnt: 8, arr: Array(16), __hash: null, cljs$lang$protocol_mask$partition0$: 16647951, …}
4: {ns: null, name: "go-loop", str: "go-loop", _hash: 692273294, _meta: null, …}
5: {meta: null, cnt: 8, arr: Array(16), __hash: null, cljs$lang$protocol_mask$partition0$: 16647951, …}
The context for this is getting the macros to be visible to the compilerAn odd (to me) thing is if you look at this in cljs-repl
there are no null keys and :macros
is at the top level of the map
you are looking at the internal structure of the map implementation. thats not very interesting. use cljs-devtools or just prn the result to get a useful representation
As I mentioned, the 'useful' representation has the :macros
field at the top level of the map. Here's a snippet:
((-> state deref :cljs.analyzer/namespaces) 'cljs.core.async)
{:rename-macros {},
:renames {},
:externs {Error {}, Array {}, Object {}},
:use-macros {go cljs.core.async, go-loop cljs.core.async},
:excludes
#{reduce take map transduce into partition merge partition-by},
:macros
{go
{:arglists ([& body]),
:doc
"Asynchronously executes the body, returning immediately to the\n calling thread. Additionally, any visible calls to <!, >! and alt!/alts!\n channel operations within the body will block (if necessary) by\n 'parking' the calling thread rather than tying up an OS thread (or\n the only JS thread when in ClojureScript). Upon completion of the\n operation, the body will be resumed.\n\n Returns a channel which will receive the result of the body when\n completed",
:line 4,
:column 1,
:file "cljs/core/async.clj",
:name cljs.core.async/go,
:ns cljs.core.async,
:macro true},
alt!
{:arglists ([& clauses]),
:doc
"Makes a single choice between one of several channel operations,\n as if by alts!, returning the value of the result expr corresponding\n to the operation completed. Must be called inside a (go ...) block.\n\n Each clause takes the form of:\n\n channel-op[s] result-expr\n\n where channel-ops is one of:\n\n take-port - a single port to take\n [take-port | [put-port put-val] ...] - a vector of ports as per alts!\n :default | :priority - an option for alts!\n\n and result-expr is either a list beginning with a vector, whereupon that\n vector will be treated as a binding for the [val port] return of the\n operation, else any other expression.\n\n (alt!\n [c t] ([val ch] (foo ch val))\n x ([v] v)\n [[out val]] :wrote\n :default 42)\n\n Each option may appear at most once. The choice and parking\n characteristics are those of alts!.",
:line 63,
:column 1,
:file "cljs/core/async.clj",
:name cljs.core.async/alt!,
:ns cljs.core.async,
:macro true},
go-loop
{:arglists ([bindings & body]),
:doc "Like (go (loop ...))",
:line 95,
:column 1,
:file "cljs/core/async.clj",
:name cljs.core.async/go-loop,
:ns cljs.core.async,
:macro true}},
:name cljs.core.async,
But the compiler claims, for example, that the go
macro does not exist in the cljs.core.async
namespaceI am using Andare which is supposed to be self-host compatible. I did discuss a bit with mfikes, but it seemed the issue was more related to the compiler
I find it strange that the internal structure differs in the simple respect that the array map impl has (multiple?) null keys
don't look at the JS representations of the CLJS data structures. they are just going to confuse you. :P
they are null in clojure too .. you are just not looking at the internal java representation ...
eg. {ns: null, name: "cljs.core.async", str: "cljs.core.async", _hash: -159169011, _meta: null, …}
... this is the cljs.core.async
symbol but its really hard to tell that from the output
Yeah, understand that - but it does not have null keys
watch some talks or read some blog posts about how the CLJ(S) data structures work. it'll make more sense then.
Putting that aside then (representation aspects), it would then seem that the compiler state does have the macros as in the cljs.core.async name space. But any attempt to reference them gives an analyzer error that the do not exist
for self hosted the macros will live in cljs.core.async$macros
but I'm honestly not entirely sure how self-hosted macros work
Yeah, that stuff is there as well - and the macros are listed in there too
I don't know what you actual question is though. the JS "mess" you posted doesn't really tell you anything about the data you actually have. just pprint it or something to get a useful view of the data
??? I posted the actual 'useful view' of the compiler state above
No, that is the real live data
@jsa-aerial it sounds like you’re trying to debug some issue with andare. Like @thheller is saying, the three questions you posted above about the JS is a red herring, it probably has nothing to do with your issue. can you explain the issue you’re having with andare?
As mentioned at 4:51 msg, despite the macros being in the compiler state for cljs.core.async, the analyzer claims they do not exist
Maybe this is just a fool's errand and unless you know some deep (and apparently opaque) magic, it just isn't possible to get this to work
In a namespace if you issue (require '[cljs.core.async :refer-macros [go]])
for example, it just errors with illegal refer that macro cljs.core.aync/go
does not exist.
what about (require '[cljs.core.async :refer [go]])
or (require-macros '[cljs.core.async :refer [go]])
?
also I'm assuming you are talking about a REPL right? otherwise requires should be in the ns
You can (require-macros '[cljs.core.async.macros :refer [go]])
w/o analyzer error, but any attempt to use it (for example with <!) just errors with <!
not in a go
block.
That's the separate namespace you mentioned - cljs.core.async require-macros
that
no I didn't. I said cljs.core.async$macros
. which is different. thats the "secondary" namespace self-hosted will be using for macros
cljs.core.async.macros
is another actual ns, which will also have the secondary cljs.core.async.macros$macros
> also I'm assuming you are talking about a REPL right? otherwise requires should be in the ns either repl or ns - either way behaves the same
Well, there is no cljs.core.async$macros
in any of the code
OK, that seems to be how Andare is written. It uses this cljs.core.async.macros
namespace
It's definitely not in the analyzer state. Does that get generated or is it how the code is expected to be written?
It does not work
It just says it does not exist
Well, I guess this just goes back to the 'deep / opaque' magic bit. Andare does not have any such namespace (that I can find) but the claim is that it does work
Oh, so it is generated
it doesn't exist on disk yes ... it is the result of compiling cljs/core/async.clj
as a macro namespace
Well, there you are - maybe I just need to grab and cache that at compile time
Let me try that and see what happens
Wouldn't that kind of conflict be something that would be solved if we reconcile it all in tools.deps? Tools.deps could find conflicts between a cljsjs and a node_modules or a git deps, etc. And just resolve which one to pull down
> maybe I just need to grab and cache that at compile time
Nope that doesn't work either. In fact the compiler state at build time claims there is no cljs.core.async$macros
namespace. I think I am going to give up and approach originating problem in a (less general, less simple, and less clean) fashion - but which should work, as I will be using core.async at the app (non self hosted) level (which definitely does work). 😒 this was one of the more total wastes of time I've had the misery to have engaged in.