Fork me on GitHub
#shadow-cljs
<
2018-06-20
>
currentoor00:06:21

I also had, in my shadow-cljs.edn file

:lein         {:profile "cljs"}
adding the dependencies to the cljs profile in project.clj made the warning go away for cider-nrepl, which is good enough for now,

currentoor00:06:03

any idea what needs to be done for clj-refactor? i still get

WARNING: clj-refactor and refactor-nrepl are out of sync.
Their versions are 2.4.0-SNAPSHOT (package: 20180420.223) and n/a, respectively.

lilactown00:06:23

yeah I haven’t figured out how to make that go away

lilactown00:06:44

honestly I see it in most of my CLJ projects, regardless of shadow-cljs 😅

lilactown00:06:58

I think that shadow-cljs automatically loads the cider-nrepl middleware if it detects it on the classpath. I don’t think it does the same for clj-refactor

lilactown00:06:47

there’s a place in the userguide about adding nrepl middleware to shadow-cljs: https://shadow-cljs.github.io/docs/UsersGuide.html#nREPL

lilactown00:06:25

so you’ll need to add

{...
 :nrepl {:port 9000
         :middleware ['refactor-nrepl.middleware/wrap-refactor]}
 ...}

lilactown00:06:31

maybe without the '

lilactown00:06:04

you might also need to add the CIDER middleware as well

Jeff Friesen01:06:13

I’m wondering if I’ve got my shadow-cljs configuration set up incorrectly. A couple issues 1. Slow: 5-15 seconds for live reload. This is on a very small project with 8 files. Reading other comments on this thread makes me think that this is typical. 2. Source maps: I think these are on by default, but I get so many errors where the component name isn’t exposed - it’s like it’s using a minified name. My problem is always with b! Here’s a simple example

(defn stats-modal []
  [:> sem/Modal {:trigger (reagent/as-element (stats-button))}
   [:> sem/Modal.Content
    [:p "example content"]]
   ])
Debugging it, I get different versions of this: > Warning: Failed prop type: Invalid prop trigger supplied to b, expected a ReactNode. > in b (created by permits.views.home.header.stats_modal) > in permits.views.home.header.stats_modal (created by permits.views.home.header.header_bar) > in div (created by permits.views.home.header.header_bar) > warning.js:34 Warning: Failed prop type: Invalid prop trigger supplied to b, expected a ReactNode. > in b (created by permits.views.home.header.stats_modal) > in permits.views.home.header.stats_modal (created by permits.views.home.header.header_bar) > in div (created by permits.views.home.header.header_bar) > in div (created by permits.views.home.header.header_bar) > The above error occurred in the <b> component: > in b (created by b) > in b (created by b) This sometimes narrows it down to the React component, but for bigger components I have no idea where the problem is. That leads me to very small refactors where I check for errors in the rendering. But with slow reload times it feels impossible to be productive. Is there a source map option to get non-minimized errors? Or does that slow it down more? Here is my shadow-cljs.edn files:
{:source-paths ["src"]

 :dependencies [[reagent "0.7.0"]
                [re-frame "0.10.5"]
                [binaryage/devtools "0.9.10"]
                [day8.re-frame/re-frame-10x "0.3.2-react16"]
                [bidi "2.1.3"]
                [kibu/pushy "0.3.8"]
                [cider/cider-nrepl "0.17.0"]
                [soda-ash "0.81.1"]]

 :builds {:app {:target :browser
                :output-dir "public/js"
                :asset-path "/js"
                :modules {:main {:entries [permits.core]}}
                :compiler-options {:closure-defines {"re_frame.trace.trace_enabled_QMARK_" true}}
                
                ;; start a development http server
                :devtools {:after-load permits.core/render
                           :http-root "public"
                           :http-port 8020
                           :preloads [devtools.preload day8.re-frame-10x.preload]}

                :release {:output-dir "dist/js"}}}}

Jeff Friesen01:06:00

I run first npx shadow-cljs server then npx shadow-cljs watch app

justinlee02:06:07

the 10 second reloads i don’t think are normal. mine are less than 2 seconds.

justinlee02:06:14

the ‘b’ thing is something from reagent

Jeff Friesen02:06:16

Ok, I’ll look at Reagent error messages. It looked like minimization, which I thought would be shadow-cljs role. I wonder why it’s so slow to reload

justinlee02:06:03

when thheller gets up he can help with that. try running your watch with the --verbose flag. that will give you some insight

justinlee02:06:05

you might be right about the minification. i think the :> operator is setting the name of the component from the function name and the function name appears as though it is getting minified. that seems weird though, because i’m pretty sure thomas only runs node modules through simple minifications

thheller06:06:52

node_modules only run through :simple yes but :simple does include variable renaming by default wherever it can. :property-renaming however is usually only used in :advanced.

thheller06:06:39

it has been a problem before with graphql

justinlee16:06:55

sorry just saw this thread. thanks for the info.

Jeff Friesen02:06:58

Ok. I’ll try the verbose flag

albert.lai05:06:05

Hi, all. Currently, I am trying to migrate my lein cljs build to shadow-cljs. I find that the embed resource tricks stop working. May I know there is some workaround on this?

lilactown05:06:43

hm interesting

lilactown05:06:48

what’s the error?

thheller06:06:00

@albert.lai that indeed looks like a bug. will look into it.

thheller06:06:32

@momoblackblack usually you should have source maps for everything but the error message looks like it might be generated by react so it might not use source maps. you can try setting :dev {:js-options {:variable-renaming :off}} and/or :property-renaming :off

thheller06:06:25

5-10sec is not normal. you can try running with --verbose to get a bit more timing information. would be useful to know where the time is spent.

thheller06:06:32

@currentoor if you use :lein then :dependencies in shadow-cljs.edn are ignored. everything must be in project.clj. no idea about emacs stuff.

👍 4
thheller06:06:48

@wilkerlucio currently there is no way to skip preloads for workers. still need to do a standalone worker build target. currently the worker module just loads all the sources of the modules it depends on without any filtering. not sure how easy it would be to filter.

thheller06:06:57

@albert.lai fixed in 2.4.6. btw if your CLJS namespace with the macro self requires (ns abc.cljs-embed (:require-macros [abc.cljs-embed])), you scan skip the :include-macros true everywhere else

albert.lai06:06:41

@thheller thanks! I will try it now!

troglotit08:06:27

Does anyone uses cljss with shadow-cljs? Did you solved cache busting, i.e. do your styles hot-reload?

levitanong08:06:31

@thheller is there a function for “release”ing, but rather than writing to disk, it returns some string a server can keep in memory?

thheller08:06:47

@levitanong no, it always assumes you want to write to disk

thheller08:06:36

do you run shadow-cljs as part of your production app?

levitanong09:06:08

@thheller yes, when i run the server, i do a number of things. For css, I compile via garden css (and then store the string in memory, so that whenever a request matches that css route, i shave a bit off my response time because i skip i/o. Plus, cachebusting is way easier) For js, I run shadow/release.

levitanong09:06:43

dev mode is pleasant because i use stuartsierra’s component, so setup/teardown of shadow.server/start! and shadow.server/stop!

levitanong09:06:12

so I’m just thinking, it would just be neat if i could do to js what i do for css.

thheller09:06:14

the way I do this is not run shadow-cljs as part of my server

thheller09:06:32

but instead have it watch the output-dir for changes to the manifest.edn

thheller09:06:44

which contains all the required info about the JS

thheller09:06:00

so it can reload the JS when the manifest changes

thheller09:06:29

running the entire shadow-cljs server in your production app may not be the best idea

thheller09:06:53

it really is meant for development and launches a bunch of endpoints you really don't want to expose on a public server

thheller09:06:00

socket repl, nrepl, etc

levitanong09:06:08

but i’m not using that for production

levitanong09:06:14

i only run release for production

levitanong09:06:23

and the shadow server stuff when my server is in dev mode

thheller09:06:54

yeah that should be ok

levitanong09:06:05

so i have another question:

levitanong09:06:20

is there any plan to support more profiles other than dev and release?

levitanong09:06:52

in my company, we have several stages our apps go through: development, testing, staging, a million other things, and then finally prod

levitanong09:06:06

it’s only in development that i want to run things in dev mode, the rest in release

thheller09:06:25

so my stance on this is simple: everything beyond development should use the release profile

levitanong09:06:32

however, those other profiles should be using slightly different endpoints

thheller09:06:41

since what good is testing/staging if it uses different code than production

thheller09:06:55

and configuration of endpoints and such really should not be part of build config

thheller09:06:05

it is runtime config you want to pass in differently

thheller09:06:14

I really should add that to the docs

levitanong09:06:20

but what about the google closure defines?

levitanong09:06:43

or is that me misusing that functionality? 😛

levitanong09:06:15

do you have any advice for endpoints? because i don’t really need them to be set at runtime.

thheller09:06:27

I usually recommend this setup

thheller09:06:33

the init fn is called from HTML

thheller09:06:51

you can pass starter.browser.init({endpoint:"http://..."}) there

thheller09:06:06

and then have the init fn store that somewhere useful and make your app use it

levitanong09:06:13

ah, that is fascinating.

levitanong09:06:25

but what about API keys?

levitanong09:06:47

but wouldn’t that be exposing your API keys to the public?

levitanong09:06:05

’cause it’ll just be there in your script tag in “plaintext”

thheller09:06:06

it is just as public in your compiled JS

levitanong09:06:27

but it’s more accessible, isn’t it? 😛

thheller09:06:46

well if someone is looking for the keys they will find them

thheller09:06:57

probably by just looking at the XHR requests you are making with those keys

levitanong09:06:02

that’s true

levitanong09:06:52

i guess that’s why domain constraints are there

thheller09:06:25

yeah you don't get any more security by compiling the keys into your JS via closure defines

thheller09:06:51

but if you put them into the closure defines you have to recompile whenever the keys change (eg. prod vs staging)

thheller09:06:05

if you just pass every bit of runtime config into init that problem goes away

thheller09:06:16

and you staging builds actually use the prod JS

levitanong09:06:25

thanks @thheller! this was really helpful 😄

thheller09:06:55

might be interesting but the init(the_config) method works just fine too

levitanong09:06:38

@thheller interesting. what is that cljs function?

thheller09:06:03

just a helper that emits the script tag from above

thheller09:06:09

<script type="shadow/run" data-fn="my_app.feature1" data-ref="self">
    {config: true,
     data: big_json_blob_from_server}
  </script>

levitanong09:06:08

okay, understood.

levitanong09:06:11

thanks again!

thheller12:06:43

@wilkerlucio @bolasblack the 1.10.312 ...spec/return issue should be fixed in 2.4.6

bananadance 4
wilkerlucio12:06:45

I was a bit worried about that one, how did you manage to get around the js marking?

thheller12:06:41

checking (not (-> sym meta ::no-resolve))

thheller12:06:00

feels super hacky but couldn't come up with a cleaner solution

wilkerlucio12:06:44

well, if works 😛

thheller12:06:12

I hope it does. didn't actually verify with test.check itself, just some test code I wrote

wilkerlucio12:06:33

ok, I can verify that and let you know, will try now

wilkerlucio12:06:00

yup, generators working just fine 🙂

👍 4
thheller12:06:11

which part?

grounded_sage12:06:47

I'm thinking of using the Clojure cli and layering on other tools to create something like Gatsby in respect of compiling to a PWA with PRPL pattern etc.

grounded_sage12:06:44

I'm just curious about the caution you have there and what it really means.

grounded_sage12:06:21

Yea I have read that a few times. So you just mean that the other build tools can slow down the experience and get in the way yea?

thheller12:06:57

the shadow-cljs command has a built-in server mode

thheller12:06:09

so if the server is running it will connect to that instead of starting a new JVM

thheller12:06:30

if you use lein or clj directly they won't know about that server and start a new JVM

thheller12:06:38

which is a whole lot slower

thheller12:06:21

apart from that it has a few safeguards to avoid some dependency conflicts like accidentally using an ancient version of clojurescript

grounded_sage12:06:28

Well I am thinking for the most part there isn't any reason for using the clj for anything other than the full compilation step. When I want to do the SSR, Critical CSS inlining etc.

grounded_sage12:06:29

I'm just thinking of using the Clj-cli for SSR, Critical CSS inlining, image manipulation etc.

thheller12:06:16

you could use shadow-cljs run your.tool/css-inline ... instead of clj -m your.tool ...

thheller12:06:46

so yeah if you build it for the clj tool it will automatically work with shadow-cljs run as well

grounded_sage12:06:01

Oh wow. I hadn't read that stuff before.

grounded_sage12:06:39

This looks easier than I thought it would be 😮

grounded_sage12:06:27

Ok that will learn me for not reading the full manual!

Jeff Friesen15:06:57

@thheller I tried using :variable-renaming :off and :property-renaming :off but still getting these obscured errors. So here’s an example error

warning.js:34 Warning: Failed prop type: Invalid prop `trigger` supplied to `b`, expected a ReactNode.
    in b (created by permits.views.home.header.stats_modal)
    in permits.views.home.header.stats_modal (created by permits.views.home.header.header_bar)
    in div (created by permits.views.home.header.header_bar)
For this code:
(defn stats-modal []
  [:> sem/Modal {:trigger (reagent/as-element stats-button)
                 :basic true}
   [:> sem/Modal.Content
    [:p "example content"]]
   ])
Here’s my config:
{:source-paths ["src"]

 :dependencies [[reagent "0.7.0"]
                [re-frame "0.10.5"]
                [binaryage/devtools "0.9.10"]
                [day8.re-frame/re-frame-10x "0.3.2-react16"]
                [bidi "2.1.3"]
                [kibu/pushy "0.3.8"]
                [cider/cider-nrepl "0.17.0"]
                [soda-ash "0.81.1"]]

 :builds {:app {:target :browser
                :output-dir "public/js"
                :asset-path "/js"
                :modules {:main {:entries [permits.core]}}
                :compiler-options {:closure-defines {"re_frame.trace.trace_enabled_QMARK_" true}}
                :dev {:js-options {:variable-renaming :off
                                   :property-renaming :off}}
                
                ;; start a development http server
                :devtools {:after-load permits.core/render
                           :http-root "public"
                           :http-port 8020
                           :preloads [devtools.preload day8.re-frame-10x.preload]}

                :release {:output-dir "dist/js"}}}}

Jeff Friesen15:06:29

the error is not wrapping the stats-button. It should be (reagent/as-element (stats-button))

Jeff Friesen15:06:49

sem is from ["semantic-ui-react" :as sem]

thheller15:06:14

might be reagent?

Jeff Friesen15:06:43

It might be. Ok. There is just no config that I know of in Reagent for that.

Jeff Friesen15:06:48

But I’ll look there

thheller15:06:19

Warning: Failed prop type: Invalid prop `trigger` supplied to `Modal`, expected a ReactNode in Modal

thheller15:06:10

with just react and :variable-renaming :off

thheller15:06:36

(react/createElement sem/Modal #js {:trigger (fn [])})

lilactown16:06:58

@momoblackblack you might need to do (reagent/as-element [stats-button])

justinlee16:06:23

no that’s not the issue. there’s something funny going on with the way reagent imports components.

Jeff Friesen16:06:04

I did try that: [:> sem/Modal {:trigger (reagent/as-element [stats-button]). No errors but the button doesn’t trigger the modal. Nothing happens. The only thing that works is [:> sem/Modal {:trigger (reagent/as-element (stats-button)). Someone else said it’s maybe because of a hacky way react-semantic-ui set up those triggers that made it require a ()

justinlee16:06:17

@thheller using react-virtualized imported like so [react-virtualized :refer [AutoSizer InfiniteLoader List]] and running the following in the repl: (react/createElement AutoSizer #js {} (js-obj)) you get the Warning: Failed prop type: Invalid prop children` of type object supplied to b, expected function. in b`

thheller16:06:06

do you have :variable-renaming :off?

justinlee16:06:24

no. should I?

Jeff Friesen16:06:27

there’s that b component again ^

Jeff Friesen16:06:10

@lee.justin.m you can see my config above after @thheller suggested it

Jeff Friesen16:06:19

:dev {:js-options {:variable-renaming :off
                                   :property-renaming :off}}

Jeff Friesen16:06:06

btw, this does work: [:> sem/Modal {:trigger (reagent/as-element [:div [stats-button]]). My issue wasn’t so much getting it to work, because I eventually got it to work through trial and error. I am just trying to make future debugging easier

thheller16:06:57

beginning to think that :variable-renaming :off might be a safer default

thheller16:06:08

but it makes the code quite a bit larger after optimizations

justinlee16:06:59

that fixes it with straight react interop. trying inside reagent

justinlee16:06:18

the reason this happens is because reagent sets the display name of the component by using the .name property of the component

justinlee16:06:30

when you minimize, you get a letter like b

justinlee16:06:03

so this value changes depending on that setting:

window.module$node_modules$react_virtualized$dist$commonjs$index.AutoSizer.name
"AutoSizer"

justinlee16:06:33

the closure documentation states that it does not change function names except in advanced compilation. how are you doing that if you are not in advanced?

thheller16:06:07

guess they changed that? :simple definitely has that turned on

lilactown16:06:10

@momoblackblack I would open up an issue on reagent about how [:> sem/Modal {:trigger (reagent/as-element [stats-button])}] doesn't work

thheller16:06:38

well technically it only changes local variable names

justinlee16:06:38

confirmed that the config change fixes the issue with reagent

justinlee16:06:23

its changing the names of exported functions too

thheller16:06:23

well it depends .. exports.Foo = function Foo() {}

thheller16:06:37

exports.Foo is unchanged, function Foo() {} will be

justinlee16:06:05

I see and that’s the value reagent uses

justinlee16:06:24

Reagent should check for a displayName prop so that it would work for nonfunctional components at least. Easy fix

thheller16:06:08

I could just default :variable-naming to :off during dev

justinlee16:06:22

Unless that’s how react determines the display name ... haha

thheller16:06:35

didn't to it to avoid the situation where dev builds work but prod builds don't

thheller16:06:48

but not sure this can ever actually affect anything relevant

thheller16:06:06

its actually required for graphql so maybe its the better default

justinlee16:06:38

you should definitely add them to the user guide

nickmbailey18:06:50

does anyone have any examples of using shadow-cljs to compile clojurescript that can be pulled in as an npm dependency by regular javascript projects?

denis_krivosheev18:06:28

About this issue with react-semantic-ui. Turns out this is semantic-ui issue, not reagent

denis_krivosheev18:06:12

they take children and extend the props of the very top node with some additional hooks

denis_krivosheev18:06:24

onClick and something else

denis_krivosheev18:06:52

But if the top level node doesn’t accept these props, everythiing is going to be bad

denis_krivosheev18:06:04

so just wrapping reagent component into the native component resolves the issue:

:trigger (reagent/as-element [:div [stats-button]])

denis_krivosheev18:06:35

@nickmbailey I’m also looking for it today. This is the best example I found so far: https://github.com/loganpowell/shadow-proto-starter

denis_krivosheev18:06:56

Tested it, it works, not deployed to npm yet though

denis_krivosheev18:06:15

They clone element and extend its prop

nickmbailey18:06:46

@denis_krivosheev yeah i maybe should have been more specific in that i’m targeting the browser specifically, from what i can tell that example is meant for node (maybe it works for both?)

Jeff Friesen18:06:14

@nickmbailey Denis was commenting on a previous issue

nickmbailey18:06:02

yeah he also linked an example for my question in the middle there though 🙂

denis_krivosheev19:06:45

Yeah. It’s hard to track several themes in the same chat 😃

thheller22:06:49

hehe nice 🙂

richiardiandrea22:06:31

well we package some uncompiled cljs in there 😄

justinlee22:06:48

“just add babel-shadow-cljs-transform to your build tool chain!” no problem!

thheller22:06:34

nice to see that at least someone is aware of this in the JS world

justinlee22:06:12

dan has huge mindshare so it’s good he’s talking about it (125k followers)

richiardiandrea22:06:13

true, didn't expect that at all