Fork me on GitHub
#shadow-cljs
<
2019-10-15
>
Joco06:10:40

Hi channel, I have somewhat of a noob question: I have a multi-build shadow-cljs project where one of the builds is a nodejs app. When I use shadow-cljs watch [build-name], I don't see logging from the app like I do when I do a shadow-cljs compile [build-name] && node app.js -- any idea why?

thheller09:10:22

well you still need top call node app.js? you don't seem to be doing that for the watch? shadow-cljs does not run node for you.

Joco17:10:08

Hey, thank you so much for the response. I completely missed that. What's the best way to start/stop node as a part of watch? :build-hooks?

thheller17:10:38

you do it manually. that is the best way.

Joco17:10:48

alrighty -- thanks

Macroz08:10:18

I just created a simple ClojureScript on Node.js + Shadow-CLJS project and can't seem to get CIDER to notice it. I run cider-jack-in-cljs and I get a complaint that I'm not in a Clojure project even though I'm editing a CLJS file in a directory which has the shadow-cljs.edn at parent. Just trying to confirm that one should not be having to jump hoops here and it should "just work".

Macroz08:10:50

running npx shadow-cljs etc. from command-line works

Macroz08:10:56

I get this particular message >>> Are you sure you want to run `cider-jack-in' without a Clojure project? (y or n)

Macroz08:10:21

If I no then nothing will start, if I answer yes then I get another error about missing ClojureScript

thheller09:10:39

might be better to ask in #cider. I can't help since I don't use emacs myself

☑️ 4
erwinrooijakkers08:10:43

Hi all, we use shadow-cljs release prod --source-maps to compile our clojurescript to javascript. We now need to compile the code to make it IE-proof too. The usage of Babel was suggested by a javascript developer here. Is this idiomatic to do in cljs too? If so, how do we include it in the build pipeline?

dazld11:10:19

http://polyfill.io might be your friend before jumping through more transpile hoops.

thheller11:10:15

no. there are already enough ways to do this in shadow-cljs. don't use anything external.

dazld11:10:45

oh, for polyfills too? stuff like promise / fetch..?

dazld11:10:38

does it create bundles per browser, or put all the polyfills for all browsers into the same thing?

thheller11:10:41

well you can always add external polyfills too ... but that could end up including 3 separate polyfills

thheller11:10:57

one for node packages, one for CLJS code and one manual

dazld11:10:07

ah, packaging is different, i think

dazld11:10:15

esm/umd etc

thheller11:10:28

not sure what that means

dazld11:10:39

ecmascript modules, universal module definition etc

thheller11:10:51

yes I know what the words mean

thheller11:10:57

just not what YOU mean in this context

thheller11:10:43

if you are talking about the "new" pattern of including things via script with nomodule and type="module" then that is not currently supported

dazld11:10:06

no, just polyfilling features

thheller11:10:15

but you could easily build two separate outputs, one with polyfills and one without

dazld11:10:26

you could, but you’d need a bundle per browser

dazld11:10:31

and then UA sniffing on serve

dazld11:10:37

which is what polyfill does.

dazld11:10:51

or put it all into one bundle, which is a bit icky

dazld11:10:59

dunno, there’s tradeoffs in all scenarios

thheller11:10:29

polyfills are always icky yes

thheller11:10:05

but not everything can be polyfilled ... so the problem needs to be solved differently

dazld11:10:20

it’s true, there is a threshold.

dazld11:10:59

i’d still try polyfiling legacy as a first step. if it doesn’t work, can drop back to more complex approaches.

thheller11:10:03

I should probably document how this is supposed to work in shadow-cljs

dazld11:10:18

that would be great!

thheller11:10:20

yeah that suggestions is just bad and will not fix anything

dazld11:10:22

depends on which problem. the thing you mention about packaging code for node vs browsers isn’t going to be fixed by it, but stuff like missing array methods will be.

thheller11:10:23

it isn't even a complex approach .. so please don't suggest "custom" approaches BEFORE trying the actual built-in

dazld11:10:58

fair enough - i’ve been using polyfills for this problem for years, so would be curious what approach you have in mind.

thheller11:10:45

:js-options {:babel-present-env {:targets {:ie 8}} is probably all you need

thheller11:10:55

but yeah if you want this to be "optional" you need 2 separate builds. which is kinda dirty currently

dazld11:10:01

cool, but .. that does have the drawbacks of outputting legacy js - so, things like weakmaps would be downpiled..?

dazld11:10:06

or polyfilled in place

thheller11:10:52

yes ... BUT this might be happening regardless of what you are doing outside the build

dazld11:10:03

also true.

dazld11:10:08

yay browsers.

thheller11:10:09

basically if you include polyfills separately the build will not know about it

thheller11:10:19

so it will include whatever it thinks it needs

thheller11:10:48

so the only way to do this properly is to create however many builds you need, targetted at each specific browser and served accordingly

thheller11:10:36

not claiming its perfect in shadow-cljs, it isn't by far

thheller11:10:56

but including 3rd party polyfills is strictly worse in pretty much all cases

erwinrooijakkers14:10:20

Thanks all!

👍 4
erwinrooijakkers09:10:39

Hmm looking at polyfills that might be the quickest fix for now. Include polyfills in IE browsers only via a script conditional. Then there’s also no configuration needed with separate builds per environment. I understand the code size will be larger and the page will be slower so it’s suboptimal.

erwinrooijakkers09:10:25

Advantage is that also the sentry-sdk javascript will start to work in IE

erwinrooijakkers09:10:04

Because that now crashes with Object.assign that is not recognized

erwinrooijakkers09:10:15

So we did not even get the frontend IE errors in Sentry

thheller09:10:48

if you configure :js-options {:babel-preset-config {:targets {:ie "8"}}} and use the sentry stuff from npm then everything will likely work as expected

erwinrooijakkers08:10:14

Ah of course thanks

thheller09:10:08

@erwinrooijakkers is the "bad" code part of your CLJS code or part of npm packages? where does it fail?

erwinrooijakkers14:10:31

I’ll have to check

vinurs11:10:11

anyone use cljs-http in react-native?

(go (let [response (<! (http/get ""
                                 {:with-credentials? false
                                  :query-params {"since" 135}}))]
      (prn (:status response))
      (prn (map :login (:body response)))))
i test the code, it output the error
TypeError: Cannot read property 'chan' of undefined
    at eval (eval at <anonymous> (), <anonymous>:1:53)
    at eval (eval at <anonymous> (), <anonymous>:108:3)
    at eval ()
    at Object.shadow$cljs$devtools$client$env$repl_call [as repl_call] ()
    at Object.shadow$cljs$devtools$client$react_native$repl_invoke [as repl_invoke] ()
    at shadow$cljs$devtools$client$react_native$handle_message ()
    at eval ()
    at Object.shadow$cljs$devtools$client$env$process_next_BANG_ [as process_next_BANG_] ()
    at Object.shadow$cljs$devtools$client$env$process_ws_msg [as process_ws_msg] ()
    at WebSocket.eval ()

thheller11:10:40

did you eval this at the REPL? well I can see that you did. I mean did you eval the ns properly too?

thheller11:10:37

it might be a problem in the REPL. or does this also happen if you load the app regularly?

thheller11:10:15

maybe there is some subtle code loading issue. so please try using this in actual code (without the REPL)

vinurs11:10:23

yes, i tried, when not in repl it works ok

vinurs11:10:47

why i can not evel it in the repl?

thheller11:10:12

I don't know. I'll look into it

vinurs11:10:50

^_^ thanks

thheller11:10:07

@haiyuan.vinurs if you have something reproducible it would help immensly if you add it to https://github.com/thheller/shadow-cljs/issues/574

vinurs12:10:29

@thheller i retry it, but it now works in repl

thheller12:10:54

yeah. I suspect that it works if the code is initially loaded from the build directly

thheller12:10:07

but when loaded at the REPL has some scoping issues so can't find the actual code

ghaskins13:10:49

@thheller im seeing an issue and there are two datapoints that I suspect are related

ghaskins13:10:02

and then this on the phone sim

ghaskins13:10:40

so, if i had to guess, for reasons that are unclear, shadowcljs isnt seeing my reference to .registerComponent and tree-shaking the react-native lib out

ghaskins13:10:28

I tried to annotate with ^js as I was advised to do in a different context…however, here it doesnt seem to have any effect

ghaskins13:10:46

im not sure if I need something else (e.g. ^foo)

thheller13:10:11

@ghaskins yeah that code seems bad but I can't tell without seeing more of it

thheller13:10:25

17 | (defn register-componnet [name root]
  18 |   (.registerComponent ^js app-registry name #(r/reactify-component root)))

thheller13:10:33

what is app-registry?

ghaskins13:10:33

theres nothing secret, happy to share

thheller13:10:58

what is this mess? 😛

ghaskins13:10:18

hah…me stumbling around trying to learn a bunch of stuff at once

thheller13:10:52

(:require ["react-native" :as rn]) (rn/AppRegistry.registerComponent name ...)

ghaskins13:10:57

in essence, app-registry is the output of an (oget+)

thheller13:10:01

thats how it should be done

thheller13:10:20

ban cljs-oops from your codebase. seriously. do not use it. not even once.

p-himik13:10:58

That's the first I see someone disliking cljs-oops. What's wrong with it?

thheller13:10:28

it is working around issues in the CLJS compiler that have been either fixed for years OR better adressed via :infer-externs

p-himik13:10:57

OK, so it may be unneeded. But is it actually a bad practice to still use it? You say that "shadow-cljs can no longer do its job for externs inference" - what are the repercussions?

thheller13:10:11

the error you see above

ghaskins13:10:33

@U2FRKM4TW at least in my case, it caused advanced compilation to fail by eliding a reference actually in use

p-himik13:10:01

To be honest, I have never seen it with cljs-oops. 🙂 And I use NPM quite a lot. Maybe I was just lucky, I dunno.

thheller13:10:03

although I'm not entirely sure why you get an externs inference warning with the ^js tag added

ghaskins13:10:22

yeah, that was strange…that fixed it the last time I ran into this

ghaskins13:10:35

but I also wasn’t using clj-oops before

thheller13:10:03

@U2FRKM4TW have you ever tried NOT using cljs-oops and just straight interop instead? I mean with shadow-cljs, not before?

thheller13:10:49

you can use cljs-oops if you really want to, I just don't think it is necessary

danielneal13:10:47

I used it extensively before I knew about shadow-cljs 😄

thheller13:10:21

yeah I get why people use it

p-himik13:10:25

@thheller I definitely started using shadow-cljs way past after I started using cljs-oops. I started using oops exactly because I had nasty issues with externs, and I hate cljsjs with passion. Another advantage of cljs-oops, albeit a dubious one, is that Cursive doesn't scream at me with yellow "cannot be resolved"s.

thheller13:10:35

but ever since :infer-externs it really isn't useful anymore IMHO

p-himik13:10:06

I should definitely read up on it.

danielneal13:10:16

yeah the infer-externs is great, and just being able to use a ^js tag is genius

thheller13:10:36

(rn/AppRegistry.registerComponent name ...) just take this example

thheller13:10:43

rn is a namespace alias for "react-native"

thheller13:10:01

shadow-cljs sees that and automatically adds AppRegistry and registerComponent to the externs

❤️ 8
thheller13:10:06

so neither of them are renamed

danielneal13:10:14

At first I thought the check wasn’t working for me but it turns out I’d put it in the top level shadow-cljs config instead of under :compiler-options. So there’s that 😄

thheller13:10:07

with cljs-oops its just a string somewhere. I'm assuming that cljs-oops emits something like rn["AppRegistery"]

thheller13:10:28

which isn't exaclty best practice

ghaskins13:10:35

working like a champ, now

ghaskins13:10:51

im a little confused why all the other ogets work, but, progress

p-himik13:10:45

@thheller Yeah, it generates exactly that:

(defn gen-key-get [obj key]
  (case (config/key-get-mode)
    :core `(~'js* "(~{}[~{}])" ~obj ~key)           
    :goog `(goog.object/get ~obj ~key)))
Another pro of using it though - you can write selector like :a.?b.c instead of its cumbersome equivalent. Would the issue be remedied if cljs-oops emitted code like x.y instead of x["y"]?

thheller13:10:25

(some-> a .-b .-c) seems fine to me but thats subjective I guess

thheller13:10:11

it can't really emit x.y

p-himik13:10:47

And also different from what I wrote. 🙂 And cljs-oops also has ! "punch" access. Why not? Can't it write something like (~'js* "(~{}.~{})" ~obj ~key) when key contains a valid JS identifier? Sorry, I've never dealt with such macros that emit JS code.

thheller14:10:18

yeah can't get into this too much right now but it can't work. especially not when things are called as a function as it was in the example of (defn get-obj [name] (oget+ ReactNative name))

p-himik14:10:19

Yeah, I'm not considering the + variety at all. I don't think externs inference would work here either if the names of keys are truly dynamic.

thheller14:10:40

yes but thats the point. in code they are never "truly dynamic"

p-himik14:10:55

OK, I read up a bit on externs inference. It seems that if I use cljs-oops then this mechanism is completely unneeded for me. And vice versa - if I don't need any of the additional features of cljs-oops, I can stick to the inference. I don't see a clear winner as it doesn't seem that using externs inference would produce smaller or more optimal code.

thheller14:10:56

in data yes, thats why you use different access patterns for data vs code

thheller14:10:30

the issue with cljs-oops is that the code is not future proof

p-himik14:10:40

Regarding 'in code they are never "truly dynamic"' - of course. But specifying everything in a truly static manner that's visible to shadow-cljs could easily end up in creating an AbstractSingletonProxyFactoryBean with all of the consequences. Sometimes it's much easier and simpler to just get a key with a check that it exists, in a dynamic manner.

thheller14:10:47

granted that future is uncertain and we may not actually ever get there but still

thheller14:10:24

not sure I understand that comment

thheller14:10:37

the problem is :advanced and you need to understand what that is doing. you simply cannot mix using x.y in one place and x["y"] in another

thheller14:10:15

it is one of the "rules" of the closure compiler

p-himik14:10:56

Well, nothing is truly future proof. We have multiple sets of versions of dependencies, tools, and languages that work together. Everything else makes our bits rot and we're responsible for keeping them fresh. About that "truly dynamic" comment. Consider this code:

(defn f1 [k]
  (oget+ js/Lib k))

(defn f2 [k]
  (case k
    :a (.-a js/Lib)
    :b (.-b js/Lib)
    :c (.-c js/Lib)))
We know what js/Lib is, so we can write f2, easy. But look at how it compares to f1, how much more code there is. And if we want all of the keys to be accessible, we have to keep f2 and js/Lib in sync. Unless there's some option that I'm missing. Note that replacing (f1 :a) with just (.-a js/Lib) is not possible in the general case. E.g. because it immediately removes the ability to iterate over keys. > the problem is :advanced and you need to understand what that is doing Yep, guilty here. I assume that I have some superficial knowledge, but at the same time it completely contradicts what I see - despite all the advanced compilations, I still see my code working with the x["y"] kind of access. To be fair, I just checked all of the instances of oget in one of my projects, and about 90% of them access fields that GCC cannot change (DOM API, external libraries). But the rest 10% access fields that come from NPM libraries. And they still work just fine for some reason! Again - maybe I'm just lucky. > you simply cannot mix using x.y in one place and x["y"] in another If x.y is a known extern (either via externs inference or via explicit externs) and if my understanding of the concept of externs is anywhere near correct, GCC will not rename y to anything. In this situation, using x["y"] should be just fine. When x.y is not a known extern, GCC can rename it to anything under :advanced. And that's exactly where using cljs-oops can bite me, right? I'm more and more interested in why my usage of NPM libraries doesn't explode...

isak15:10:55

@U2FRKM4TW here is an example:

p-himik15:10:09

Oh, thanks, nice! Huh. It's able to substitute k = 'age', p[key] with a.key but it doesn't replace that a.key with a.a.

isak15:10:41

yea, but maybe they don't bother because in many cases the key won't be known at compile time like this simple example, and then advanced would be even harder to reason about

p-himik15:10:12

There seems to be a more robust reasoning because the README of cljs-oops states: "Google Closure compiler rewrites string literals to dot property access whenever possible." So it seems to rely on it.

p-himik15:10:34

And "String names explicitly prevent minification of key names which must stay intact."

isak15:10:30

@U2FRKM4TW only for that "callsite" though, which doesn't help you if the property has been renamed elsewhere

p-himik15:10:51

Yes, of course. I just realized that I don't understand yet another thing. Suppose I use (.-field lib) where lib comes from NPM. Why do we even need externs here? Let GCC rename field to something else both in CLJS and in JS code. Or is it simply because GCC cannot really tell without the externs that field in CLJS is the same field as in JS?

isak15:10:53

Externs is for code that is not processed by GCC compiler. It can rename such cases if both the JS and CLJS runs through it. But for shadow, it explicitly does not run npm deps via GCC, because it causes too many problems. I think that is a feature people tried to add to the clojurescript compiler, but they failed

p-himik15:10:33

Oh, right, I remember now... It is processed by GCC but only the :simple level of optimizations is used. Which is exactly why cljs-oops is able to work at all. OK, I think I understand now, thanks! And consequently, now I see why using cljs-oops indeed adds something to the set of moving parts. Although I'm still unsure whether it's worth it to dump it at this point or not.

isak16:10:01

Oh, you're right. Yea, I'm kind of in the same boat, (not clj-oops but reagent.interop). Haven't tried converting it to all prop access yet.

thheller16:10:01

yes, the npm code is only running through :simple in a separate compilation step. thats why we still need externs in the CLJS parts. running everything through advanced doesn't work.

thheller16:10:33

but if we are ever able to run everything through advanced then cljs-oops becomes a problem. because it mixes direct property access with string access

thheller16:10:23

should we get to a future where everything is written in strict ESM, then it may actually become a possibility to run everything through advanced

4
thheller16:10:30

but we aren't close to that in any way

ghaskins13:10:28

ah, good to know

ghaskins13:10:41

i will try that, thank

ghaskins13:10:06

i assume the same goes for similar aget approaches

thheller13:10:12

the issue with cljs-oops is that shadow-cljs can no longer do its job for externs interence and stuff

thheller13:10:20

don't use aget either

thheller13:10:34

use proper JS interop, like the language intended

ghaskins13:10:13

yeah, always good advice..problem is, im a clojure/jvm guy so im a stranger in a strange land on js

ghaskins13:10:21

but im learning, thank you

dpsutton14:10:56

@thheller do you remember the reason that CIDER and shadow don't work when using node-script target? I thought that was a known issue but don't remember any details

isak16:10:29

How is javascript source processed? (Not npm deps, I mean .js under /src). GCC Advanced? (assuming the CLJS is advanced)

thheller16:10:17

@dpsutton not sure what you mean? that should work fine. or are you referring to the https://shadow-cljs.github.io/docs/UsersGuide.html#missing-js-runtime?

dpsutton16:10:27

yes i think so

lilactown16:10:45

works just fine for me

Macroz16:10:32

@U4YGF4NGM do you mean you have a CIDER + shadow-cljs + node-script running?

Macroz16:10:53

for me CIDER does not find the project

lilactown16:10:00

yes, my last job was spent mostly developing a node script using shadow-cljs

Macroz16:10:20

did you use cider-jack-in-cljs?

lilactown16:10:53

typically I would cider-jack-in-clj and then start the build, but I had many builds in my project

lilactown16:10:02

cider-jack-in-cljs should work

Macroz16:10:14

I must be missing something but no idea what it is

Macroz16:10:35

I basically just created the shadow-cljs sample project and changed it to node-script but CIDER doesn't find the project

lilactown16:10:36

if you’re in a project dir with a shadow-cljs.edn file, CIDER should pick it up

lilactown16:10:51

what version of CIDER are you using?

Macroz16:10:54

all my previous projects have been lein/figwheel and that works fine

Macroz16:10:06

I'm using 0.24

lilactown16:10:21

hmm that’s newer than me. should be fine

Macroz16:10:31

I just upgraded because I thought that maybe there's something

lilactown16:10:41

I’m on 0.22

lilactown16:10:02

can you push your repo and I’ll peek at it?

Macroz16:10:03

it wasn't working for me before upgrade, not sure what version that was

Macroz16:10:57

I followed that one myself

Macroz16:10:13

I'll try to recreate my problem and push it if I still hit it

lilactown16:10:21

it worked for me

Macroz16:10:33

hmm I got some other problem now

Macroz16:10:46

thanks a bunch anyway! I was looking for confirmation that it should work as advertised without jumping through hoops

lilactown16:10:57

1. npx create-cljs-project acme-app 2. Add build to shadow-cljs.edn:

;; shadow-cljs configuration
{:source-paths
 ["src/dev"
  "src/main"
  "src/test"]

 :dependencies
 []

 :builds
 {:backend
  {:target :node-script
   :main 
   :output-to "target/backend.js"
   }}}}
3. Create
(ns )

(defn init []
  (prn "init"))
4. in CLJS buffer, M-x cider-jack-in-cljs 5. Select shadow for REPL type. type backend for build ID. 6. In a terminal, run node target/backend.js

Macroz16:10:46

yes indeed it does not give the problem

Macroz16:10:57

now I shall have to try to compare these two projects ...

Macroz16:10:35

hmm it broke again

Macroz16:10:54

I'll push my repo so you can try

lilactown16:10:09

I won’t be able to get to it for a bit

Macroz16:10:10

it doesn't work for me anymore though it did and I fail to see why

Macroz16:10:57

I'll try to recreate from empty again and see if that works

Macroz16:10:06

ping @dpsutton here is what doesn't work for me

lilactown16:10:45

what’s the behavior when you say it “doesn’t work”?

Macroz16:10:02

cider-jack-in-cljs does not find the project

Macroz16:10:21

it did for a moment, now I fail to see what changed

lilactown16:10:25

and you’re in /src/main/shadow_test/core.cljs?

lilactown16:10:00

at this point I would bring it to #cider might be a bug

Macroz16:10:16

looking for more info now

lilactown16:10:42

yeah it has nothing to do with #shadow-cljs. shadow-cljs works fine with node-script, I don’t know what dpsutton was talking about

Macroz16:10:13

shadow-cljs does indeed work here because I can build the project fine, just that CIDER does not find it

Macroz16:10:27

and it was nice to hear from you and confirm that it should work

Macroz16:10:47

I still don't have clear steps for repro

dpsutton17:10:25

i was referring to the missing js runtime error

dpsutton17:10:34

your step 6 is the solution as i understand it

lilactown17:10:54

yeah, that’s not a problem. just people not understanding how CLJS works

lilactown17:10:20

CLJS requires you to run a JS process. for web stuff it’s the browser window. for node it’s the node script

Macroz17:10:07

I get my error in step 4

Macroz17:10:36

I don't understand how it could work for a while, then again not. I have now three projects and none of them work

Macroz17:10:52

some race condition in my Emacs/CIDER setup?

Macroz17:10:22

AFAIK I'm not doing anything strange

Macroz17:10:00

ok strangeness continues

Macroz17:10:51

I delete-package clj-refactor , comment it out in my .emacs, restart emacs, doesn't work uncomment clj-refactor in .emacs then start emacs and let it reinstall clj-refactor, now it works

Macroz17:10:28

restart emacs and it stops working

Macroz17:10:02

so cider-jack-in-cljs works in shadow-cljs project iff I have just reinstalled clj-refactor Emacs package

dpsutton17:10:35

can you try it without clj-refactor installed at all?

dpsutton17:10:05

and what exact error are you seeing? i know clj-refactor doesn't know that shadow is a project root. but i think its just a warning that clj-refactor won't be enabled and everything should work fine

Macroz17:10:35

so if I delete-package and restart without it, doesn't work

Macroz17:10:52

exact error is >>> Are you sure you want to run `cider-jack-in' without a Clojure project

dpsutton17:10:04

can you elaborate on exactly what "doesn't work" means

Macroz17:10:19

I get that error in a shadow-cljs project

Macroz17:10:29

I should instead be able to jack in

Macroz17:10:38

CIDER does not recognize my shadow-cljs project

Macroz17:10:46

only after fresh install of clj-refactor package ...

Macroz17:10:13

the shadow-cljs project is as in the github project earlier in this thread created by the shadow-cljs quickstart guide

dpsutton17:10:34

can you put it on github exactly as you have it?

Macroz17:10:40

it is there

Macroz17:10:03

scroll up a bit

Macroz17:10:06

shadow-test

Macroz17:10:32

I'm trying with a clean .emacs and I'm seeing it working

dpsutton17:10:55

yeah works for me

Macroz18:10:04

I'll bisect my .emacs in a bit

Macroz18:10:41

AFAIK it's my own fork of clojure-mode that is slightly out of date

Macroz19:10:51

so that's where the list of project files is kept

Macroz19:10:12

it's missing the one for shadow

Macroz19:10:39

logical that it's the reason why the project is not found but surprising that the code is there

Macroz19:10:56

have to rebase to origin/master

Macroz19:10:27

thanks @U4YGF4NGM and @dpsutton for working this out with me

thheller16:10:39

@isak it depends on how you write the code

thheller16:10:54

ES6 is going through GCC advanced

thheller16:10:10

CJS is treated the same as node_modules, so no :advanced

isak16:10:46

@thheller hm, how can I tell? I didn't think about ES6 when writing, but did for example "goog.provide(...)" at the top, and followed the Closure JS rules

thheller16:10:26

yes if you write in the closureJS style that also goes through advanced

thheller16:10:41

basically if you use require it goes with commonjs

thheller16:10:03

if you use import/export it is treated as ESM and advanced

isak16:10:09

ah, cool. got it, thanks.

thheller16:10:31

it is kind of in a weird spot for interop reasons

thheller16:10:40

commonjs <-> esm interop that is

thheller16:10:22

should prefer esm whenever possible but that gets a bit tricky when mixing with commonjs (ie. node_modules)

4
beetleman16:10:58

Recently I started extracting shadow-cljs hooks which I used into the library, maybe it will be handy for somebody: https://github.com/beetleman/shadow-cljs-hooks/

👍 4
beetleman17:10:36

It's need bit more love to being sweet but I will work on it;)

thheller17:10:23

but it just takes a pre-made index.html and replaces the script paths

thheller17:10:58

not yet documented, was going to use this as a documentation example

thheller17:10:36

yep, me too. just something really simple so I don't have to explain too much 😉

thheller17:10:42

so less complex than yours

beetleman17:10:53

Copy file hook looks good to.

beetleman17:10:05

I play now with idea his to make management of images simpler

thheller17:10:43

yeah seems useful. although I probably wouldn't do it as a hook

beetleman17:10:19

Partly. As configuration, rest as macro with return path

beetleman17:10:37

Its initial idea

thheller17:10:46

I would probably have it "index" the files and copy if needed

thheller17:10:19

and then provide a data file like {"/img/foo.png" "/actual/path/img.hash.png"} or more complex if needed

beetleman17:10:26

Copy dir can be good enough

thheller17:10:28

and then load that file at runtime

thheller17:10:50

otherwise changing an image will require recompiling JS which makes no sense to me 😛

beetleman17:10:04

I do not know source code of shadow-cljs but I saw hooks and want something morw user friendly like webpack have;)

