This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2020-04-25
Channels
- # announcements (2)
- # architecture (7)
- # aws (1)
- # babashka (105)
- # beginners (88)
- # braveandtrue (2)
- # calva (9)
- # cider (18)
- # cljs-dev (265)
- # cljsrn (22)
- # clojure (138)
- # clojure-argentina (3)
- # clojure-austin (1)
- # clojure-france (14)
- # clojure-italy (6)
- # clojure-uk (8)
- # clojurescript (283)
- # community-development (4)
- # conjure (11)
- # datomic (43)
- # docker (12)
- # duct (16)
- # emacs (1)
- # figwheel (1)
- # figwheel-main (27)
- # fulcro (10)
- # graalvm (6)
- # kaocha (4)
- # malli (9)
- # off-topic (13)
- # rdf (2)
- # reagent (12)
- # shadow-cljs (86)
- # spacemacs (1)
- # vrac (1)
So, are you saying that one would use :require
instead of :import
for the goog libs?
Isn't it the case that you'd usually only ever see an inner class $
situation in CLJ when using the :import
context? If we want to ride on existing idioms, would it make sense to keep this behavior to the :import
context?
I love the $
idea!
As an OG Clojurist, I vote for the $
syntax. Strongly dislike adding :
within symbols, since some things like to store keywords concatenated as a string (without a space).
Two things to consider:
1. Would there ever be ambiguity with choosing $
? Could JS start using this for other thing? What about Clojure?
2. Is it easy to auto-complete? For example, $ can act as a marker, saying, ok now auto-complete given what's before what can come after
Also, how does :refer
work, if the referred thing is a data property rather than a fn? Does it just become the value of the property?
And my last question would be: What are the possible ways in which a Clojure user's expectations of the $
symbol for inner classes be violated when trying to use this feature in CLJS land? Any?
Man, JS modules are a mess 😛 I don't think I even really understand how things are imported in JS, so I can't contribute too much. But I always thought it was really confusing that I can't just :require x.y.x :as foo for everything. So if this gives me that, I'd say +1. And the whole thing with import I still don't really understand what needs imported and why.
Also, I would find it weird that I need to use ns
for requiring/importing. I would always expect that I can choose to use require
and import
on their own, outside of ns
as well.
So I think whatever CLJS does with ns, it should be compatible with require
and import
, or it needs to add new functions, if there was a :default
now you need a matching default
function, etc.
@didibus I think the default would go as a tag in the require or import vector, not as a top level command like require or import, so wouldn't have an associated fn. But yeah, the default stuff is all another language to me too.
I personally like to try and be as consistent with Clojure. But I also think there shouldn't be anything that is not possible to import due to this constraint. And maybe for me, the latter is more important. Like there's nothing more frustrating but to hit a wall and realize there's just no way to require what you need. Which I'm concerned a little bit in case $
can clash. Would there be a way to say escape the one that is for require vs the one that is in the name?
dynamic require is just not something that’s easily supported and my guess is probably won’t be in the near future
I guess the string version could allow you to escape the $
that happened to be in js name? I never liked the string syntax though.
my understanding is that :import
would still be there for some google closure interop.
the proposal is:
:require
would be used to access CLJS namespaces, external JS packages, and globals
importing a JS property as a namespace would be supported using the new feature, at this time the $
in the middle would delimit the package/global and the property
I think it would be better to use :import
to add some new semantic, since it’s used so infrequently, but the semantics we’re talking about (using an object property as a namespace) doesn’t match the semantics of Clojure’s :import
at all
Does the inner class thing and the nested object thing really differ so much? And how so?
import
in Clojure brings in a Java class as a value
the nested object require we’re talking about brings in a JS object as a namespace
Hum, Clojure's import is a bit crappy though, it doesn't follow require syntax, so everyone get it mixed up all the time. And it has no features, can't alias, refer is implicit, etc. But hey, I guess in Clojure the ship as sailed. That said, the syntax is the same as for namespaces outside of it. If you imported a.b Foo
you can do Foo/
for everything else. And I think one thing confusing in CLJS, is that there's no logic. In Clojure you can say.. require
for Clojure stuff, import
for java stuff. It be nice if that was true in cljs as well
I don’t know that it would disallow, but it does allow (console/log ,,,)
which is typically reserved for namespaces
:import
alone also doesn’t really solve the problem we started with:
(ns
(:import
["react" default]
["@corp/my-lib" default]))
you get two default
bindings, need to introduce some way to alias them, you might even want to add :refer
….Can someone explain to me what we mean here between namespace thing and object thing? Like what's wrong with: (import [window console])
and then I can do console/log
?
To be honest... If I go back to the first time I saw the $
, I think I wished that it could have been a .
, just to minimize the noise. But if there's any utility keep it, and it's not an artifact of java-isms, then I'd love to see $
smooth out the interop between CLJS and JS.
In Java you don't actually use $ for inner class, that's only used in ASM, which Clojure compiler uses. So you can say it is more of a Clojure thing then a Java thing in my opinion
I guess a JVM thing, but Clojure could have chosen whatever symbol it wants, Java for example uses .
: outer.inner
.
Well, there might have been a decision at the time, where maybe using .
caused some ambiguity
So in fact, lots of Java folks get tripped up in Clojure, and ask how to access an inner class, because they try .
and it doesn't work 😛
Ya, I think making it $ is equivalent to Clojure's /. So now given any prefix a.b.c$d you know to look up a.b.c for d. Otherwise you'd need some more elaborate logic I think. Like can you find a.b.c.d in the map? No, ok try a.b.c ? No, ok try a.b, ok found it, ok now from it look for c.d, etc.
Anyways, so if I understand the issue, this is about how do you alias and refer JS dependencies?
Cause without those features, seems import
could work for everything no?
Well, after thinking about it some more, the :import
syntax is generally disliked, by everybody, in it not having the :as
and :refer
and friends. And if we're putting this stuff there just to be like CLJ, then would you also disallow :refer
? Seems draconian...
I guess I'm just trying to unravel the "issue". In Clojure, you want to use a function from Java, you always need to prefix the classname or even fully qualify it. Like I said before, this seems a bit underwhelming in features, but it also motivates people to wrap Java stuff in Clojure.
There's a bunch of weird import/export scenarios in JS that this feature would nicely address - one of which was the default issue
I think there are two things to consider for the proposal of using :import
for JS libs:
• import
in Clojure land typically imports a class that's used as a value, not a namespace, so it would be a slight semantic diff
• you would want things like :as
, :refer
, :rename
, etc. to avoid collisions which would be additional syntax inside the :import
section
dnolen has been pretty explicit that he isn't interested in extending the ns
form and adding more differences between Clojure and CLJS, but maybe these differences are more palatable seeing as import
has very little direct relation between the two platforms
I also personally like how it addresses "the differences between clojure and clojurescript" issue... if only a little
Right, but all of these "weird import/export" seems out of place for Clojure. It seems JS is trying to bring so much "user convenience". Like I'm so lazy, I don't even want to choose what to import, I want the export to define defaults that magically appear in my import and might change at any upgrade because the export controls it
@didibus but we need some way to map the lib in... and js/ or "[email protected]." is a wild west
@lilactown what do you mean by "`import` in Clojure land typically imports a class that's used as a value, not a namespace, so it would be a slight semantic diff"
So maybe this is where I'm not familiar with the complexities. But why can't you just: (import whatever)
and then do (whatever/some-fn)
and (.- some-field whatever)
?
When used in an ns declaration, isn't it [Some$Foo bar]
? Where that's more-so an ns than a value. Or are you talking about using Some$Foo/bar
in code?
You asking me? In Clojure it would be (import some.package OuterClass$InnerClass]
and then in code you do: (OuterClass$InnerClass/some-fn)
@didibus because if the lib exported as, for instance, default, then neither of those existing ways get at the export correctly. I can't remember the details, but I've been bit by the complexity of it.
The only difference is you would never do: (.-field some-ns)
but you might do: (.-field SomeClass)
Well... hum, actually I'm a bit fuzzy here, might still be (SomeClass/field)
actually.
But that field access is syntax sugar for the .
special form, which would be: (. SomeClass -someField)
It be nice if someone could describe such an edge case that makes it you can't do things exactly how they are in Clojure to me 😄
Another question: what would this whole solution look like if .
was used instead of $
? Would that introduce any ambiguity?
It still all seems to me like all the challenge here are due to having used require
for JS stuff as well, and not just cljs stuff.
I think I understand the intent at first, like, hey JS modules are closer to Clojure ones, so why not pretend like they are Cljs libs, but clearly, they were different enough that now we have a weird state of affair
Which I think is where dnolen is coming from. Like saying, ok we don't want a js-require. So either we want to use import, but that's not convenient because people seem to really want to be able to alias, or refer things from JS lib as well. If so, then we must find a way to make them work as if they are ClojureScript lib with standard require
. And now the question is.. can we?
@didibus Yeah, sounds like david and team got most of the way there over the last few years and a kind of solution is finally coming together.
Might not solve all edge cases, but it doesn't sound like the string require escape hatch is going away.
Speaking of which, it is also inconssitent with Clojure for enums to be EventType.value and not EventType/value. Don't know what the rational was for that
@didibus There’s no such thing as a class in JS. It’s all objects. You always access objects with .
.
And it appears to me here we are suggesting that we want to lift Objects in JS which act as namespaces as if they were namespaces and treat them so.
What an animated (and overwhelming) debate, I wish a good rest to the CLJS team during this week-end. Event if I arrived after the battle, I thought maybe I can add something. I was wondering if is was possible to get the name of all npm package. The answer is "yes", and guess what: there's a npm package for it "all-the-package-names". It just output every package on stdout.
npx all-the-package-names | grep "coffee.*maker" | wc -l
4
npx all-the-package-names | grep get-or-set | wc -l
1
You can find anything there. Yeah, coffee maker packages exist (you can check it yourself). These JS funny guys have a package for everything! I you do get how huge is this ecosystem, I highly recommend you to take a look at the generated galaxy regarding npm: https://anvaka.github.io/pm/#/galaxy/npm (you should take a seat before using this link).
So from there, I check if there's any package with the $
character: no package involved the character, good news! But:
npx all-the-package-names | grep "dollar" | wc -l
123
We're just one step away from it. One day, a JS dev will find to long to use dollar
in a package name and will prefer $
instead: concise, explicit, straightforward, only benefits => profits!
And who knows, if emoji are allow, why not use them in package name?
More seriously, I wonder if they were forbidden characters in package name. I found a npm package which answer this question, "validate-npm-package-name" (https://github.com/npm/validate-npm-package-name): package every where.
In its README, you can find the Naming Rules (https://github.com/npm/validate-npm-package-name#naming-rules) of package name. It says explicitly that package name cannot contain these characters: ~)('!*
Any character for this list can be used as a delimiter IMHO, and my favorite one is !
.To me, a prototype acts as both a Class and its instance, so I would have found it natural to treat them as a Class as well
@fabien.rozar Good investigation! The other issue is you need it to also not clash with possible ClojureScript namespace names. And the rules for that is it may include: . * + ! - _ ? $ % & = < > : #
. Though I guess it already allows $
so if something were to happen, we'd be breaking compatibility if there are any existing namespace with a $
in it
Hi guys. I ran into some problems with the latest version of CLJS. I reported about it here https://ask.clojure.org/index.php/9260/some-problems-with-latest-cljs-1-10-741
@dnolen any thoughts on it?
just added one more issue related to node target
reproduced and fixed, cutting a release just for the Quick Start - it seems like a pretty old bug
@fabien.rozar that's useful info thanks, it's been 10+ years of Node and you haven't seen $
in package name, I'm not too concerned at this point, again it aligns with some Clojure-isms so that's a plus
@didibus no dynamic imports, we're never going to work on that outside of what's needed for REPLs and all the various restrictions that apply for even that case
@john .
just not under consideration - Foo/bar
thing from Clojure can't work because Clojure knows that Foo
is a class and not a namespace, we don't have this information in ClojureScript generally, including foreign libraries coming from node_modules
- there's no type information to figure this out
@didibus Not really interested in :import
it really only serves one purpose - a way to get a certains kind of GCL libraries, it's not relevant outside that use case. The other problem is that :import
has a very restrictive syntax, again not interested in any changes - so not useful in this context.
all the feedback is appreciated. Just want to reiterate not interested in any change to the ns
form wrt syntax, if your idea is based on that let it rest 🙂
$
is still a primary contender given it exists in Clojure in a similar context, it's been used before in CLJS bootstrap, and it's unlikely to clash for cases that matter to most ClojureScript users
what we're proposing now is about reconciling 2 different but related problems: A) global stuff that's loaded outside of ClojureScript B) being able to treat some property, not nested, of a JS value as a namespace
My confusion here from a mostly Clojure dev is what you mean by "as a namespace"? As opposed to what? You referring to the use of js/
instead?
secondary benefits, for goog.global.Math
where GCL has externs we can do the same arity, existence, validation as is done for GCL namespaces
Ok, just to say, concerning cljdoc, its trajectory is clear thanks to the above discussion, thank you 😸 (I just follow the discuss for other issue you're talking, that's it)
@dnolen after looking more into https://clojure.atlassian.net/browse/CLJS-3159 I now think that perhaps we could have reify*
special instead of fiddling with anonymous deftype
, this would also align with Clojure, wdyt?
@roman01la for that why can't you just mark the var as private?
I don't know why deftype needs to do anything here except preserver the private var meta if it doesn't
hmm, good point. Would that solve https://clojure.atlassian.net/browse/CLJS-3160 though?
I guess it should, will give it a try, thanks
3160 seems a bit contrived to me - I don't know how these vars would every appear in numeric forms
I think it went out of https://clojure.atlassian.net/browse/CLJS-2875
> The ns-publics issue is related to the use of reify inside cljs.core/nil-iter's definition and incorrect type information being established: A Var is created, which is tagged as being of function type, when in fact the Var's value is nil. Then when the var special is applied to the Var's symbol, there is a bit of code that would normally conditionally include test meta in the generated Var:
yeah going to have to look all that later - that's a bit too much for me to load - the public problem is easy and obviously should be fixed
I can work on that, just need more input
@dnolen okay, understood. Is it true that $
would only be used in ns declarations? Or could I go (ns (:require [X.Y])) (Y$someFn))
?
Didn't you say the main impl would be in the resolve machinery? That sounds like it's usable in code, so I was wondering where you were going with the idea. And you can do (Y$someFn)
in Clojure, so I was wondering if the general behavior of $
applied here.
using this example (:require [goog.global$Math :as math])
. How do you know at compile time what can be used before $
? I mean even goog.global
does not exist as a namespace and is itself a property of the goog
"global"?
so I guess its too early to ask about implementation details? I'll come back in a couple days then.
implementation details are not a discussion point, and not going to be looking for feedback about that
my concern is about figuring out what can be valid as a "prefix" (ie. prefix$Thing
)?
Didn't you say the main impl would be in the resolve machinery? That sounds like it's usable in code, so I was wondering where you were going with the idea. And you can do (Y$someFn)
in Clojure, so I was wondering if the general behavior of $
applied here.
@john I would drop this line of thinking 🙂 don't worry about how it's going to work, we're past that part now
I'm not advocating one way or another. Just trying to better understand what's under consideration
sure, but the answer is if I didn't mention it above, not under consideration - what's above is it
you used (:require [goog.global$Math :as math])
as an example. I'm trying to figure out how you get to the point of knowing that goog.global
is valid and correct? is it just a hardcoded default?
what we can do is validate against known globals via externs, and warn if foreign entry w/o file isn't provided
sort of don't like the ambiguities that creates though. goog.string.format
would also be valid as goog.string$format
by that logic. given that it exists as a goog.provide and a runtime "var"
the ambiguity doesn't seem meaningful though, I don't see how this could lead to any real correctness issues
the whole point of this idea is that it perfectly aligns w/ object as namespace convention
Would it be usable for things that are renamed? Eg in the case of goog string? I think I've not well followed what the impact of externs is
if you think about the proposal is really just allowing something which already true right now
in global objects loaded by something else - objects are used to represent nested namespaces
if you squint - this is an incredible minimal change, with significant repercussions that allow to cover all use cases of external JS
Feedback on :bundle
target
- Setting :output-to
to a different dir than :output-dir
breaks import {npmDeps} from "./npm_deps.js";
, since the path should be different
- :bundle-cmd
doesn't output stdout/err of whatever command it executes, which makes it less obvious to find out if something is broken or not
@roman01la minor ticket + patch welcome for more flexible path, and another one for printing out stderr on failure
I guess there already was a discussion regarding generating JS exports for ^:export
vars with :bundle
target?
@roman01la what do you mean?
To turn (def ^:export x 1)
into module.exports.x = cljs.user.x
when :bundle
target is set
sure, btw who are those most users in your opinion?
if there's some use case you believe everyone is going to hit then something to talk about
I also want to point out something which I haven't had time to elaborate is there's a ton of change to make downstream tooling trivial
yes, I agree
ho, that's a nice example of using compiler passes
not try to compose this transformation stuff, if you need it just write 20-30 lines of code
@roman01la yes so again I haven't had a ton of time to document this
also later not now I would like to do some of the things that shadow-cljs wrt to the pipeline
shadow-cljs IMO does too much, has too many options, but the general idea of keeping everything in data and only a final flush to disk is sound and easier to reason about
sounds good, I could help with code or docs/guides, but that would still require some of your time, to put thoughts on paper
@roman01la I believe you have enough right now to handle the export stuff, just binding a pass around build that collects ^:export
vars and then generate the :target-fn
sounds like a plan 🙂
@dazld fixed https://github.com/clojure/clojurescript/commit/6a6e4e30f14b38a20b383d38e89c1f2604803cf0
This one is interesting. Depending on ClojureScript code from JS with optimizations set to :none
doesn't work, because ClojureScript output is loaded asynchronously. First browser loads Webpack output, which includes deps loader which only then loads ClojureScript output.
Also running Webpack in watch
mode from :bundle-cmd
blocks REPL, which means Webpack process should start in background and then it's a bit more tricky to manage this
yeah I'm just providing feedback from my observations
> running watch form :bundle-cmd is gratuitous I have JS module that consumes ClojureScript and renders Reagent component in existing JS code. Here it makes sense to run Webpack in watch mode because JS code is being changed. But maybe that's not where target :bundle should be used.
there's just too many cases where :bundle-cmd
isn't going to be sufficient - which is fine
good point, a not on that in the docstring could be useful
I still don't understand your first comment about :noneHere's network trace. bundle.js
is produced by Webpack, the code in this file depends on ClojureScript code which is loaded later.
circular deps? the only thing that I have here is that both cljs and js sources depend on React from node_modules
@roman01la you could try :whitespace
which is REPL compatible
@roman01la the other option is to have your JS sources go through Closure instead of Webpack
not sure about mutual deps, it's just JS code that depends on cljs, but yes, bundling all cljs output into a single file will solve this
but again, can probably write a custom target-fn to handle this somehow
mm, no, just this
import "./out/index.js"
console.log(window.hello_bundler.core);
Looks like it hooks into closure's debug loader?
@roman01la the problem with waiting for anything is that goog.base
has to be there, but even goog.base
is written as a script tag
https://github.com/vouch-opensource/krell/blob/dbc31f264349b466174393f465cf2611855708ef/resources/main.dev.js haha, for anyone else curious