Fork me on GitHub
#shadow-cljs
<
2018-02-09
>
justinlee00:02:23

okay well i can’t get react-flip-move to import: i get nil. i’m pretty sure this is a bug so i’ll open an issue so you have all the context

justinlee02:02:59

^ sorry the problem above is that I had put :js-options inside of :devtools (would be super cool if there were warnings about config keys in unexpected places)

thheller09:02:10

@lee.justin.m shadow-cljs indeed always minimizes files and react unfortunately complains about this during development. for shadow-cljs release it will use their correct production js and not minify the dev version. so the warning is the only problem.

pepe09:02:24

I have created sample repo with both node and browser apps. It is just bare bones. https://github.com/pepe/two-in-shadows

pepe09:02:44

Please tell me what you think about it.

pepe09:02:08

Also I have no problem to hook the #dirac

thheller09:02:20

@pepe cool. you can run shadow-cljs watch client server to watch both builds in one process. no need to use separate processes.

pepe09:02:58

@thheller great, thank you

cmal09:02:48

Hi, I use (:require ["qiniu" :as qiniu]) to import a node library to clojurescript in shadow-cljs. But I got stuck when trying to write javascript

var mac = new qiniu.auth.digest.Mac(key1, key2)
in clojurescript. I tried
(def mac (-> (qiniu.auth.digest/Mac access-key secret-key)))
but failed. How should I do this?

thheller09:02:28

qiniu/auth.digest.Mac should work

thheller09:02:15

the aliases created by :as must always be used as-is. qiniu.auth.digest is not a valid alias

thheller09:02:52

(def mac (qiniu/auth.digest.Mac. access-key secret-key))

thheller09:02:05

not the . at the end. that is sugar for new.

pepe10:02:53

So I successfully (and easily) added shared code to the sample. Man it feels great

Jon15:02:31

------ ERROR -------------------------------------------------------------------
 File: /Users/chen/repo/memkits/manuscript/src/app/util.cljs:6:11
--------------------------------------------------------------------------------
   3 |
   4 | (defn focus-text! []
   5 |   (js/requestAnimationFrame
   6 |    (fn [] (let [element (.querySelector js/document ".text"), .focus element] ))))
-----------------^--------------------------------------------------------------
Invalid local name: .focus at line 6 app/util.cljs
--------------------------------------------------------------------------------

Jon15:02:52

no more responding to my file changes after throwing this error...

Jon15:02:15

restarted server to make it work.

justinlee18:02:50

well @thheller i really appreciate the help. i wanted to say thanks so much for your help and amazing work you are doing. for now, i have to declare defeat. i’ve spent too much time trying to make my project work in cljs and i just have to go back to javascript where i can be productive.

justinlee18:02:26

if there were about 10 more of you i think everything would be different

thheller18:02:37

what happened?

thheller18:02:30

I can't let you go back to JS just yet 😉

justinlee18:02:20

basically i’ve got a website i’m trying to build. i use a few libraries: flip-move, react-virtualized, react-dnd. it’s just excruciating to try to figure out how to use them in cljs. what i hate most of all is that i cannot figure out what’s going on. like yesterday trying to figure out why flip-move won’t load. there’s just nothing for me to do. i tried like 50 combinations of random shit in my config files and different versions of libraries

justinlee18:02:43

in JS if i have a problem i can methodically work through it. but in cljs i just get stuck. there’s nothing more i know to try

justinlee18:02:19

i reported the flipmove issue, but also several of my react-dnd libraries weren’t loading. i got an error message in teh console, but i have no idea what to do about it

justinlee18:02:23

so maddening

thheller18:02:09

yeah the :as vs :default issue is a bit annoying due to the inconsistencies in JS

justinlee18:02:10

i opened up a new portion of my website that i’m trying to port and saw all of the crazy s* i have built with react-vritualized and i realized it was going to be super hard

thheller18:02:24

did you try :npm-module at all?

thheller18:02:53

this would let you keep your old toolchain and load CLJS into that

