Fork me on GitHub
#shadow-cljs
<
2021-07-05
>
Adam Kalisz16:07:35

@thheller After an upgrade to shadow-cljs 2.11.26 to 2.14.5 the loading of our administration module broke with this message message: "Error loading admin: Consecutive load failures", stack: "CustomError: Error loading admin: Consecutive load…2e67cadcbe6a0cbc0cd49287b5202a7cdedc.js:421:1090)" Any ideas?

Adam Kalisz16:07:39

In dev, everything is fine. Also release on my local laptop works fine. As soon as I deploy to staging, the administration module loading is broken.

thheller16:07:01

don't know. what is the full error? looks like it is missing some info WHY it fails loading?

thheller16:07:00

I also don't recognize that error. it isn't from shadow?

Adam Kalisz16:07:02

I don't really have a clue why it happens, I only know, I updated shadow-cljs as described to use newer ClojureScript 1.10.866 and that's it. The module is loaded using something like:

[lazy/lazy #:lazy{:loadable (slazy/loadable <someprojectname>.client.views.administration.core/administration)
                  :state    :loading/administration}]
Here is the lazy implementation:
(ns <someprojectname>.client.views.widgets.lazy
  (:require ["react" :as react]
            [reagent.core :as r]
            [shadow.lazy :as slazy]
            [<someprojectname>.client.views.loading :as loading]))