beetleman17:10:48

I'm not started worked on images. But my idea was similar to your. But I must work on implementation/

mruzekw18:10:34

Has anyone been able to set up shadow-cljs to work well with AWS lamda functions? I’d like to use Zeit Now. Basically all *.cljs files in the /src/api folder would be compiled into the build/api folder as JS files and then the build files would be shipped via now

thheller18:10:58

there are examples for both zeit and aws out there

thheller18:10:05

I made a netlify example a while ago. zeit is pretty much the same https://github.com/thheller/netlify-cljs

David Pham18:10:23

Anyone has a guide about web workers? I read shadow-CLJS documentation but I am not sure if I understand everything and if there is anything else to know to use webworkers

thheller18:10:25

what do you want to know?

thheller18:10:35

hard to write something more generic than the docs 🙂

mruzekw18:10:31

I’m following this for shadow-cljs on zeit now https://github.com/jntn/haiku

mruzekw18:10:18

What I can’t figure out is how to add multiple functions beyond haikus

mruzekw18:10:56

Is there anyway without adding a new build for each lambda?

thheller19:10:45

not sure how that works either. not sure if they need to be bundled separately or if you can have multiple in one bundle

mruzekw19:10:19

I can look into that, but I think this example is based on a folder/file pattern

mruzekw19:10:00