justinlee18:02:15

the thing is that the primary thing i want from cljs is state management. atoms + specter is freaking amazing

justinlee18:02:30

maybe i don’t understand what you’re proposing

thheller18:02:13

this will compile CLJS into something CommonJS-ish

thheller18:02:17

so require from JS just works

thheller18:02:46

but this only generates the CJS output. it is then treated like any other JS file by JS tool, ie. webpack

justinlee18:02:18

so then i just access everything useing the js global accessors?

thheller18:02:18

this demo is a bit old but it demos the integration in create-react-app

thheller18:02:01

no (:require ["react-dnd"]) stays just like that

thheller18:02:12

but instead of shadow-cljs providing the value for this

thheller18:02:27

it just emits require("react-dnd") and lets webpack provide it

thheller18:02:12

so you literally make no modification to your webpack setup

thheller18:02:32

shadow-cljs compile npm (default config included, no extra build config required)

thheller18:02:52

and then require("shadow-cljs/your.ns") and let webpack find it

justinlee18:02:51

interesting. question: is there a “verbose” mode in shadow-cljs to explain what it is doing when it tries to load a library?

justinlee18:02:01

because that would have helped me when i was trying to figure out what was going on

justinlee18:02:20

like literally list every js file it is loading and why

thheller18:02:36

the resolve rules are identical to node

thheller18:02:00

(:require ["react-dnd"]) looks at node_modules/react-dnd/package.json for main

thheller18:02:29

reads that file, parses out all its require calls or import

thheller18:02:34

follows those and so on

thheller18:02:55

it doesn't list the files exactly in the log output but I can add that if you want

thheller18:02:44

I think you got burned hard by the :foreign-libs mess and NOTHING from that applies to shadow-cljs

justinlee18:02:49

okay well let me just try to see if i can get these packages to load before i give up

thheller18:02:12

shadow-cljs pretty much does exactly what webpack does

justinlee18:02:54

i think the hard part is that in JS you just cut-n-paste whatever magical BS is required to get things to load. you need to understand that stuff and translate it in cljs

thheller18:02:15

I made a translation table for that exactly

justinlee18:02:27

yea but i did that and it didn’t work 🙂

thheller18:02:40

however you got bitten by the problem I described where react-flip-move pretends to be ES when it isn't

justinlee18:02:42

believe me there’s nothing you’ve written that i haven’t read at this point

thheller18:02:45

what you can always do is (:require ["thing" :as x]) and then (js/console.log "x" x)

thheller18:02:10

if that is just an object with a .default property you are better off using :default

thheller18:02:19

otherwise :as is always the safer choice

thheller18:02:39

due to old compat issues there may also be a .default$ property but that is just :default again

thheller18:02:56

the situation with ES6 default exports is really strange

thheller18:02:04

but AFAICT thats also true in node world

justinlee18:02:14

i guess the other thing i was puzzling through is the fact that reagent used to require cljsjs versions of react. so i excluded those. but I just could be sure what I was doing was working. that’s kind of why i was wishing for some kind of diagnostic.

thheller18:02:40

it still does

thheller18:02:57

but as a migration shadow-cljs includes these shim files

justinlee18:02:20

can’t i just exclude them?

justinlee18:02:26

that seemed to work

thheller18:02:44

excluding is fine but not required

thheller18:02:35

the shim file basically maps the pseudo-ns that :foreign-libs otherwise would create back to the original npm package

justinlee18:02:56

wow you know why I couldn’t get react-flip to work? I was putting “.js” at the end of my :js-options :require.

thheller18:02:59

and then exports it to the global name the react foreign lib would have provided

thheller18:02:11

so technically you can require cljsjs.react and use js/React

thheller18:02:15

how exactly? maybe I can validate that?

justinlee18:02:01

wait no that’s not it. args this is so annoying. i tried all of this last night and it didnt work

thheller18:02:13

why are you messing with it at all?

justinlee18:02:02

