Fork me on GitHub
#shadow-cljs
<
2019-02-07
>
anmonteiro11:02:49

@thheller am I right in assuming that we don’t need to use cljs.core/resolve when code splitting with shadow?

thheller11:02:57

yes and no. all resolve really gives you is the var so if you want to call something from a namespace you otherwise have no access to that is one option

thheller11:02:14

or you can skip all that and call it via js/

thheller11:02:26

eg. you load a module that includes some.ns/foo. calling (some.ns/foo) may cause a compiler warning. but (js/some.ns.foo) is fine since it doesn't try to load analyzer data for the call

anmonteiro11:02:51

^ in this example you call (.then #(code-split.c/in-c "from-a"))

anmonteiro11:02:10

should that be wrapped in resolve then?

thheller11:02:40

I personally would never use resolve since produces too much code for what you really want

anmonteiro11:02:42

I know it will give a warning, the reason for my original question was to know whether shadow had a special case for this

thheller11:02:47

(eg. the entire var metadata)

anmonteiro11:02:16

what’s the tradeoff here though?

anmonteiro11:02:18

living with warnings?

anmonteiro11:02:47

I mean, I’m doing this via a macro so I could just add a ^::ana/no-resolve 😉

thheller11:02:52

(defn test-fn []
  (-> (loader/load "c")
      (.then #(js/code_split.c.in_c "from-a"))))

thheller11:02:17

works fine without warnings, just need to manually munge it

anmonteiro11:02:29

thoughts on my sneaky approach?

thheller11:02:38

I have plans for making this nicer but nothing concrete yet

👍 5
thheller11:02:54

sure if you want to write an extra macro for this 😉

anmonteiro11:02:44

yeah that’s a given

thheller11:02:47

I want this to be possible (loader/load 'code-split.c/in-c (fn [the-val] ...))

anmonteiro11:02:57

we need to write the macro anyway

anmonteiro11:02:06

otherwise we’re repeating too much code

thheller11:02:10

ie. load a specific var and let the compiler figure out which module it is in

anmonteiro11:02:20

that sounds nice

thheller11:02:58

most of my dynamic loading code ends up "cheating" like this currently

thheller11:02:05

so I want to get rid of that 😉

thheller11:02:07

the closure compiler folks are apparently working on dynamic import(...) support so that may be another solution in the future

thheller11:02:32

(more similar to what webpack does regarding code-splits)

anmonteiro11:02:39

not sure how that would work within Closure

anmonteiro11:02:51

but I’ve been away from the internals for a while

thheller11:02:15

yeah the entire :modules stuff would need a rework

thheller11:02:19

but could potentially end up with something simpler. I do like to have strict control over what my modules look like but webpack is certainly easier to use in that regard

thheller11:02:48

just use import(...) and let it split how it likes which is good enough for most cases

anmonteiro12:02:34

@thheller successfully code splitting with React.Suspense metal

orestis13:02:02

Ohh that’s nice @anmonteiro — are you using Reagent for that?

anmonteiro13:02:26

@thheller got a couple minutes to chat about module loading?

anmonteiro13:02:17

so right now the module loading support in shadow cljs assumes that the modules will be loaded from the current host / origin

anmonteiro13:02:33

this doesn’t really work for us because we host our scripts in a CDN

anmonteiro13:02:22

to make it work, we’d need support for a custom prefix in Shadow’s module loader

anmonteiro13:02:27

or the alternative might be to write our own

anmonteiro13:02:36

depending on what you’d want to support / maintain

anmonteiro13:02:23

or maybe this is already supported and I’m not aware of it

lmanolov15:02:23

Hello @thheller, importing of http://recharts.org/ stopped working on 2.7.26 and later versions. I have created a simple test case here: https://github.com/lmanolov/minimal-shadow-cljs-browser/commit/2a1cc97dba7b396f0a005121249db3671282f7dd On 2.7.25 everything works great. On 2.7.26 and later I get the following error:

lmanolov15:02:28

shadow.js.js:133 Uncaught TypeError: (intermediate value)(intermediate value)(intermediate value).default is not a constructor
    at Object.shadow$provide.module$node_modules$recharts$lib$util$Events (Events.js:13)
    at shadow.js.jsRequire (shadow.js.js:122)
    at Object.shadow$provide.module$node_modules$recharts$lib$chart$generateCategoricalChart (generateCategoricalChart.js:63)
    at shadow.js.jsRequire (shadow.js.js:122)
    at Object.shadow$provide.module$node_modules$recharts$lib$chart$LineChart (LineChart.js:9)
    at shadow.js.jsRequire (shadow.js.js:122)
    at Object.shadow$provide.module$node_modules$recharts$lib$index (index.js:376)
    at Object.shadow.js.jsRequire (shadow.js.js:122)
    at Object.shadow.js.require (shadow.js.js:158)
    at app.main.js:4

lilactown16:02:06

is there a way to tell shadow-cljs that cljs.core et. al. will be provided separately?

lilactown16:02:38

we have an npm library that is used both in a vanilla JS app with web pack, and a CLJS app with shadow-cljs

lilactown16:02:08

(it’s actually an bunch of separate libraries, some written in JS some in CLJS)

lilactown16:02:23

we’d like to be able to import into both as an npm lib

lilactown16:02:46

but right now it is (of course) importing all of cljs.core with the CLJS npm lib

thheller16:02:08

@anmonteiro this is sort of supported via :asset-path as it is just blindly prepended before the file url. so you could use :release {:asset-path ""} which will end up loading

anmonteiro16:02:26

I think I’ve figured that out too 🙂

anmonteiro16:02:46

I think I’m fighting this one last error now

thheller16:02:49

@lubo which recharts version is that? did you maybe upgrade that version too while upgrading shadow-cljs?

lmanolov16:02:46

@thheller the recharts version is 1.4.2 and I haven't changed it while upgrading shadow-cljs

thheller16:02:10

well in your example you are using a version range so are you sure that didn't change?

thheller16:02:24

I'm looking at it now, just want to make sure 😉

anmonteiro16:02:10

my module loading is failing even though I see a successful request for it in the network pane

lmanolov16:02:14

@thheller I just checked with the exact version "recharts": "1.4.2" and it works with 2.7.25 but fails with 2.7.26

thheller16:02:35

do you use the :minimize-require option added in that version?

lmanolov16:02:27

no. I have just changed the shadow-cljs version. shall I try this option?

thheller16:02:50

no I'm just ruling out places I need to look 😉

anmonteiro16:02:18

@thheller do you know how to enable the goog.log logger in prod?

anmonteiro16:02:26

besides setting DEBUG to true..

thheller16:02:59

not sure no

anmonteiro16:02:15

apparently goog.log.ENABLED

thheller16:02:25

@lubo found the problem, for some reason the compiler thinks the "events" package is unused and just doesn't emit the code for it

thheller16:02:46

I changed how that is detected so I guess I missed something

ccann17:02:07

noob question here: is it possible to access environment vars at compile time? (via cljs or shadow-cljs)

thheller17:02:29

via macros yes but should be avoided

ccann17:02:19

is the recommendation to avoid env vars entirely and use compiler optiosn?

thheller17:02:52

you can use :closure-defines {some.goog-define/var #shadow/env "FOO"} in the config

thheller17:02:25

that will use the FOO env var in place of that var

thheller17:02:51

so in the ns you just do (goog-define THING "default value")

ccann17:02:10

wow, okay, great! thank you

ccann17:02:22

I missed that in the docs

thheller17:02:30

this question has come way too often in recent times ... I'll definitely write some docs about this soon 🙂

thheller17:02:37

yeah its not in the docs 😉

ccann17:02:43

ahh there we go haha 🙂

ccann17:02:43

if you have a patreon or donations page or similar please let us know 😄

ccann17:02:39

is it possible that this technique ignores the default value of goog-define?

thheller18:02:48

well you are replacing it with the FOO env vars so yes thats kinda the point 🙂

ccann18:02:10

oh ok so if FOO isn’t set it won’t default to "default value"

thheller22:02:58

I changed this behavior in 2.7.30 and now no FOO will actually use the default value instead of an empty string.

thheller18:02:28

if you only want to do that for release builds you can do :release {:closure-defines {some.goog-define/var #shadow/env "FOO"}}

thheller18:02:49

yes it will use an empty value if FOO is not set

thheller18:02:39

all this is a bit messy at the moment. I have plans to make this a bit cleaner

thheller18:02:10

@lubo should be fixed in 2.7.29. thanks for the report.

lmanolov19:02:16

@thheller I checked it with 2.7.29 and it works perfectly. Thank you very much for the quick fix!

anmonteiro19:02:36

@thheller I’m absolutely in love with:

Module Entry "ladder.views.api" was moved out of module ":static-pages".
It was moved to ":main" and used by #{:static-pages :main}.

anmonteiro19:02:05

tells me I need to remove a require

anmonteiro19:02:13

which I tend to forget 😓

thheller19:02:29

hehe yeah me too 🙂

anmonteiro19:02:56

@thheller the only thing that feels weird to me having done code splitting in bare CLJS is how module ids become strings out of keywords

anmonteiro19:02:06

maybe this is for historical reasons / backwards compat?

thheller19:02:54

I added a new thing today which might be useful to some people here. https://clojureverse.org/t/using-none-code-resources-in-cljs-builds/3745

thheller19:02:39

@anmonteiro the shadow.loader is written in JS since I wanted to be able to use it without CLJS. eg. create a tiny initial loader that then loads the rest

thheller19:02:06

cljs.loader always makes the assumption that cljs.core is in the base which I didn't want to force

thheller19:02:26

but yeah it should probably support keywords, I don't like that part either

anmonteiro19:02:41

from what I see it just gets an argument and forwards it

anmonteiro19:02:47

so that argument could actually be anything

thheller19:02:13

no it must be a string since the module manager expects a string

anmonteiro19:02:14

maybe if it were a keyword you’d have to str it?

anmonteiro19:02:31

yeah, and that would introduce a dependency on cljs.core

anmonteiro19:02:32

that makes sense

thheller19:02:41

yeah but the real problem I want to remove is that you need to remember which module to load

thheller19:02:54

you should just be loading namespaces and let it figure out which module it is in

thheller19:02:28

it could still call id.toString() and remove : if it starts with that

thheller19:02:45

that would make it work with keywords without depending on cljs.core

mhuebert23:02:24

Looks great!