Thus any new function would be src/api/fn -> api/fn/index.js

mruzekw19:10:16

But there might be a way to map functions from one single file with multiple exports

mruzekw19:10:30

That would mean updating now.json though, which sounds preferable

thheller19:10:16

it would be easy to have shadow-cljs generated multiple files

thheller19:10:30

or just writing a tiny bit of boilerplate JS by hand

David Pham19:10:08

@thheller Is there anything else to know about webworkers?

thheller19:10:41

depends. what do you want to build?

David Pham19:10:49

Delegate some computation off the main thread to avoid blocking

thheller19:10:17

the difficult part is often the data sharing

thheller19:10:37

if you have to serialize too much back and forth that it is often not worth doing in the first place

David Pham19:10:42

The communication could be async though right? I am not so concerned about speed, more about blocking the UI

thheller19:10:21

no sync is not possible

thheller19:10:33

all async always

David Pham19:10:29

Thanks a lot!! :)

mruzekw19:10:31

> it would be easy to have shadow-cljs generated multiple files By an existing config? Or something that would need to be built?

thheller19:10:18

something that might need to be built. it is mostly about figuring out how zeit/aws want stuff to be organized

thheller19:10:24

and outputting it in that style

thheller19:10:11

but thats the entire point of the :target abstraction in shadow-cljs