i mean i saw that flip move had different distros and i tried resolving it to the .es module even before i reported that issue

thheller18:02:12

:js-options
{:resolve
  {"react-flip-move" {:target :npm :require "react-flip-move/dist/react-flip-move.es"}}}

justinlee18:02:18

now it’s working and i want to know how i screwed up so i don’t do it again

thheller18:02:27

did I mess that up?

justinlee18:02:38

no that works but i swear i tried that

thheller18:02:51

:require "react-flip-move/dist/react-flip-move.es.js"

thheller18:02:53

should be fine too

justinlee18:02:01

the only difference is that i use “react-flip-move/dist/react-flip-move.es.js”

justinlee18:02:08

but both of those work now

justinlee18:02:07

so back on my larger project. what does this mean and how i diagnose it:

shadow-cljs - failed to load module$node_modules$react_dnd$lib$DragDropContextProvider
shadow.js.jsRequire @ shadow.js.js:53
shadow$provide.module$node_modules$react_dnd$lib$index @ index.js:17
shadow.js.jsRequire @ shadow.js.js:51
shadow.js.require @ shadow.js.js:77
(anonymous) @ seekeasy.sidebar.js:10

thheller18:02:50

the actual error should be in there as well

thheller18:02:26

it rethrows the actual error that happened when importing

thheller18:02:37

so you should get an exception

thheller18:02:54

the message just informs you which file failed to load

thheller19:02:51

module$node_modules$react_dnd$lib$DragDropContextProvider is the internal namespace that is generated for the file

dominicm19:02:05

Is the build target exposed anywhere? I have code which works in both node & browser with only a slight change.

thheller19:02:43

what do you mean? exposed at runtime?

dominicm19:02:46

@thheller any time I guess build config or runtime, just need to be able to switch my code on it.

thheller19:02:03

switch how?

dominicm19:02:06

For runtime I'd have to fallback on detection strategies I guess

thheller19:02:28

the default recommended strategy would be a goog-define since it works with DCE

dominicm19:02:55

(dostuff
  (if (goog.node-js)
    (js/require "some-canvas-alt")
    (js/getElementById "canvas")))
I can do a goog.define 🙂

dominicm19:02:05

Wanted to make sure there was nothing I'd be duplicating first

thheller19:02:17

ugh you are getting into tricky territory with conditional requires but yes that would be a candidate for goog-define

thheller19:02:27

(goog-define target "browser")

thheller19:02:55

