This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-10-20
Channels
- # announcements (10)
- # aws (4)
- # babashka (71)
- # beginners (30)
- # calva (61)
- # cherry (1)
- # cider (16)
- # clj-kondo (3)
- # clj-on-windows (4)
- # cljsrn (1)
- # clojure (28)
- # clojure-austin (2)
- # clojure-bay-area (1)
- # clojure-europe (45)
- # clojure-hungary (1)
- # clojure-nl (1)
- # clojure-norway (26)
- # clojure-sweden (14)
- # clojure-uk (11)
- # clojurescript (39)
- # core-async (3)
- # core-typed (11)
- # datomic (68)
- # fulcro (7)
- # keechma (1)
- # lsp (29)
- # malli (5)
- # off-topic (57)
- # other-languages (13)
- # pathom (4)
- # rdf (7)
- # reagent (7)
- # reitit (6)
- # releases (1)
- # schema (8)
- # shadow-cljs (86)
- # sql (22)
- # squint (1)
- # vim (8)
- # xtdb (12)
I am working with a react application and am noticing an interesting bug w/ shadow + uix (v1) and live-reload with a :after-load a/render
in my build config.
If I have
;; a.cljs
(ns a
(:require [b])
(defn app []
[b/render])
(defn render []
(uix.dom/render [app] (js/document.getElementById "app")))
;; b.cljs
(ns b)
(defn render []
[:p "Hello world"])
Everything works fine (ie. it will update if I modify b/render
and save the file
If I have:
;; a.cljs
(ns a
(:require [b]))
(defn app []
[b/render])
(defn render []
(uix.dom/render [app] (js/document.getElementById "app")))
;; b.cljs
(ns b
(:require [c]))
(defn render []
[c/render])
;; c.cljs
(ns c)
(defn render []
[:p "Hello world"])
It will not reload if I modify c/render
until I also re-save b.cljs
.
If I add c
as a require to a
then it will work properly. I suspect it has to do with caching intermediates, but I would expect this to work… Is this expected?Are you sure c isn’t reloading? Throw in some printlns to rule out that this isn’t a dataflow issue.
Meaning, c/render doesn’t take any arguments here and there is no internal hooks so it has no reason to know to rerender (even if the code has changed and reloaded)
Same thing with b/render
So adding printlns confirms that the files are reloaded correctly on save (ie. modifying c.cljs
will cause c
and b
to be reloaded
and it also confirms that the render functions are not fired
But, when requiring c
from a
then the render function is fired… Which is what I am having trouble understanding
ie. I could understand it one way or the other, but why does re-requiring c
from a
cause it to work?
been there, partner haha
The order of requires is probably important there too.
(ns a
(:require b c))
is probably not going to be the same as
(ns a
(:require c b))
I'm guessing that c/render
needs to be redefined first, then b/render
, then a/render
for hot reload path to function correctly
due to potential for eager binding in scope capture
do you by any chance use react 18 ? i remember seeing an issue on live reload with 3 namespaces
I’m actually using react 16 I believe
see the recompile logic & gotchas described here https://code.thheller.com/blog/shadow-cljs/2019/08/25/hot-reload-in-clojurescript.html
Agreed, I think this is more of a reactive coding / framework nuance issue and shadow is working as expected
Yeah I think it has to do with react memoization inside uix v1
The dummy prop is a cute trick though, hadn’t thought of that.
I've been called worse 😉
I noticed that in dev builds, source files and source maps (in a base64 url) are embedded in an eval
statement. I’m suspecting that react-native doesn’t support source maps on eval’d code. Is there a workaround for this?
it looks like react native supports source maps yeah? https://reactnative.dev/docs/next/sourcemaps
input source maps are an issue with Metro that I’ve been looking at for a couple weeks now yeah
the eval js maps are only emitted so source maps at least work when using the run in chrome thing
oh, so these “embedded” source maps produced by shadow dev builds never have to be processed as input source maps if they’re evaluated at runtime right?
not sure thats even still a thing though. been a couple of years since I looked at react native stuff
i guess the important question here is if shadow can be configured to create a dev build without the embedded source maps
hmm okay, i'm surprised no one else has asked for this. I’m pretty sure the embedded source maps are responsible for nonsensical stack traces inside Expo: https://docs.expo.dev/get-started/errors/#redbox-errors-and-stack-traces
but IIRC it had the issue that metro will try to process everything. and it used to take a lllooooooooooong time to process cljs.core
if you get it to work with :target :npm-module
I'll happily change :target :react-native
metro issue #104 has been open for five years, yeah I saw your post on it there all those years ago, I took a stab at it, still trying
but there is no option to turn of the eval mode for :react-native
. it is there for good reasons
im new to react-native which is part of the problem here, but what are the reasons for the eval? was it specifically for testing react-native somehow in chrome?
oooh, that explains why I have not seen a speed issue
i saw the re-natal-husk solution in the cljsrn wiki talking about the slowness with that
but also this was the only way to get source maps to work reliably in the chrome devtools runtime thingy
i suppose most people are just developing on chrome, then for prod they’re manually mapping error locations in the sentry logs to cljs sources using their own manual tooling
i got a stack trace trying to load an npm-module build into Expo Go
might be a path issue
i'll go down this rabbit hole another time, but thanks for the context here.
@thheller I’m trying again to get :target :npm-module
working on react native to test if it’s still slow. I see that it doesn’t generate an <output-dir>/index.js
like target react-native would.
Is there a way I can recreate that index.js file required by react-native, I feel that including my main project’s js file will be missing other things that seem to be included by shadow-cljs to make the build work
that was my question actually why your react-native target creates one, and what would I be missing if I tried to do it myself
thumbing through it, I saw a lot of shadow-react-native namespaces being included
:npm-module
is just plain commonjs, it doesn't try to hide anything and therefore doesn't need all this boilerplate
the only point of the index.js
is to have some code that renders something. that code can be all CLJS, but it needs to be a called from a index.js file
so just that one line loading the cljs code and calling the init fn is equivalent to what :init-fn
in :target :react-native
does
got it, thank you
I created the index.js file with require('./dev.js').init_BANG_()
, since our config has :init-fn dev/init!
, but I got back an error when trying to load it:
iOS Bundling complete 130ms
ERROR Error: Requiring unknown module "undefined".
Somewhere this is failing, and this doesn’t seem equivalent to the index.js file created for the react-native target.as I just explained. it is obviously not equivalent in mechanics, since it doesn't do any of the hiding
the 130ms is already suspicious enough. there is no way it processed all the code in that time
so :output-dir "cljs"
so that all the files go to <project>/cljs/...
, then <project>/index.js
does require('./cljs/dev.js').init_BANG_()
that way you can at any time kill the cljs
dir without worrying about any of your other files
I am driving to a doctors appt, i will answer when i get back. There's a lot to debug and figure out but i got no info on where the error was coming from. The build time of 130ms was because it was a rebuild, it took longer the first time. Sorry and thank you
This is kind of a bit off topic for shadow but @thheller I'm kind of curious if you've done any devlogs or podcasts where you talk about how you can stay so motivated on an open source project for so long. It's really impressive.
well, I built it for my own work projects in the first place. and still use it for that, so sort of just solving my own problems that others also happen to have 😉
nah come on haha
well where it comes from, good stuff, and thanks 😄