thheller19:10:45

figure out the minimal amount of config needed and implement it 😛

mruzekw19:10:09

Sure, how are targets implemented?

mruzekw19:10:17

Is there a concept of target-plugins?

thheller19:10:10

ie :target :browser responds to browser.clj in that dir

thheller19:10:36

anyone in theory could write those since it also accepts symbols :target my.custom/stuff

thheller19:10:51

but given that there is no documentation I don't really expect anyone to write these just yet 😛

thheller19:10:14

basically it is one function that gets called repeatedly going through the stages

thheller19:10:17

same as build hooks

mruzekw19:10:47

Okay, thanks. I will look into this for the long-term

mruzekw19:10:33

For reference, the expected output for zeit is flexible

{ "src": "/api", "dest": "/my-api.js" },
    { "src": "/users", "methods": ["POST"], "dest": "/users-api.js" },
    { "src": "/users/(?<id>[^/]*)", "dest": "/users-api.js?id=$id" },

mruzekw19:10:38

Based on the config

thheller19:10:00

and those files then each just have a singular export?

thheller19:10:11

like module.exports = function(req) ... or whatever?

mruzekw19:10:20

There is the zero-config option which behaves like:

{
            "src": "/api/(.*)",
            "dest": "/api/$1"
        }

mruzekw19:10:55

