cljs-dev 2025-08-28

would love to know more

:refer-global :only

@dnolen I see there is also a variant without :only?

(ns foo.core
                           (:refer-global [Date] :rename {Date MyDate})

thats commented out, so probably not 😛

oh ok. values going into :rename don't have to be :only 'd first? with :require + :refer that is the case AFAIK?

I'm inclined not to support that - at least initially

FWIW:

user=> (require '[clojure.set :rename {union xunion}])
nil
user=> (xunion #{1 2 3} #{4 5 6})
Syntax error compiling at (REPL:1:1).
Unable to resolve symbol: xunion in this context
My expectation is that this would work the same in CLJS for :require-global

why not? seems redundant to name things twice

but this test seems to suggest otherwise:

(deftest test-parse-global-refer
  (let [parsed (ana/parse-global-refer-spec {}
                '((:refer-global :only [Date] :rename {Symbol JSSymbol})))]
    (is (= parsed
           '{:use {Date js}
             :rename {JSSymbol js/Symbol}}))))

oh hrm sorry, I switched gears to the lite mode stuff - I think you all are right, only and rename gets combined - so it works

why not? it seems CLJS already works that way:

$ plk
ClojureScript 1.11.132
cljs.user=> (require '[clojure.set :rename {union xunion}])
Unexpected error (ExceptionInfo) compiling at (<cljs repl>:1:1).
Renamed symbol union not referred at line 1

and this agrees w/ what was done before

but the important thing to note here ... is that what's driving this is Clojure refer

because nothing is being required here

only is the counterpart to refer here?

so require expectations do not need to be fulfilled

yeah so I'm correct in that you probably need :only

I'm not sure if we're on the same page. Do you think that the renamed value should also occur in :only ? yes or no

you do see how :refer works and what it means in Clojure?

I'm starting from there, I'm not concerned about convenience or anything else really

aaah I see now:

user=> (refer 'clojure.set :rename '{join x}
)
nil
user=> (x #{1 2 3})
Execution error (ArityException) at user/eval8 (REPL:1).
Wrong number of args (1) passed to: clojure.set/join

I ran aground of this problem once I started working on the macro for the REPL

you just referred the whole clojure.set namespace

see the clojure.docs for the conflict warnings example

right, so it should be:

user=> (refer 'clojure.set :only '[join] :rename '{join x})
nil
user=> (x #{1 2 3} #{4 5 6})
and this is how require-globals should also work - right?

sorry, `:refer-globals` :refer-global

then we are on the same page since my original message, thank you for clearing this up. the test-parse-global-refer seemed to indicate otherwise

oh yeah sorry, that needs to be fixed up

I'm not totally against sugar because of course refer-global w/o :only doesn't mean anything - we cannot know what's in the global ns

but can be done trivially after people play around w/ it

(:refer-global :rename {Date Foo}) we also know that Date is something global, so the extra :only [Date] is just redundant. that can be inferred

that could be a nice thing

if we can auto known things

(but that's why I kind of like these decisions later since the design space opens up fast)

but we know it just by the fact that its mentioned in this form. it can't rename something from another form or so

The point that it can be inferred seemed not to be an argument for :require + :refer in JVM Clojure and CLJS so far. I'm not totally against it, but I think it's nice to keep to the defacto standard which is JVM Clojure as well

(CLJ doesn't have refer-global so no "standard" to adhere to)

I find the implication of :only a bit confusing, since that kinda seems to imply there is a way to :refer :all for all globals, which we can't know

(:refer js/globalThis :only [Date] :rename {Date x})

I had the same feeling about :only but I dropped that objection since :refer is a standard

but if you argue that there is no standard to adhere to since this is a completely new feature, I'd buy that too

:only as used in current places means actual "only", as in that thing but nothing else. not using :only meaning everything. but in :refer-global not using it doesn't mean all globals, since we can't know that

👍 1

dunno its bikeshedding. doesn't really matter what it is as long as its consistent

:only+`:rename` seems redundant but also doesn't really matter

One additional question. Will :refer-global also support the property syntax, like:

(:refer-global :only [Library$Module])
like is supported in :require with e.g. $default ? I think this is a must have when using CLJS with script tags that pull in other libraries that define a nested library structure. Even more compelling with :lite-mode . I don't think the :refer-global syntax lends itself well for this at the moment. In :require you can give such a property-accessed object an alias, e.g. (:require ["foobar$default" :as foobar]) but this doesn't work with :refer-global

(I removed my "ship it" message since this seems kind of important!)

there's a separate thing I haven't worked on yet :require-global which supports require syntax.

The idea here is to distinguish between browser builtins and other scripts you added to the page. :require-global is for the later.

why distuingish? and how would one refer window.Intl.NumberFormat for example? (this is just an example, there might better ones)

Intl/NumberFormat - any real properties in the browser can be inferred properly

you never need to write window that's just global stuff

haven't seen any compelling argument for complecting into one thing here.

another thing here is validation logic

for browser globals we can check lots of things that aren't going to work

for libs, maybe a couple of runtime asserts in dev

I mean when you want to have NumberFormat itself referred, not with the Intl prefix. So you can write (NumberFormat/supportedLocalesOf ...) . Maybe this isn't the strongest example, but maybe down the road there will be browser APIs where this makes more sense. Complected: I'm agnostic to the difference between a host global or something defined by a polyfill or just a normal library. To me it doesn't matter. This also isn't browser specific, could also be node, Bun, etc.

browser apis are not that nested - it's inconvenient, really not concerned about that.

polluting the global ns is not a thing JS runtimes do that much for the obvious reasons

unlike the browser

Looks like a bug in CLJS. As I mentioned in my response to that thread, no clue how Transit would be related, but cljs.analyzer/cache-file can return either File or URL while cljs.analyzer/write-analysis-cache expects it to always be File. https://clojurians.slack.com/archives/C03S1L9DN/p1756400705732949