shadow-cljs

https://github.com/thheller/shadow-cljs | https://github.com/sponsors/thheller | https://www.patreon.com/thheller
Adam Kalisz 2021-07-05T16:10:35.439200Z

@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 Kalisz 2021-07-05T16:11:39.440Z

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.

thheller 2021-07-05T16:16:01.440700Z

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

thheller 2021-07-05T16:17:00.441Z

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

Adam Kalisz 2021-07-05T16:52:02.444Z

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 <http://fully.qualified.name/component|fully.qualified.name/component>).
  :lazy/state - The loading state while the component's source code is loaded."
  [{:lazy/keys [loadable state]}]
  [:&gt; react/Suspense {:fallback (r/as-element (if state
                                                [loading/loading {:loading/state state}]
                                                [:div]))}
   [:&gt; (component loadable)]])
The error isn't very specific unfortunately - or at least I don't see any useful details.

thheller 2021-07-05T16:55:11.444600Z

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

Adam Kalisz 2021-07-05T17:04:27.444800Z

No 404 I can see...

thheller 2021-07-05T17:05:25.445500Z

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

thheller 2021-07-05T17:05:44.446Z

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

thheller 2021-07-05T17:05:53.446200Z

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

thheller 2021-07-05T17:07:17.447600Z

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

Adam Kalisz 2021-07-05T17:07:53.448100Z

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 Kalisz 2021-07-05T17:10:16.448200Z

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

Adam Kalisz 2021-07-05T17:19:52.448800Z

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

thheller 2021-07-05T17:22:08.449300Z

you should modularize the code though 😉

Adam Kalisz 2021-07-05T17:23:07.450200Z

Yes, that would be nice...

thheller 2021-07-05T17:23:20.450500Z

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

Adam Kalisz 2021-07-05T17:24:14.451700Z

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.

thheller 2021-07-05T17:25:41.452800Z

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

thheller 2021-07-05T17:26:02.453400Z

and the closure stuff has had a few known breaking changes

thheller 2021-07-05T17:26:27.454200Z

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

Adam Kalisz 2021-07-05T17:26:49.454700Z

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

Adam Kalisz 2021-07-05T17:27:30.455100Z

(So before any of the other changes.)

Adam Kalisz 2021-07-05T17:28:12.455700Z

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

2021-07-05T17:28:39.455800Z

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

2021-07-05T17:30:56.456Z

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

Adam Kalisz 2021-07-05T17:48:07.456200Z

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

2021-07-05T17:56:57.457Z

@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?

thheller 2021-07-05T17:57:36.457400Z

yes, no changes

2021-07-05T18:06:38.458500Z

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.

Adam Kalisz 2021-07-05T18:27:00.459900Z

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.

thheller 2021-07-05T18:29:59.460200Z

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

thheller 2021-07-05T18:30:05.460400Z

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

2021-07-05T18:33:10.461Z

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

2021-07-05T18:33:30.461300Z

there are no errors in the console

Adam Kalisz 2021-07-05T18:37:55.463300Z

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.

Apple 2021-07-05T19:04:49.464900Z

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 ... -&gt; Resolving Module: :main [:app] Build failure: The required namespace "react" is not available, it was required by "reagent/core.cljs".

Apple 2021-07-05T19:06:35.465100Z

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

Apple 2021-07-05T19:14:16.465400Z

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 Kalisz 2021-07-05T19:16:12.465600Z

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

Adam Kalisz 2021-07-05T19:19:40.465800Z

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

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

Adam Kalisz 2021-07-05T19:20:56.466100Z

And install the packages with npm/ npx.

Apple 2021-07-05T19:21:43.466300Z

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

Adam Kalisz 2021-07-05T19:23:34.466500Z

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

Apple 2021-07-05T19:24:22.466700Z

{: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 Kalisz 2021-07-05T19:24:36.466900Z

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

Apple 2021-07-05T19:24:37.467100Z

clj -M:dev-deps:dev

Apple 2021-07-05T19:25:10.467300Z

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

Apple 2021-07-05T19:25:19.467500Z

and was hoping it'd just work

Apple 2021-07-05T19:25:55.467700Z

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

Apple 2021-07-05T19:27:50.467900Z

https://shadow-cljs.github.io/docs/UsersGuide.html#_library this is the way i use

Adam Kalisz 2021-07-05T19:29:56.468100Z

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

thheller 2021-07-05T20:24:19.468300Z

@zengxh 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)

thheller 2021-07-05T20:24:45.468500Z

so you need to have node/npm installed

Apple 2021-07-05T20:26:25.468700Z

got it. thank you!

thheller 2021-07-05T20:26:46.468900Z

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?

Apple 2021-07-05T20:29:23.469100Z

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

thheller 2021-07-05T20:34:05.469300Z

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

👍 1
Adam Kalisz 2021-07-05T21:09:09.470200Z

@thheller shouldn't root-el be used in the function here: https://github.com/thheller/code-splitting-clojurescript/blob/master/src/main/demo/util.cljs ?

Adam Kalisz 2021-07-05T21:09:23.470600Z

I don't understand the comments there

thheller 2021-07-05T21:13:19.470900Z

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 Kalisz 2021-07-05T21:25:29.474700Z

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 Kalisz 2021-07-05T21:27:19.476Z

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.