And since they’re separate functions, the dependencies would be bundled in each

thheller19:10:28

not sure what you mean by that. the /my-api.js has to be self-contained without require of its own?

thheller19:10:19

I built this some time ago which basically had the config for stuff in metadata in CLJS

thheller19:10:27

the compiler would then use it for structure the output

thheller19:10:49

maybe something like that would work for zeit too

thheller19:10:18

I had plans to build examples for more of these platforms .. but it is really time intense to figure out how they all work

mruzekw19:10:25

Each function should be considered isolated, I’m assuming deps would need to be bundled with each

mruzekw19:10:09

Sure, happy to help given it fits with what I’m already working with

mruzekw19:10:33

You could also either document the symbol usage or open up some way for people to build plugins and download those

mruzekw19:10:46

Might take the load off of doing it all yourself

thheller19:10:30

well, if I knew how to document this stuff properly I would

thheller19:10:43

but there is so much stuff to consider on certain platforms

thheller19:10:55

just compare browser.clj vs node_script.clj or so

thheller19:10:07

one is trivial, the other is not 😛

mruzekw19:10:24

haha indeed

thheller19:10:45

the basic setup is always the same, configure stuff, tell the compiler which files it should compile, then "post-process" everything into the right shape

mruzekw19:10:08

post-process === post closure?

