Hi, I’ve been chasing down a bug that is leading StackOverflows when I try and compile my CLJS file.
I’m seeing that deps/dependency-order
is introducing an extra :requires ["react"]
and this is causing the StackOverflow:
(require '[cljs.js-deps :as deps])
=> nil
(deps/dependency-order
'({:file "libs.js", :provides ["react" "cljsjs.react"], :requires [] :foreign true}
{:file "libs.js", :provides ["react" "react-dom" "webpack.bundle"] :foreign true}
{:file "libs.js" :provides ["react-dom" "cljsjs.react.dom"], :requires ["react"] :foreign true}))
=>
({:file "libs.js", :provides ["react" "cljsjs.react"], :requires [], :foreign true}
{:file "libs.js", :provides ["react" "react-dom" "webpack.bundle"], :foreign true, :requires ["react"]}
{:file "libs.js", :provides ["react-dom" "cljsjs.react.dom"], :requires ["react"], :foreign true})
Note the extra :requires ["react"]
on the second line of the output, it was not present in the input.
If the order of the inputs is switched, then the extra require does not get added:
(deps/dependency-order
'({:file "libs.js", :provides ["react" "react-dom" "webpack.bundle"] :foreign true}
{:file "libs.js", :provides ["react" "cljsjs.react"], :requires [] :foreign true}
{:file "libs.js" :provides ["react-dom" "cljsjs.react.dom"], :requires ["react"] :foreign true}))
=>
({:file "libs.js", :provides ["react" "react-dom" "webpack.bundle"], :foreign true, :requires []}
{:file "libs.js", :provides ["react" "cljsjs.react"], :requires [], :foreign true}
{:file "libs.js", :provides ["react-dom" "cljsjs.react.dom"], :requires ["react"], :foreign true})
I think this is the cause of the issue that is leading to StackOverflows on some of our developer machines whilst it is working fine on others. Maybe the order of the input to that function is not consistent across developer machines (although all software versions are identical).
Can anyone confirm if this is a bug in cljs.js-deps/dependency-order
? I assume that the output should be identical to the input (except for order)?@jamescroft that's a bug in your graph
you should only have one foreign entry for libs.js
not 3
you have a cycle in your input so you can't expect this to work
@dnolen Thanks for looking. I’m using webpack to bundle a load of JS dependencies that are used by the app. The config that I’m using is:
:foreign-libs [{:file "libs.js"
:global-exports {react React
react-dom ReactDOM}
:provides ["react" "react-dom" "webpack.bundle"]}]
The webpack bundle includes “react”, “react-dom” and I’m also giving it the synthetic namespace “webpack.bundle”this one looks ok, so can you explain what you're doing above
I cannot make sense of your report because it doesn't look the same
Sure, the config that I have in the app is the :foreign-libs
config (second snippet). This had been working fine, but recently started to StackOverflow when compiling on some developer machines. I have been trying to track it down and I have found that an extra :requires ["react"]
is being added by the call to deps/dependency-order
.
The inputs to deps/dependency-order
that I posted are the ones I grabbed from a debugging session. I don’t know why at that point it has 3 inputs for libs.js
, I assume they have been expanded to that by the clojurescript codebase. My only config is what I posted in the second snippet
In my dev.cljs.edn
config I don’t mention cljsjs.react
and cljsjs.react.dom
but they are there as part of the :provides
for the extra 2 “libs.js” inputs to deps/dependency-order
. I think it is the clojurescript compiler that is turning my single foreign lib into 3?
so you cannot reproduce on your machine?
I can
but I don't understand the foreign lib at all - providing cljsjs.react.dom
and react-dom
can't be right
so you need to explain why you need both
I just captured the input that was passed to deps/dependency-order
. At that point there are 3 foreign libs with the :file "libs.js"
. I didn’t construct these I just captured the call. I only have 1 foreign lib defined in my config file, so I don’t know why there are 3 by the time that the dependency sort happens
you're missing what I'm saying
go back to the beginning
who cares what happening in ClojureScript yet
why do you have react-dom
and cljsjs.react.dom ?
Sorry, this is difficult over slack. Where are you seeing cljsjs.react.dom
?
This is my config:
:foreign-libs [{:file "libs.js"
:global-exports {react React
react-dom ReactDOM}
:provides ["react" "react-dom" "webpack.bundle"]}]
ok, sorry - so we don't talk past each other - this looks good
but when you debugged somehow you are getting cljsjs.react.dom
but you haven't explained how this is possible
ClojureScript is not going to inject that w/o it be provided by something else
A search for cljsjs.react.dom
over the codebase doesn’t return anything, so it must be coming from a dependency. Off the top of my head, the dependencies that use react are: UIX and devcards. These are defined in our deps.edn with exclusions for React (because we need to include React in the webpack bundle for other reasons):
uix.core/uix.core {:deps/root "core"
:exclusions [cljsjs/react]
:git/url "<https://github.com/roman01la/uix.git>"
:sha "0da33eef38a7122be226b9b9a8ae0b5431b6b5d3"}
uix.dom/uix.dom {:deps/root "dom"
:exclusions [cljsjs/react-dom]
:git/url "<https://github.com/roman01la/uix.git>"
:sha "0da33eef38a7122be226b9b9a8ae0b5431b6b5d3"}}
devcards/devcards {:mvn/version "0.2.7"
:exclusions [cljsjs/react cljsjs/react-dom]}
So, the aim is to have a single JS file produced by webpack that contains React, ReactDom and a bunch of other libraries. Hence we exclude React from any clojure dependencies that we add in, and use the :provides
and :global-exports
options of the foreign-lib to tell them where React is coming from
right you have to exclude stuff - dump the dependency tree and find out where it's coming from
clj -Stree
or something like that
Ok, so it looks like the graphql client re-graph
is bringing in cljsjs/react
and cljsjs/react-dom
too. I haven’t got exclusions defined for that dependency in deps.edn. I’ll try adding an exclusion there and see if it changes anything
Awesome! That looks to have fixed it. Changing the dependency to
re-graph/re-graph {:mvn/version "0.1.15"
:exclusions [cljsjs/react cljsjs/react-dom]}
avoids the StackOverflow.So, not specifying those :exclusions
somehow messed up the graph, leading to a StackOverflow? Thanks so much for your help looking into that
@jamescroft I mean the error is super annoying for sure
the stackoverflow and the dependency graph thing makes understanding the issue hard
but in the end you can't have these things together in your dependency graph anyway
it cannot work
@dnolen Yeah, understood. I had no idea we had an extra React dep being included until you pointed it out. Thanks!
np
Can reagent be used to do SSR and then hydrate?
Same way you'd do that in React, I imagine - probably with dangerouslySetInnerHTML
.