(defn- component
  "React Lazy component which waits till the code is loaded and then replaces it with the component itself."
  [loadable]
  (react/lazy
    (fn []
      (-> (slazy/load loadable)
          (.then (fn [root-el]
                   #js {:default (r/reactify-component (fn [props] [@loadable props]))}))))))

(defn lazy
  "Renders a component whose source code may have to be first loaded. While the source code is loaded, renders the
  loading screen for the given state. The single parameter is a map having the following keys:

  :lazy/loadable - Call (slazy/loadable ).
  :lazy/state - The loading state while the component's source code is loaded."
  [{:lazy/keys [loadable state]}]
  [:> react/Suspense {:fallback (r/as-element (if state
                                                [loading/loading {:loading/state state}]
                                                [:div]))}
   [:> (component loadable)]])
The error isn't very specific unfortunately - or at least I don't see any useful details.

thheller16:07:11

whats in the network tab of the devtools? do the files 404 or something?

Adam Kalisz17:07:27

No 404 I can see...

thheller17:07:25

does it execute code on load? maybe it throws an error during loading

thheller17:07:44

you can sort of easily test this by just loading the required files manually in your html

thheller17:07:53

without the loader. just some script tags, in the correct order so shared/admin or whatever else there is

thheller17:07:17

not sure why its loading everything twice though? why is it loading "layout" twice or even 3 times?

Adam Kalisz17:07:16

I really don't know, I haven't written this part of the code... I only stumbled over it, because it broke. :-)

Pavel Klavík17:07:39

We are running the same webworker in layout twice, so that is likely the reason.

Pavel Klavík17:07:56

Administration is loaded twice because we have two lazy components which depend on it, inserted into different views.

Adam Kalisz17:07:07

Ok, after removing one of the lazy loads, I get one fewer error messages...

Adam Kalisz17:07:53

Ah, ok, I will try that. This is something that gets executed early on - but don't even see the temporary console.log.

(rf/reg-event-fx
  :administration/load-data
  [clean/effects]
  (fn [effects [_ refresh]]
    (let [{:administration/keys [init mode]} (db-get/administration effects)]
      (js/console.log "LOG LOG Loading administration data.")
      (if (or init refresh)
        (db-update/administration (case mode
                                    :administration/index (metrics/switch-to-metrics effects)
                                    :administration/metrics (metrics/switch-to-metrics effects)
                                    :administration/charts (charts/switch-to-charts effects)
                                    :administration/users (users/switch-to-users effects)
                                    :administration/usergroups (usergroups/switch-to-usergroups effects)
                                    :administration/devices (devices/switch-to-devices effects)
                                    :administration/orgpages (orgpages/switch-to-orgpages effects)
                                    :administration/campaigns (campaigns/switch-to-campaigns effects)
                                    (metrics/switch-to-metrics effects))
                                  dissoc :administration/init)
        effects))))

Adam Kalisz17:07:52

If I don't modularize the code, everything works without issue.

thheller17:07:08

you should modularize the code though 😉

Adam Kalisz17:07:07

Yes, that would be nice...

thheller17:07:20

I mean there aren't that many things that can go wrong, so finding it shouldn't be that hard

Adam Kalisz17:07:14

Well, it kind of is for me, because it just is a pile of stuff I see for the first time. With basically a three line change in dependencies.

thheller17:07:41

well you didn't just upgrade shadow-cljs. you upgraded the clojurescript, closure-compiler and closure-library version as well

thheller17:07:02

and the closure stuff has had a few known breaking changes

thheller17:07:27

so totally possible that something broke that worked before. not a clue without finding your actual error

Adam Kalisz17:07:49

Yes 🙂 Btw. have rewritten the cookies as you recommended - but while testing my changes, I traced the broken administration back to this change.

Adam Kalisz17:07:30

(So before any of the other changes.)

Adam Kalisz17:07:12

What really strikes me is it doesn't happen when I do a release build locally

Pavel Klavík17:07:57

@thheller the entire code just follows https://code.thheller.com/blog/shadow-cljs/2019/03/03/code-splitting-clojurescript.html, does that still work for you in the latest shadow-cljs version?

thheller17:07:36

yes, no changes

Pavel Klavík18:07:38

I don't really understand why release build locally works while it is broken when we deploy to staging. So it looks like it would be related to script file not being served correctly, but we get 200 on it with no errors.

thheller20:07:46

guess you'll have to find out whats different in staging. maybe some sort of caching? did you verify that the hashes actually match and it doesn't end up using files from an old build or something?

Adam Kalisz18:07:00

Ok, if I include layout and admin into the app.html template, the administration loads. This obviously kind of breaks the point of modularization, but it shows the problem is most likely in the lazy loading part somewhere.

thheller18:07:59

do not do anything other than directly loading the JS files in your html

thheller18:07:05

no loader, no lazy. just load the files. that'll most likely already reveal the problem.

Pavel Klavík18:07:10

after adding it directly without lazy loading, everything works fine, except no modularization

Pavel Klavík18:07:30

there are no errors in the console

Adam Kalisz18:07:55

So what I did is, I left the lazy loader in the code just as it always was. I just added the admin.js into the app.html so it is basically loaded before the part where <someprojectname>.client.views.administration.core/administration is called. As Pavel wrote, this doesn't produce any errors and it works.

Apple19:07:49

hi i'm first time shadow user. i'm trying to convert from figwheel to shadow and run into this issue: pretty sure i have reagent/reagent in my deps.edn file. where to look for clues? [:app] Compiling ... -> Resolving Module: :main [:app] Build failure: The required namespace "react" is not available, it was required by "reagent/core.cljs".

Apple19:07:35

i'm not using npm/npx. shadow is started from a user clj like: (defn shadow-cljs [& args] (server/start!) (shadow/watch :app {:verbose true}))

Apple19:07:16

https://shadow-cljs.github.io/docs/UsersGuide.html#_dependencies says add reagent to shadow-cljs.edn. Instead i'm using an alias within deps.edn. Does it matter?

Adam Kalisz19:07:12

Perhaps require React e.g. (ns ... (:require ["react" :as react]))

Adam Kalisz19:07:40

And perhaps [reagent.core :as r] Also in your package.json add the dependency:

"dependencies": {
...
  "react": "^16.14.0",
<and optionally other dependencies with appropriate versions>
  "react-dom": "^16.14.0",
  "react-easy-crop": "^2.1.2",
  "react-motion": "^0.5.2",
  "react-transition-group": "^4.4.1",
...
},

Adam Kalisz19:07:56

And install the packages with npm/ npx.

Apple19:07:43

i was using figwheel and didnt have to deal with any package.json is shadow different in this aspect?

Adam Kalisz19:07:34

It looks for package.json for dependencies and other stuff more akin to how a JavaScript project would work.

Apple19:07:22

{:deps {...}} :paths ["src" "resources" "target"] :aliases {:dev-deps {:extra-deps {;;nrepl/nrepl {:mvn/version "0.8.3"} cider/cider-nrepl {:mvn/version "0.26.0"} reagent/reagent {:mvn/version "1.1.0"} cljs-ajax/cljs-ajax {:mvn/version "0.8.3"} cljsjs/react-bootstrap {:mvn/version "1.3.0-0"} thheller/shadow-cljs {:mvn/version "2.14.6"} ring/ring-devel {:mvn/version "1.9.3"}}} :dev {:main-opts ["-m" "user"] :extra-paths ["dev"]} :build {:main-opts ["-m" "figwheel.main" "-O" "advanced" "-bo" "dev"]} :prod {:main-opts ["-m" "web.core"]}}}

Adam Kalisz19:07:36

At least that is how I understand it. It is nothing too complex, just a json file, that describes your project.

Apple19:07:37

clj -M:dev-deps:dev

Apple19:07:10

i replace figwheel deps with shadow deps in :extra-deps

Apple19:07:19

and was hoping it'd just work

Apple19:07:55

so npm/npx is a hard dependencies with shadow-cljs?

Adam Kalisz19:07:56

I don't use deps.edn so can't really help you with that. Perhaps somebody else will step in...

thheller20:07:19

@UP82LQR9N yes, with shadow-cljs you need to use npm to handle npm dependencies. it does not support CLJSJS (which you probably relied on with figwheel)

thheller20:07:45

so you need to have node/npm installed

Apple20:07:25

got it. thank you!

Apple20:07:23

by reading https://shadow-cljs.github.io/docs/UsersGuide.html#_installation i had an impression that npm/npx was not mandatory.

thheller20:07:05

you do not have to use the shadow-cljs npm package. that is correct. but you'll still need npm for the actual npm packages such as react

👍 2
Apple02:07:53

I reduce my deps.edn to minimal w/o figwheel, and it still compiles. So cljs compiler should be able to handle all dependencies. shadow-cljs calls cljs.main to compile as well, right? If that's true then shadow should be able to compile as well, right? {:aliases {:dev-deps {:extra-deps {org.clojure/clojurescript {:mvn/version "1.10.866"} reagent/reagent {:mvn/version "1.1.0"} cljs-ajax/cljs-ajax {:mvn/version "0.8.3"} cljsjs/react-bootstrap {:mvn/version "1.3.0-0"}}}}} clj -M:dev-deps --main cljs.main -O advanced -c web.core

thheller05:07:08

@UP82LQR9N no. shadow does not use or support cljs.main. and if you your question is still about npm dependencies then the answer is still no. shadow-cljs does NOT support CLJSJS dependencies and you MUST install npm dependencies. I suggest reading https://shadow-cljs.github.io/docs/UsersGuide.html#js-deps if you want to learn more

Apple13:07:36

@thheller Excuse my English. What I was trying to say was that my *.cljs files can be compiled manually by invoking cljs compiler w/o figwheel(cljsjs or not), so that means the functions in cljs compiler(clojurescript-1.10.866.jar) alone did the job. I presume shadow-cljs uses and is built upon the same cljs compiler(clojurescript-1.xx.xxxxx.jar) to compile .cljs files so I don't understand why shadow-cljs cannot compile the same set of .cljs files.

Apple13:07:32

I'm curious in how it works the underlying connection between shadow-cljs and cljs compiler.

Apple13:07:01

cljs compiler perhaps uses google closure library to solve dependencies? shadow-cljs does not uses cljs compiler or closure library for dependencies but npm instead?

thheller14:07:43

yes, shadow-cljs uses the regular cljs compiler. react however is not a CLJS library. it is a JS library. the default cljs implementation will resolve those using a mechanism called foreign-libs which are provided by CLJSJS packages. shadow-cljs does not support those and instead provides JS deps directly from npm.

Apple14:07:20

I'm almost there with you.... you say "shadow-cljs uses the regular cljs compiler", while what regular cljs compiler can compile fails in shadow-cljs. Does that somehow mean shadow-cljs is not leveraging what's already available in regular cljs compiler?

thheller14:07:52

please re-read what I wrote and maybe read the docs ... I can only repeat myself over and over again.

thheller14:07:28

shadow-cljs uses the latest cljs compiler and it is quite intentional that it does NOT support CLJSJS.

thheller15:07:11

if you do not want to use npm at all then you probably shouldn't use shadow-cljs

Apple15:07:51

Thank you very much! I'll read them all to better understand how js dependency works.

Apple16:07:20

I sense that ":foreign-libs support" is probably it. I'm good now.

Adam Kalisz21:07:23

I don't understand the comments there

thheller21:07:19

if you want hot-reload to work you can't use root-el? I mean I can't describe it any clearer than I did in that comment?

Adam Kalisz21:07:29

Ok, thank you for the clarification. We will probably end up injecting the script tag into head to load the administration. We just can't figure out, why exactly the lazy load doesn't work just when we run the build for staging.

Adam Kalisz21:07:19

The order how Chrome loads stuff if I do a release build locally and in staging is different. It seems, in staging the JavaScript is loaded later than in the local build. I don't know why.