thheller19:10:30

pre and post yes

mruzekw19:10:03

:compile-prepare :compile-finish

thheller19:10:31

most of the custom works happens in :flush

mruzekw19:10:33

When you say document properly, what do you mean?

thheller19:10:39

since thats the part actually writing stuff to disk

thheller19:10:04

well document the internal "build api" basically

thheller19:10:59

basically what the compiler needs is :modules config

thheller19:10:03

all build targets use that abstraction

thheller19:10:27

so :node-script basically just is syntax sugar for :modules {:main {:entries [that.main.ns] :append-js "that.main.ns.main(process.argv)"}}

thheller19:10:35

with a bit more platform related stuff

thheller19:10:13

so for the zeit stuff there would probably be one shared module and then one per fn

thheller19:10:33

and just combined again later. or something like that

thheller19:10:20

well yeah .. documentation needs to be written ...

mruzekw19:10:49

Is there an example of the :node-script to :modules mapping?

mruzekw19:10:01

Err, more examples? Just to grasp the concept

mruzekw19:10:15

Or is this more of a conceptual thing rather than technical

mruzekw19:10:21

Cool, well I’ll give this a look later on and see what I can do to help

mruzekw19:10:27

Have to peace out for now

Macroz20:10:12

sigh so what's the best way to solve advanced compilation problems (I have set optimization simple, pretty-print, pseudo-names and)

Macroz20:10:51

TypeError: Cannot read property 'cljs$core$IFn$_invoke$arity$1' of undefined

Macroz20:10:22

no problem in dev mode, only in release build (also with --debug)

Macroz20:10:56

looks like it's a line with clj->js

Macroz20:10:37

changing to advanced compilation fixes that but then one of the npm dependencies breaks

Macroz20:10:12

^js tagging that one method call works

Macroz20:10:23

but I wonder what breaks cljs.core when using optimization simple

David Pham21:10:51

What are the disadvantage of using deps.edn with shadow-CLJS?