then in the node target :compiler-options {:closure-defines {your.ns/target "node"}

thheller19:02:06

node_modules/react-dnd/lib/DragDropContextProvider.js in this case

justinlee19:02:14

unless something is messed up with my chrome, the above is all i got

thheller19:02:40

uhm I can't tell the actual error either, thats weird

thheller19:02:29

is this a fresh page reload?

thheller19:02:22

no idea why that wouldn't show anywhere?

justinlee19:02:43

i’m going to try in a different browser

thheller19:02:19

you can try chrome with pause on exception maybe

thheller19:02:48

I just tested (:require ["react-dnd"]) and it works just fine. what exactly do you require?

justinlee19:02:55

same thing with firefox. i’m going to downgrade to react 15

justinlee19:02:02

see if i get different resutls

thheller19:02:31

I'm on react v16

justinlee19:02:19

i’ll try this then i’ll start commenting things out until i get something sane

dominicm19:02:08

@thheller Hmm, yes, I hadn't considered that conditional requires might be tricky territory. I don't want to compile into a single js particularly, I want to write a standalone js module (I think, haven't explored this far). Is there anything specific you'd recommend?

thheller19:02:46

:closure-defines is static at compile time. if you prefer to detect at runtime instead you could use js/process.browser

thheller19:02:13

JS tools like webpack will set this. shadow-cljs does as well

thheller19:02:43

@lee.justin.m react-dnd seems painfully hard to use even from the JS side. I would probably never be able to use this without looking at the docs every time.

justinlee19:02:06

that’s true 🙂

justinlee19:02:10

i have it working though

thheller19:02:47

combining this with the weirdness that reagent does sometimes just smells like pain

justinlee19:02:08

okay. now i’m losing my mind. i have removed react-flip-move from packages.json. my dependencies look like:

:dependencies
 [[org.clojure/clojure "1.9.0"]
  [org.clojure/clojurescript "1.9.946"]
  [reagent "0.8.0-alpha2" :exclusions [cljsjs/react cljsjs/react-dom cljsjs/creat-react-class cljsjs/react-dom-server]]
  [hiccup "1.0.5"]
  [secretary "1.2.3"]
  [cljs-http "0.1.44"]
  [com.rpl/specter "1.1.0"]
  [venantius/accountant "0.2.3" :exclusions [org.clojure/tools.reader]]
  [binaryage/oops "0.5.8"]
  [org.clojure/test.check "0.9.0"]]
and now i’m getting
The required JS dependency "react-flip-move" is not available, it was required by "cljsjs/react_flip_move.cljs"
Where is that cljsjs coming from?

thheller19:02:39

something is still requiring cljsjs.react-flip-move

thheller19:02:49

I think re-frame-trace does that

justinlee19:02:58

i’m not using re-frame

justinlee19:02:22

is there a way to dump the dependency resolution graph?

justinlee19:02:33

kind of like yarn list

thheller19:02:57

shadow-cljs clj-repl

thheller19:02:59

(shadow.cljs.devtools.api/find-resources-using-ns 'cljsjs.react-flip-move)

thheller19:02:13

I should probably show the full graph in that exception, eg. everyone involved in that require

justinlee19:02:39

that is SUPER useful

justinlee19:02:39

okay got all of my stupidity out of the way. now i have a create-react-class issues:

shadow.js.js:53 shadow-cljs - failed to load module$node_modules$create_react_class$index
shadow.js.jsRequire @ shadow.js.js:53
shadow.js.require @ shadow.js.js:77
(anonymous) @ reagent.impl.component.js:3
shadow.js.js:54 Uncaught TypeError: m.Component is not a constructor
    at Object.shadow$provide.module$node_modules$create_react_class$index (index.js:23)
    at Object.shadow.js.jsRequire (shadow.js.js:51)
    at Object.shadow.js.require (shadow.js.js:77)
    at reagent.impl.component.js:3

justinlee19:02:50

weirdly, reagent will render a simple div

thheller19:02:17

that means reagent is trying to new something thats supposed to be used a function

thheller19:02:47

but I don't understand why you are getting failed to load?

thheller19:02:46

are you sure you are calling the DragSource setup stuff correctly?

justinlee19:02:52

i removed all of that stuff

justinlee19:02:13

i’m trying to get back to a hello-world and now i’ve obviously messed the buid configuration up so bad it won’t work

thheller19:02:43

is this in the test project? I'd love to see this state

justinlee19:02:44

this doesn’t work anymore because of all the load errors:

(defn thing [] [:div "goodbye world"])

(defn mount-root []
  (reagent/render [thing]
                  (.getElementById js/document "app")))

thheller19:02:17

and the build config?

thheller19:02:46

there might be a caching error somewhere if you modified the node_modules directly while the compile is running

thheller19:02:59

since that modifies so many files it might just give up at some point

justinlee19:02:00

the shadow config is just the dependencies vector, no additional options

justinlee19:02:07

i’ll nuke everything and restart

justinlee19:02:21

nothing is working. somehow i’ve messed up react and reagent. i downgraded to reagent 0.7.0 and i’ve installed the cljsjs/react.js shim

thheller19:02:57

you never need to include the cljsjs/react shim. shadow-cljs provides this

thheller19:02:07

did you nuke target/shadow-cljs?

thheller19:02:37

I'd really love to see the state the project is in though

justinlee19:02:55

just tried that. same thing. so I should install react, react-dom, and create-react-app via npm, righT?

thheller19:02:18

create-react-class you mean?

thheller19:02:21

create-react-app no

justinlee19:02:56

sorry i mean create-react-class

justinlee19:02:39

omg. i deleted node_modules, killed yarn.lock. only those three dependencies (react 15). i have reagent 0.7.0 with no exclusions. killed target. that got me back to a working state

thheller20:02:18

you did restart the shadow-cljs process right?

thheller20:02:42

I mean the actual server process? didn't leave anything running in the background or so?

thheller20:02:19

uh I know what might have happend

justinlee20:02:24

yea i haven’t been backgrounding the server because this smelled like caching. the one thing i haven’t been doing is killing the target. killing the target and resetting node_modules fixed whatever chaos i had created

thheller20:02:42

npm can install nested versions. so it maybe installed node_modules/thing/node_modules/react

thheller20:02:55

but shadow-cljs only looks at node_modules/react never the nested versions?

thheller20:02:05

maybe yarn thought a thing was installed because it was nested

thheller20:02:52

but shadow-cljs didn't find it and errored out on you?

thheller20:02:00

hmm damn we might never know 😛

justinlee20:02:50

i really don’t think that was it because i’m pretty sure i was looking at the create-react-class files

justinlee20:02:02

well just wait 30 minutes and i’ll probably have it royally screwed up again

theasp21:02:08

Does shadow-cljs clear the js console now?

theasp21:02:23

Damnit, wtf

theasp21:02:22

I have no idea whats doing it, but every refresh seems to clear the console, which is actually a bit convenient

thheller21:02:12

console.clear = function () { throw "who be calling me"; }

thheller21:02:20

eval that in the chrome console 😉

theasp21:02:38

Nothing is thrown

thheller21:02:14

hmmm guess that doesn't work then 😛

theasp21:02:04

Yeah, either way, I think I like it, so if I find it and fix it, I would have to reimplement it

thheller21:02:41

doesn't sound like a terrible idea so maybe I can add it behind a flag

thheller21:02:03

would be good to find out who does it though

theasp21:02:15

Yeah, but should be trivial in the reload fn too. What would be even better is if the console can be scrolled to the bottom

theasp21:02:40

Have a good weekend 🙂

thheller21:02:11

thx, you too!

thheller21:02:58

I wanted to see if I can compile a modern JS application with shadow-cljs. Turns out I can with no modifications to the source whatsoever. Only config stuff and a manual babel pass due to JSX.

thheller21:02:22

I'll probably write a blog post about this. I guess I can claim that shadow-cljs has pretty good JS support when it can do this. 😉

justinlee21:02:54

that’s pretty amazing

justinlee21:02:17

i’m working through some unexpected things, but i really think most of my problems were related to a stale build

thheller21:02:11

thats unfortunate. I have not had any caching issues in years for CLJS

thheller21:02:36

npm/yarn however do scary stuff to the node_modules folder sometimes

thheller21:02:48

so I can't claim reliable caching for that yet

thheller21:02:52

needs a lot more testing

justinlee22:02:33

flipmove working, react-dnd working

justinlee22:02:01

the sheer non-determinism and crazy insanity that plagued me yesterday is gone

justinlee22:02:09

the only weird thing that is happening is that when i’m off of the main entry point, reloading breaks now, presumably because i’m using html5 history

thheller22:02:48

I think you need to stick that into a defonce

justinlee22:02:18

I’m using :http-handler shadow.http.push-state/handle

thheller22:02:45

thats only relevant when you reload the page manually

justinlee22:02:44

right of course. when i’m not on the root path and i change the code, everything goes haywire and i have to reload

justinlee22:02:09

when I try to reload from the non-root path, something super werid happend

thheller22:02:17

hmm it shouldn't affect the reloading itself but I don't know what you do :after-load

justinlee22:02:27

oh maybe that’s the problem

justinlee22:02:45

i would have though :after-load should just re-mount the root reagent component

thheller22:02:10

well shadow-cljs doesn't do anything other than calling the specified function. so it is up to you.