This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-04-06
Channels
- # announcements (33)
- # babashka (13)
- # babashka-sci-dev (23)
- # beginners (94)
- # calva (105)
- # cider (37)
- # circleci (1)
- # clj-kondo (45)
- # cljs-dev (59)
- # cljsrn (2)
- # clojure (145)
- # clojure-czech (1)
- # clojure-europe (19)
- # clojure-nl (18)
- # clojure-norway (13)
- # clojure-portugal (1)
- # clojure-uk (5)
- # clojurescript (19)
- # community-development (2)
- # conjure (3)
- # copenhagen-clojurians (1)
- # core-async (34)
- # data-science (6)
- # datomic (25)
- # emacs (43)
- # fulcro (19)
- # graalvm (7)
- # graalvm-mobile (12)
- # graphql (10)
- # honeysql (3)
- # hyperfiddle (3)
- # improve-getting-started (2)
- # interop (20)
- # kaocha (3)
- # lsp (16)
- # meander (7)
- # off-topic (22)
- # other-languages (14)
- # portal (15)
- # releases (1)
- # rewrite-clj (2)
- # ring (1)
- # shadow-cljs (119)
- # spacemacs (19)
- # sql (65)
- # testing (4)
- # tools-deps (11)
- # xtdb (29)
Hello! I’ve been testing shadow-cljs and bumped into a similar issue reported by others with not being able to import css-modules (npm-libraries that basically just wrap css-files). To work around the issue I went with a solution suggested in this thread with creating a separate js-bundle that only contains the module containing css which is then prebuilt with webpack: https://clojurians.slack.com/archives/C6N245JGG/p1603638343132300 Is creating a separate bundle still close to the “best practise” for getting around this problem?
hard to say. some css-modules are precompiled so the code has foo.css
require but also a foo.css.js
file exists. those should work fine
Cool, thanks! I was testing a design system that had react components and styles as separate libraries, so the css-one seems to only contain styles. So I went the “dual bundle”-route 😊
I hope you mean the optjon #2 described here https://code.thheller.com/blog/shadow-cljs/2020/05/08/how-about-webpack-now.html
Sort of! Since I’m only hacking to improve my Clojurescripting at the moment I just used Webpack to build a js-file with only one import (the css) and reference that in index.html. I guess you could call it a bastardized version of option 2 🙈
Right, I’ll go with option 2 for real if I get beyond the hacking stage with this. Thanks for the info!
Whelp, I couldn’t stop thinking about this so I ended up doing it the “correct way” and it worked surprisingly well! Now I have shadow-cljs watching with
npx shadow-cljs watch app
and webpack watching with
npx webpack watch
Very cool! :thumbsup:
One thing I did try to probe the limitations is to comment out and re-add a js-library, which rebuilds the target js-file and in turn causes webpack to rebuild the “lib-file”.
I get the impression hot reloading doesn’t work in that case? Or is there some magic that can be applied to fix even that scenario?Oh well, I’m mostly wondering for sake of curiosity, but since the js-libraries won’t change often this works damn great 👏
I'm using lazy loading for Reagent components as described in https://code.thheller.com/blog/shadow-cljs/2019/03/03/code-splitting-clojurescript.html, and for some reason it works in Firefox but not in Chromium. My code is as follows:
(ns website.my-component)
(defn <my-component>
[]
[:div "Hello world!"])
(ns website.core
(:require ["react" :as react]
[shadow.lazy :as lazy]
[reagent.core]
[reagent.dom]))
(def *<my-component>
(lazy/loadable website.my-component/<my-component>))
(defn <app-root>
[]
[:> react/Suspense {:fallback (reagent.core/as-element [:div "Loading..."])}
[:>
(if (lazy/ready? *<my-component>)
(reagent.core/reactify-component (fn [& _] [@*<my-component>]))
(react/lazy
#(do (prn "loading step 1")
(-> (lazy/load *<my-component>)
(.then (fn [_<elem>]
(prn "loading step 2")
#js {:default (reagent.core/as-element
(fn [& _]
(prn "loading step 3")
[@*<my-component>]))}))))))]])
(defn init-app!
[]
(reagent.dom/render [<app-root>] (.getElementById js/document "app")))
Firefox prints both "loading step n" statements, whereas Chromium only prints "loading step 1". No errors are logged to the console in either case. Any idea what's wrong?@thheller I edited the code. Does that help?
def
* 😉
hmm.. not sure I follow
I am using react/lazy
just like in https://github.com/thheller/code-splitting-clojurescript/blob/master/src/main/demo/util.cljs#L16 if that's what you mean
use this part I mean https://github.com/thheller/code-splitting-clojurescript/blob/master/src/main/demo/util.cljs#L15
pulling it into the render function doesn't work since that recreates it every time never allowing react.lazy to do what it does
ah okay
perhaps it's getting garbage-collected in Chrome then?
yeah like I wrote, no errors
I'll try def
ing the react/lazy
call and see if that resolves it
@thheller I changed the code to the following, but it didn't help:
(ns website.my-component)
(defn <my-component>
[]
[:div "Hello world!"])
(ns website.core
(:require ["react" :as react]
[shadow.lazy :as lazy]
[reagent.core]
[reagent.dom]))
(def *<my-component>
(lazy/loadable website.my-component/<my-component>))
(def lazy-component
(react/lazy
#(do (prn "loading step 1")
(-> (lazy/load *<my-component>)
(.then (fn [_]
(prn "loading step 2")
#js {:default (reagent.core/reactify-component
(fn [& _]
(prn "loading step 3")
[:div "hello"]))}))))))
(defn <app-root>
[]
[:> react/Suspense {:fallback (reagent.core/as-element [:div "Loading..."])}
[:> lazy-component]])
(defn init-app!
[]
(reagent.dom/render [<app-root>] (.getElementById js/document "app")))
It seems to me that the problem isn't really in this code, but somewhere else. In Firefox, the module JS gets loaded after the "loading step 1" printout, but in Chrome it's not loaded at all.
sorry, what extra stuff?
okay yeah sure
the point of that was to avoid calling react/lazy
on every render
now that I moved react/lazy
to a def
I forgot to get rid of it
either way, I got rid of it now and it didn't make a difference
just use (js/console.log ...)
instead. async printing is icky if you expect output to show up in the REPL
okay, sure
that doesn't make a difference in this case though
I figured I'd eliminate the possibility that there was something wrong when the code was being rendered
to be clear, this shows up as an empty single-page div with "Loading..." in Chrome, and "hello" in Firefox
it does not in Chrome
in Firefox, it does
Out of a sudden I am seeing this error, what does it mean?
error: Error: Unable to resolve module from /Users/matthew/Drive/dev/mobile2/target/app/index.js: could not be found within the project or in these directories:
node_modules
> 1 | var $CLJS = global;
| ^
2 | var shadow$start = new Date().getTime();
3 | var shadow$provide = global.shadow$provide = {};
4 | var goog = global.goog = {};
I don't know. as I said this is not a shadow-cljs error. without more context I cannot guess further.
yes, but under what circumstances? like what is the full log? what command did you run? what was the state of cljs compiliation at the time of that error
maybe just try restarting metro. I really don't know. I don't use react-native so my guesses are very limited.
@thheller FYI I managed to get it working by restarting my computer, cleaning my browser cache, and deleting .shadow-cljs
and all build files
not sure which one of those fixed it 🙂
apologies for wasting your time
(my hunch is that Chromium had somehow cached an old JS build file, that it wasn't letting go despite me hard refreshing the page)
if you use the :dev-http
server that can't happen since it sets the proper cache headers
yeah, that's probably it
I'll double check my cache headers
Every time if a namespace mismatches, shadow will get stuck and stops compiling even if after I fixed the naming issue:
Also, what does this line mean?
$CLJS.shadow$js["../../resources/assets/landing-bg.jpg"] = function() { return require("../../resources/assets/landing-bg.jpg"); };
Reason I asked this is, in my source code, if I replace the line
(defonce landing-bg (js/require (config/asset-path "landing-bg.jpg")))
with
(defonce landing-bg (js/require "../../resources/assets/landing-bg.jpg"))
Then the
$CLJS.shadow$js["../../resources/assets/landing-bg.jpg"] = function() { return require("../../resources/assets/landing-bg.jpg"); };
will be gone.
In my code, config/asset-path
is a macro. The output of (config/asset-path "landing-bg.jpg")
is exactly “../../resources/assets/landing-bg.jpg”.Further more background on this, the react native require only supports literal strings and dynamic variables are not supported, (see https://reactnative.dev/docs/images#:~:text=In%20order%20for%20this%20to%20work%2C%20the%20image%20name%20in%20require%20has%20to%20be%20known%20statically). So I think I might go with macro so that it will be expanded to literal strings.
However, the generated file missies the $CLJS.shadow$js["../../resources/assets/landing-bg.jpg"] = function() { return require("../../resources/assets/landing-bg.jpg"); };
line compared to the case of a vanilla (defonce landing-bg (js/require "../../resources/assets/landing-bg.jpg"))
.
Shadow is already expanding the macro, for example,
(defonce landing-bg (js/require (config/asset-path "landing-bg.jpg")))
gets converted to
(defonce landing-bg (js/require "../../resources/assets/landing-bg.jpg"))
It’s just this piece is missing
$CLJS.shadow$js["../../resources/assets/landing-bg.jpg"] = function() { return require("../../resources/assets/landing-bg.jpg"); };
I think (defasset landing-bg "landing-bg.jpg")
is a macro you could write instead that just emits the (defonce landing-bg (js/require "../../resources/assets/landing-bg.jpg"))
for you
the compiler is looking for a call to js/require
with a string argument. nothing else
I see, so you were saying the extra creation of this line
$CLJS.shadow$js["../../resources/assets/landing-bg.jpg"] = function() { return require("../../resources/assets/landing-bg.jpg"); };
is not possible in the current cljs/shadow compiler.you can just clone this too https://github.com/shadow-cljs/shadow-cljs.github.io