Fork me on GitHub
#shadow-cljs
<
2024-03-25
>
Ben Lieberman00:03:41

hey I'm using the :graaljs build target to do some React SSR but it looks like shadow pulls in the browser build of react-dom? I see this when I eval in GraalJS

shadow-cljs - failed to load module$node_modules$react_dom$cjs$react_dom_server_browser_development
I tried the
:js-options {:resolve {"react-dom/server" {:target :npm
                                                   :require "react-dom/server.js"}}}
thing. But compilation fails with package react-dom had exports, but could not resolve ./server.js. That doesn't seem to be true from looking at my node_modules. I'm actually not sure if that's how this option is even supposed to be used, though.

thheller08:03:10

shadow doesn't pull in anything. your build does.

thheller08:03:29

:resolve affects the build, but shadow-cljs - failed to load is a runtime error. it pulled in the correct file already, it didn't need help on that front

thheller08:03:41

usually there should be the causing exception printed somewhere

thheller08:03:02

graal is a shitty JS engine and I do not recommend using it. you'll have much more luck with node

1
ghaskins20:03:27

@thheller I thought I might share a shadow-cljs+WASM success since we spoke about it a month or so ago: https://github.com/manetu/lambda-sdk-clj

ghaskins20:03:32

Also, thanks again on the guidance such as :target :esm and :runtime :custom

thheller20:03:54

well if you are setting :custom but don't actually provide any then you might as well just set :devtools {:enabled false}

ghaskins20:03:35

ah, what will that do? shrink the output a bit?

ghaskins20:03:42

(it all seems to work as it is, fwiw)

thheller20:03:23

just disabled the devtools entirely, so in essence the same as :runtime :custom and not actually setting :devtools {:client-ns ...}

thheller20:03:11

the idea behind :runtime :custom is that you can provide an implementation that can connect back to the shadow-cljs websocket and provide REPL/hot-reload

thheller20:03:28

if you are not gonna do that at all anyway then just set :devtools {:enabled false}

ghaskins20:03:36

ah, got it. I am not even trying to do anything that sophisticated (yet)

ghaskins20:03:45

ok, will give that a try. Ty!

ghaskins20:03:05

I didnt see any material changes good or bad, so I went forward with your suggestion: https://github.com/manetu/lambda-sdk-clj/pull/5

thheller20:03:16

note that its disabled for release builds anyways, so technically you don't even need that

jeaye22:03:45

Hey folks. I'm trying to port a reagent SPA I have to https://single-spa.js.org/, for reasons outside of my control. It looks like single-spa uses https://github.com/systemjs/systemjs, which is able to load its own systemjs modules as well as UMD modules. This leads me to wonder what the heck type of module I'm getting when I use shadow and target :browser. I've been digging around the shadow docs, issues, and threads in here to answer my questions, but I'm still unsure on this one specifically. shadow doesn't seem to use the same JS terminology for these modules as the mainstream JS tooling.

hifumi12305:03:15

:target :browser spits out an optimized form of ClojureJS as far as I understand

hifumi12305:03:24

the output is equivalent to whatever the closure compiler emits, with some hacks employed by shadow in order to prevent npm code from going through advanced optimizations

hifumi12305:03:09

I think you may be able to port the reagent SPA by using :js-provider :external then relying on webpack to produce UMD output this guide seems useful for that https://remarkablemark.org/blog/2016/09/22/webpack-build-umd/

jeaye05:03:14

Thanks for the response. If I need to go through webpack, I can have it output systemjs modules.

thheller07:03:02

:browser isn't equivalent to any common JS module type, its basically custom

thheller07:03:28

:npm-module is commonjs

thheller07:03:33

:esm is well .. ESM

thheller07:03:31

> We recommend a setup that uses in-browser ES modules + import maps (or SystemJS to polyfill these if you need better browser support). This setup has several advantages:

thheller07:03:42

so seems like :esm is the best fit?

thheller07:03:29

:js-provider :external is only concerned with packages JS dependencies, so it would do nothing to integrate the CLJS code into the systemjs model

thheller07:03:16

technically there could be a :target :systemjs since that is what this whole target abstraction is for, "wrapping" outputs to integrate into other systems. it isn't however exactly trivial to write one and I have never looked into what systemjs actually is

jeaye17:03:43

Thanks so much for the breakdown. Yeah, not seeing :systemjs support was not a surprise, since it's just yet another way to do modules in JS. I'll give :esm a go and hope that it's enough.

thheller20:03:12

note that by default :esm will try to bundle all dependencies, for those it should not bundle you can set :js-options {:keep-as-import #{"react"}}, so that they remain as regular import and work with importmaps as the recommended setup suggests

jeaye20:03:59

Ah, so I don't need to do something like:

:js-options {:resolve {"react" {:target :global
                                :global "React"}
                      "react-dom" {:target :global
                                    :global "ReactDOM"}}}

thheller20:03:45

nope. well, depends I guess. dunno how they are provided 😛

jeaye20:03:16

Thanks. That's a helpful tip.

thheller20:03:42

you can also set :js-options {:js-provider :import} which will everything as import and don't bundle any npm deps

jeaye20:03:13

Most of my deps I'll want bundled, but the container that's running the single-spas will have react, so I'll figure out if I want :resolve or :keep-as-import for that.

thheller20:03:45

seems like a core idea behind singlespa yes

jeaye20:03:24

Microservices have found their way into browsers. :man-shrugging: