Fork me on GitHub
#shadow-cljs
<
2019-06-21
>
timovanderkamp09:06:58

Hi, Im running 2 react apps with shadow-cljs on 1 document which is causing react-errors. Im using output-wrapper configurations for both apps https://shadow-cljs.github.io/docs/UsersGuide.html#output-wrapper. The react error is telling me that there are probably multiple copies of React loaded

thheller09:06:31

well are you?

thheller09:06:54

shadow-cljs will include one unless you configure it otherwise

thheller09:06:02

same for the other react parts I guess?

timovanderkamp09:06:49

Both have an own version of React

timovanderkamp09:06:20

which might be a problem

timovanderkamp09:06:51

https://github.com/thheller/shadow-cljsjs/blob/master/src/main/cljsjs/react.cljs Could this be a problem? That each app exports react to the global variable “React”

thheller09:06:27

yes that would be a problem. but having 2 versions of react on the page is the actual problem

thheller09:06:36

why are the 2 builds not combined?

thheller09:06:56

you are duplicating everything. not just react but also react-dom and probably other dependencies

thheller09:06:05

adding a lot of unncessary bytes overall

mitchelkuijpers09:06:23

This is because we are creating a addon for JIRA, where everyone needs to package it's own version

👆 4
mitchelkuijpers09:06:18

Which absolutely sucks but that is we way Atlassian wants us to do this...

thheller09:06:42

then you must avoid the cljsjs.* packages. using (:require ["react" :as x]) will not expose the global

mitchelkuijpers09:06:12

I was afraid of this, so we need to patch Fulcro 😞

thheller09:06:29

well you can try using the require redirect and use react from a different lib

thheller09:06:07

but then you are relying on some foreign defined version of react which is kinda bad 😛

mitchelkuijpers09:06:39

Yeah and fulcro contains code like this: js/React.createElement

mitchelkuijpers09:06:59

I don't think we can patch that right?

thheller09:06:32

in a release build you can maybe cheat that but in development no

mitchelkuijpers09:06:42

Oh that would be fine 😛

mitchelkuijpers09:06:41

I could probably just add a string/replace then

thheller09:06:08

well in a release build using output-wrapper everything is in its own scope

thheller09:06:16

so the js/React only needs to come from that scope

thheller09:06:52

so in theory if you get var React = the.actual.react; into the output-wrapper that should be fine

mitchelkuijpers09:06:13

that makes sense

thheller09:06:35

so what I would probably try is creating a dummy ns that abuses js* and is loaded first

thheller09:06:41

(ns hack.react (:require ["react" :as react] ["react-dom" :as react-dom])) (js* "var React = {};" react) (js* "var ReactDOM = {};" react-dom)

thheller09:06:55

still need to replace the cljsjs shims so they don't export a global

mitchelkuijpers09:06:04

That will be easy

thheller09:06:14

load that namespace first before anything else loads react

mitchelkuijpers09:06:16

Nice I will try this out, thank you so much

thheller09:06:48

either by using :modules {... {:entries [hack.react ]}} or by just requiring it first in whatever ns is loaded first

mitchelkuijpers09:06:20

Awesome, will report back if it works

mitchelkuijpers09:06:31

If you are interested in that 😛

thheller09:06:47

yeah let me know. maybe I can come up with other hacks if it doesn't 😉

parrot 8
mitchelkuijpers13:06:48

Well this is annoying:

2019-06-21 15:57:52.567 - INFO] duplicate resource cljsjs/react/dom.cljs on classpath, using jar:file:/home/mitchel/.m2/repository/thheller/shadow-cljsjs/0.0.18/shadow-cljsjs-0.0.18.jar!/cljsjs/react/dom.cljs over file:/home/mitchel/Development/atlas-crm/atlas-crm-kit/src/cljsjs/react/dom.cljs
[2019-06-21 15:57:52.577 - INFO] duplicate resource cljsjs/react.cljs on classpath, using jar:file:/home/mitchel/.m2/repository/thheller/shadow-cljsjs/0.0.18/shadow-cljsjs-0.0.18.jar!/cljsjs/react.cljs over file:/home/mitchel/Development/atlas-crm/atlas-crm-kit/src/cljsjs/react.cljs

mitchelkuijpers13:06:59

it keeps choosing the wrong one

mitchelkuijpers13:06:26

Hmm wait I think order matters just as in maven

mitchelkuijpers14:06:24

Stupid classpaths

mitchelkuijpers14:06:17

I fixed it by forking shadow-cljsjs

mitchelkuijpers14:06:40

Unfortunately it does not work:

mitchelkuijpers14:06:25

Oh and for extra fun we use modules, so it generates this:

mitchelkuijpers15:06:12

So if you have any other hacks I am all ears

thheller16:06:00

oh that should have been (js* "var React = ~{};" react)

thheller16:06:14

but yeah with modules things might get trickier

thheller16:06:27

but it might work so definitely try it first

thheller16:06:36

ah no nvm it won't work

thheller16:06:07

well the global is the problem so its not easily fixable

mitchelkuijpers20:06:49

Thnx will think about this some more

mitchelkuijpers12:06:30

Damn it seems to work!

mitchelkuijpers12:06:34

Nope false alarm 😞

mitchelkuijpers12:06:36

It is weird this: (js* "var React = ~{};" react) results in React=null;

thheller20:06:00

it isn't for me?

thheller20:06:13

(js* "var React = ~{};" r)

(js/console.log "react" r js/React (identical? r js/React))

thheller20:06:24

with (:require ["react" :as r])

mitchelkuijpers09:06:06

So I have created this:

(ns atlas-crm.server.react-hack
  (:require ["react" :as r]
            ["react-dom" :as rd]))

(js* "var React = ~{};" r)
(js/console.log r)
(js* "var ReactDOM = ~{};" rd)
(js/console.log rd)
And this results in:
React=null;console.log(nl_avisi_atlascrm.A0);ReactDOM=null;console.log(nl_avisi_atlascrm.L7a);

thheller09:06:30

that makes no sense at all.

thheller09:06:09

can you try changing the name? (js* var WTF = ~{};" r) or so

thheller09:06:19

maybe it has some sort of conflict on the React name?

mitchelkuijpers09:06:58

I also find this in resulting JS now: nl_avisi_atlascrm.A0.createElement,a,b,c

mitchelkuijpers09:06:03

So that seems correct

mitchelkuijpers09:06:18

I am trying it out now with the new name

mitchelkuijpers09:06:19

omg the var definition fixes al of the renaming.. that is interesting

mitchelkuijpers09:06:31

WTF=null;console.log(nl_avisi_atlascrm.A0);

mitchelkuijpers09:06:34

And now the rest of the code is React.createElement,a,b,c again

thheller09:06:27

I guess its a problem in the closure compiler since React is declared in the externs and you are not allowed to reassign it maybe?

mitchelkuijpers09:06:41

Ah maybe that is problem, but it does rename all the references

mitchelkuijpers09:06:44

which is good 😛

mitchelkuijpers09:06:54

For our use case

thheller09:06:27

rename how?

mitchelkuijpers09:06:50

So our code now contains instead of:

React.createElement,a,b,c
nl_avisi_atlascrm.A0.createElement,a,b,c

thheller09:06:14

so you are not using the global in those cases?

thheller09:06:45

you are phrasing this confusing. I don't know what you mean

mitchelkuijpers09:06:46

All of the cljsjs code get replaced by the correct var

thheller09:06:53

> And now the rest of the code is React.createElement,a,b,c again

thheller10:06:01

which is it? your last statement looks like you mean the other case

mitchelkuijpers10:06:39

After I added the

(js* "var React = ~{};" r)
(js* "var ReactDOM = ~{};" rd)
It changed all the code to:
nl_avisi_atlascrm.A0.createElement,a,b,c

thheller10:06:58

thats exactly what you want

mitchelkuijpers10:06:06

Yeah that is awesome

mitchelkuijpers10:06:11

but unexpected I guess?

thheller10:06:34

depends, what is the definition of nl_avisi_atlascrm.A0?

thheller10:06:33

it isn't unexpected. it is exactly how :modules is supposed to work. I just don't get why it is assigning var React=null;

thheller10:06:36

that makes no sense to me

mitchelkuijpers10:06:00

nl_avisi_atlascrm.A0=(6)

thheller10:06:17

that looks correct to me

thheller10:06:34

is it probably a renamed shadow.js.jsRequire call

mitchelkuijpers10:06:35

Awesome, yeah the only weird part is that it assignes React=null

thheller10:06:45

try with shadow-cljs release build --pseudo-names

thheller10:06:07

its fine if it assigns React to null if its never used again

thheller10:06:21

it is not fine if something else still references React

mitchelkuijpers10:06:23

Yeah but it does it in the global scope

mitchelkuijpers10:06:32

Yeah that is the only problem

mitchelkuijpers10:06:52

But I could even make regex after which removes that code 😛

thheller10:06:22

but there should be no react in the global scope? isn't the goal to get rid of that?

mitchelkuijpers10:06:02

So we are embedded in another application, So if that application decides to use React we don't want to set that to null

mitchelkuijpers10:06:44

nl_avisi_atlascrm.$module$node_modules$react$index$$.createElement.apply(null, $arr$jscomp$166$$);

mitchelkuijpers10:06:50

this seems correct :thumbsup:

thheller10:06:36

also check the assignment of nl_avisi_atlascrm.$module$node_modules$react$index$$

mitchelkuijpers10:06:18

Sorry I gotta go be back in a hour or so

mitchelkuijpers10:06:32

Fighting with my terminal and escaping

thheller10:06:42

if it works I'd just regex out the react=null assignment for now. no idea where that is coming from or if that somehow can be removed otherwise

mitchelkuijpers10:06:47

Yeah we will be doing that probably

mitchelkuijpers10:06:09

I found this btw:

nl_avisi_atlascrm.$module$node_modules$react$index$$ = nl_avisi_atlascrm.$shadow$js$require$$(6); 

mitchelkuijpers10:06:49

That seems to be correct

mitchelkuijpers10:06:39

I had to fork shadow-cljsjs btw to get this working

mitchelkuijpers10:06:10

https://github.com/mitchelkuijpers/shadow-cljsjs So do you want me to try removing the externs to see if it assigns React?

thheller10:06:31

why did you need to fork for that? just put the files into your source paths?

mitchelkuijpers10:06:56

I did that but shadow kept insisting that the shadow-cljsjs files win

thheller10:06:17

files on the source path should win always?

mitchelkuijpers10:06:28

No we have a shared modules

mitchelkuijpers10:06:39

because we have about 6 projects who work like this

mitchelkuijpers10:06:00

And we don't want to copy all of this stuff around

mitchelkuijpers14:06:50

It all works, thank you so much for all the help

👍 4
colinkahn15:06:27

I’m having some trouble importing an npm package, specifically router5. When I require it via ns (like: (:require ["router5" :as router5]))) and try to use one of the exported functions (`createRouter`) I get TypeError: module$node_modules$router5$dist$index.createRouter is not a function, and looking at the actual export it is in fact an empty object. But, if I’m in the browser repl and do (require '["router5" :as router5]) I can use the exported functions just fine.

colinkahn15:06:02

Also, node_modules/router5/dist/index.js is a commonjs file, with exports like:

exports.RouteNode = RouteNode;
exports.transitionPath = transitionPath__default;
exports.createRouter = createRouter;
exports.cloneRouter = cloneRouter;
exports.constants = constants;
exports.errorCodes = errorCodes;
exports.default = createRouter;

colinkahn15:06:44

Actually if I change those exports to be module.exports = everything works fine…

colinkahn15:06:48

Still weird that it works when I do (require ...)

thheller16:06:00

@colinkahn add a (js/console.dir router5) to the file using it

thheller16:06:08

seems to me like it should be working when it works in the REPL?

colinkahn16:06:00

@thheller not sure what’s different now, but yeah, console.dir worked, and then console.log worked, and now everything works. Is there some cache besides the output dir that could be holding onto some local change? I’m not eager to get it to break again but it is a bit worrisome that it didn’t work one minute and now it does

Ahmed Hassan16:06:11

How we can build a library to be used by ClojureScript projects with Shadow-cljs?

Ahmed Hassan16:06:08

One option is node-library which I think is npm deployable. But how can a .jar file be made which can be deployed on Clojars?

lilactown17:06:27

@ahmed1hsn shadow-cljs doesn’t provide a way of bundling CLJS for publishing as a library. I typically use leiningen and lein deploy to publish to e.g. clojars or other maven repo

✔️ 4
lilactown17:06:44

the important thing is, you don’t need to compile your clojurescript code at all

✔️ 4
lilactown17:06:02

you just put the CLJS sourcefiles in a jar and upload it

✔️ 4
Ahmed Hassan17:06:40

Thanks @lilactown. What about npm dependencies I required in the deployed library? Will users of library have to include npm modules in package.json and just start using it?

Ahmed Hassan17:06:19

And if there are other CLJS dependencies with .jar format, they can be included in :dependencies in project.clj. Right?

lilactown18:06:51

CLJS dependencies can be included in project.clj and will be automatically installed yeah.

👍 4
lilactown18:06:37

There's not a dependable way to install npm dependencies automatically, so I usually include it as part of the installation instructions to manually install them via npm when adding it to their project

👆 4
thheller19:06:42

@ahmed1hsn for JS dependencies you can add a deps.cljs to your .jar with {:npm-deps {"foo-bar" "1.2.3"}}

✔️ 4