This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-03-26
Channels
- # announcements (6)
- # babashka (29)
- # babashka-sci-dev (2)
- # beginners (129)
- # calva (9)
- # clara (16)
- # cljdoc (49)
- # clojure (125)
- # clojure-bay-area (3)
- # clojure-europe (55)
- # clojure-france (1)
- # clojuredesign-podcast (8)
- # clojurescript (85)
- # conjure (3)
- # core-logic (2)
- # cursive (1)
- # events (1)
- # honeysql (61)
- # jobs-discuss (23)
- # lsp (69)
- # malli (14)
- # nrepl (3)
- # off-topic (16)
- # portal (11)
- # re-frame (8)
- # releases (1)
- # ring (2)
- # shadow-cljs (12)
- # vim (42)
- # xtdb (18)
Trying to do promise interop with js.
backend> (-> (js/Neutralino.filesystem.readDirectory js/NL_PATH)
(p/then #(prn %))
(p/catch #(prn %)))
#<Promise[~]>
I'm not sure why I can't get anything to print out. Is there a way to inspect a promise?If I decide not to use promesa, then I get this:
(-> (js/Neutralino.filesystem.readDirectory js/NL_PATH)
(.then #(prn %))
(.catch #(prn %)))
It still just returns a promise though, I get nothing showing up in the console.Yeah, I definitely wouldn't use Promesa here. :) But that's besides the point.
Your promise is never resolved because .readDirectory
probably never attempts to read that directory. It's either bugged or blocked by something else. The latter is often the case when you have another code running, just because JS is single-threaded. But if you're doing it in a REPL then that shouldn't be the case.
I might have to use electron after all, even though I really don't want to ship another chromium with my application.
I am not sure about the namespace being taken wording in the doc. The relevant part is this sentence: https://clojurescript.org/guides/ns-forms#:~:text=Since%20the%20JVM%20ClojureScript%20compiler%20uses%20Clojure%20for%20execution%2C%20there%20would%20be%20a%20namespace%20collision%20if%20the%20port%20were%20not%20moved%20to%20cljs.pprint.%20In%20short%2C%20the%20clojure.pprint%20namespace%20was%20taken. Why is it taken? The clj and cljs are two files with different extensions.
> But, if you look at, say, the port of clojure.pprint
for use with ClojureScript, it involves a macro namespace
The CLJS version of pprint
needs additional CLJ code. Technically, I guess, it could be moved to a different namespace. But either I'm wrong and that's not possible or the authors decided not to do that for some reason.
Example code is:
(defn- main-stack
[]
(let [stk (createNativeStackNavigator)]
[:> (.-Navigator stk) {:headerMode "none"}
[:> (.-Screen stk) {:name "Welcome"
:component (r/reactify-component welcome-stack)}]]))
and metro warns about this:
WARN Got a component with the name 'app.welcome.stack.welcome_stack' for the screen 'Welcome'. React Components must start with an uppercase letter. If you're passing a regular function and not a component, pass it as children to 'Screen' instead. Otherwise capitalize your component's name.
This part >
React Components must start with an uppercase letter.
is of course invented by Metro - React itself doesn't care.I dunno how to hide this warning. The name http://app.welcome.xxx is the cljs ns name, so it’s something I cannot control though.
What about the second part of this warning? About passing the function. Or you can look at Metro's sources, find where the warning is issued, and see if there's a way to disable it.
As the last resort, you can always override console.warn
and just filter it out explicitly, by text.
Ran into this today. I did what’s mentioned above:
(set! js/console.warn
(fn [message]
(when-not (str/includes? message "React Components must start with an uppercase letter.")
(js/console.warn message))))
The warning comes from react-navigation: https://github.com/react-navigation/react-navigation/blob/4e4935ac2584bc1a00209609cc026fa73e12c10a/packages/core/src/useNavigationBuilder.tsx#L212
Yeah, we discussed it on Reddit as well.
If I were one of you guys, I'd create an issue for react-navigation
. ;)
I was partly through creating one, and they required an repro project link, so I abandoned it because I didn’t want to spend the time setting up a separate project just to show them a simple issue, unless I knew they were going to accept a change (the one I experienced it in is a work project). I understand the importance of repro steps, but always requiring a project link is going to stop some people from reporting real issues at all, which I think is unfortunate.
FWIW, here’s updated code that won’t go into infinite recursion and also respects all args given to console.warn.
(defonce warn js/console.warn)
(set! js/console.warn
(fn [& args]
(when-not (str/includes? (first args) "React Components must start with an uppercase letter.")
(apply warn args))))
If you make something like "Add a flag to disable that warning" a feature request, surely that won't require a repo? Because there's nothing to put in the repo.
FYI, someone closed the above request, informing that LogBox.ignoreLogs
can be used to silence the warning.
Another clj vs cljs question. In clj I have the function requiring-resolve
, used like (requiring-resolve 'foo.bar/baz)
. What should I use in clojurescript? I know that there's resolve
in cljs, but it doesn't automatically load baz
from the foo.bar
namespace.
If you're building a complete JS bundle without self-hosting, then there are no dynamic require
s.
If you can describe what's your primary goals are, maybe a better solution can be devised.
so, I mainly would need this as a dev help for me. I have in my emacs config:
(after! cider-mode
(defun cider-tap (&rest r)
(cons (concat "(let [__value " (caar r) "]"
" (if-let [f (requiring-resolve 'emacs.portal.master/portal-add-metadata)]
(tap> (f __value))
(tap> __value))
__value)")
(cdar r)))
(advice-add 'cider-nrepl-request:eval
:filter-args #'cider-tap))
which basically checks if I have the emacs.portal.master/portal-add-metadata
function, and if that's there it acts as an interceptor to choose a correct visualizer for portalthe problem is that, being portal-add-metadata
in an external library, I cannot just check `(resolve 'portal-add-metadata), because this will be evaluated in a different ns
maybe I could quickly try to switch to the emacs.portal.master
ns, if I can detect something. Edit - this doesn't seem to work
A common way to solve it is in reverse - assume that the function is always there, and either use a classpath that has it or add a dummy noop instead.
so, I should (require '[emacs.portal.master :as emp])
and use that nonetheless, but if I don't add the dummy noop it will explode, right? And the dummy noop is just another library with the same path
I'm confused by the fact that if I evaluate this at a repl:
(require '[emacs.portal.master :refer [portal-add-metadata]])
(resolve 'portal-add-metadata)
I get nil
Indeed.
It doesn't have to be a proper library - it can just be a separate dir that you include in your :paths
via an extra alias.
So e.g. alias :with-portal
has either :paths
or :deps
(or :extra-deps
- you get the point) that has a proper implementation of emacs.portal.master/portal-add-metadata
. And an alias :without-portal
has the same but with a noop implementation.
> I'm confused by the fact that if I evaluate this at a repl
Try putting require
anywhere that's not top-level. Wrap it in an if
.
If you always have emacs.portal.master
on your classpath but sometimes portal-add-metadata
is not there, then using require
+ resolve
and then checking for nil?
should work.
So, something like:
(if (require '[emacs.portal.master :refer [portal-add-metadata]])
:a
:b)
gives me :repl/exception
and no other info in the repl 😂maybe in cljs I can only use (:require ...)
in the ns form, but not (require ...)
as a standalone function
No, I meant as a separate combination:
(require 'emacs.portal.master)
(if-some [f (resolve 'emacs.portal.master/portal-add-metadata)]
...
...)
No clue why requiring-resolve
- maybe just not a priority to have it.Or maybe so that require
is always at the top level, since you can't have it anywhere else. More likely.
the problem with this snippet:
(require '[emacs.portal.master])
(if-some [f (resolve 'emacs.portal.master/portal-add-metadata)]
:a
:b)
is that it returns :b
even when I have the library in the classpath, probably because dealing with namespaced symbols is not what resolve
doesWith the default REPL and compiler:
ClojureScript 1.11.4
=> (require '[app.core])
nil
=> (if (resolve 'app.core/main) 1 2)
1
you're right, I can do:
(require '[cljs.core.async])
(resolve 'cljs.core.async/chan)
;; => 'cljs.core.async/chan
but not
(require '[emacs.portal.master])
(resolve 'emacs.portal.master/portal-add-metadata)
;; => nil
Here are my shadow.cljs and deps.edn files:
;; shadow-cljs configuration
{:deps true
:dev-http {8080 "public"}
:builds
{:frontend
{:target :browser
:modules {:main {:init-fn main.core/init}}}}}
and
{:deps
{thheller/shadow-cljs {:mvn/version "2.17.8"}
djblue/portal {:mvn/version "0.22.1"}
emacs-portal-master/emacs-portal-master {:local/root "../emacs-portal-master"}}}
After you do (require '[emacs.portal.master])
, what happens if you evaluate just emacs.portal.master/portal-add-metadata
?
maybe these are not the right coordinates?
emacs-portal-master/emacs-portal-master {:local/root "../emacs-portal-master"}}
I also tried:
emacs-portal-master/emacs-portal-master {:local/root "/home/carlo/code/clojure/emacs-portal-master"}
Well, if your code doesn't work with require
then yeah, something's fishy. :)
The relative path should be OK, as long as it's correct relative to the deps.edn
file where you're using it.
But does that ../emacs-portal-master
dir have its own deps.edn
with correct classpath and sources?
that has only:
{:deps
{metosin/malli {:mvn/version "0.8.4"}}},
do I need something more?in there I have src/emacs/portal/master.cljc
, and I didn't specify a sources path because src
is default for deps.edn. Also, I can load emacs-portal-master
as a dependency in the clj side.
I tried repeating your setup, to some extent.
I have a project, and I have dir lib
next to it, so its relative path also starts with ../
. That dir has one file at src/lib/core.cljs
, with one function f
.
I then ran npx shadow-cljs watch main
in one terminal and, after opening a browser tab with the app, npx shadow-cljs cljs-repl main
in another tab.
In that tab:
cljs.user=> (require 'lib.core)
nil
cljs.user=> (resolve 'lib.core/f)
#'lib.core/f
So it all works as I would expect. I can't reproduce what you see.
Maybe you can create a minimum reproducible example (with no external dependencies, no extra tools, etc) and share it.Moved the file from .cljs
to .cljc
, as it's in your case - same exact behavior, it all works just fine.
Given that you're using a CLJC file, are you sure that function doesn't end up behind a reader conditional that excludes it from CLJS?
thanks @U2FRKM4TW! I'll see about creating a reproducible example and check for conditionals!
Ok I think I was hitting this https://github.com/thheller/shadow-cljs/issues/536
How so? Given that we're both using shadow-cljs, and it's working just fine for me. Or are you running it not from a REPL but from some CLJS file?
I see. Then just make that require
into :require
as a part of your ns declaration. The resolve
part should still work.
because I thought that when I was evaluating a form in the cljs file, it was just like sending that expression to a repl
and instead what's happening is that I'm loading the namespace first, right (I think cider evaluation does that)
so cljs knows that I'm in a cljs namespace, and require is not available outside a ns
declaration? I don't know if this is actually the reason
Maybe, I'm not familiar with the Emacs ecosystem.
But in any case, see if :require
works.
It refuses to require my namespace because it depends on malli.instrument
, which seems to be only available in clj
(I asked in #malli why that's the case, since I know that there are other projects, like guardrails, that do instrumentation in cljs)
But given that you control that CLJC namespace, you can make a dependency on malli.instrument
CLJ-specific.
oh, you are totally right, in fact, I don't even really depend on malli.instrument
except for some code blocks that I was using to test the functionality. I'll remove them
ok now it's loaded and I get a proper response for
(resolve 'emacs.portal.master/portal-add-metadata)
next thing for me is figuring out how I can structure this so that it only runs in a repl, avoiding the ns*
restrictionDoes resolve
not work if you make it a part of a CLJS file? I thought only require
didn't work.
I still don't think that:
(resolve 'emacs.portal.master/portal-add-metadata)
by its own can work, I mean it's not an error, but will return nil
. (If I don't do a require
before in the ns form)ok, I get that now; so now the problem is that was meant to be some dev tooling, and this forces me to add a require on a dev dependency in namespaces that are doing other things (and delete it after). Like, if I have an unrelated project that has a main.core
, now I have to say:
(ns main.core
(:require [emacs.portal.master]))
even when main.core
doesn't have much to do with this dev library, and remove it manually afterwardsthe other option would be changing namespaces in:
(defun cider-tap (&rest r)
(cons (concat "(let [__value " (caar r) "]"
" (if-let [f (resolve 'emacs.portal.master/portal-add-metadata)]
(tap> (f __value))
(tap> __value))
__value)")
(cdar r)))
but if I change namespace there, now all the variables referenced in the code are not validSo you will have that dev :require
in all relevant namespaces.
During the prod build, that dev namespace will have only noop functions (or no functions at all if you can still use resolve
).
During the dev build, that dev namespace will come from a completely different file and will have proper functions.
ok I see, but last question, where does the noop version live? The only possibility I see is that it's another dummy library that is in the default dependencies, that I then overwrite with my real dev library in a extra-deps
clause