Fork me on GitHub
#shadow-cljs
<
2018-02-08
>
mjmeintjes03:02:40

@mynomoto Here you go: https://reagent-project.github.io/news/news060-alpha.html, check the "Better interop with native React"

armed05:02:53

Hey, could somebody point me example with shadow-cljs on frontend and clojure as a server? Is this worth doing or just use classic figwheel approach?

armed05:02:19

Nwm, figured out. Was easier than expected

orestis09:02:40

Any success stories in using shadow-cljs to write node servers? Piggy-backing onto popular “mainstream” JS libraries (e.g. Express et al) while keeping the business logic in CLJS.

thheller09:02:57

I think it is very common for most people to use Clojure on the server side (I do personally) so CLJS on the server is not too common yet.

orestis09:02:22

Apparently so… unfortunately having a REPL-driven with Node is a bit frustrating. I managed to get a working nREPL CLJS connection from Atom to shadow-cljs, but it’s still a bit flaky.

orestis09:02:14

The reloading story is much better though, and for people coming over from JS it should be a familiar experience.

thheller09:02:09

I don't do much node development so if there are things that could be improved from the CLJS side let me know

orestis10:02:24

One immediately obvious thing is that compilation failures didn’t show up in Atom. Given the multitude of moving parts, I’d like to do some triaging before creating bug reports, it could be my fault, or proto-repl, or some other thing…

thheller10:02:24

what you can do is run shadow-cljs from a terminal inside atom

thheller10:02:36

terminal-plus or something like that

thheller10:02:45

I don't know it proto-repl shows any stdout output from the REPL.

mitchelkuijpers10:02:04

I am trying out shadow-cljs 2.1.4 we are coming from 2.0.x and we get babel errors for some reason.. Was there a change that triggers this?

mitchelkuijpers10:02:36

ReferenceError: [BABEL] shadow$empty.js: Unknown option: /home/mitchel/Development/atlas-crm-next/node_modules/react/react.js.Children. Check out  for more information about options.

A common cause of this error is the presence of a configuration options object without the corresponding preset name. Example:

Invalid:
  `{ presets: [{option: value}] }`
Valid:
  `{ presets: [['presetName', {option: value}]] }`

mitchelkuijpers10:02:05

Oh I had a .babelrc that was causing this.. Sorry for the noise

thheller10:02:34

.babelrc should be ignored for files in node_modules so if that wasn't an issue before thats definitely a bug

mitchelkuijpers10:02:44

That might be a bug then.. Btw really loving the new loading indicator

mitchelkuijpers10:02:13

And the warnings look a lot better too

thheller10:02:15

k, I'll check it out

mitchelkuijpers10:02:36

But it also said I had a configuration error so it might be my fault

thheller10:02:12

yeah but it shouldn't even be looking at .babelrc so it shouldn't matter whats in there

wilkerlucio11:02:06

hello, I'm getting a weird warning from shadow-cljs:

wilkerlucio11:02:09

------ WARNING #1 --------------------------------------------------------------
 File: /Users/wilkerlucio/Development/pathom/src/com/wsscode/pathom/core.cljc:70:1
--------------------------------------------------------------------------------
  67 |                     (gen/call-gen g rdn size))
  68 |                   (gen/call-gen (gen/return []) rdn size)))))))
  69 |
  70 | (s/def ::mutation-expr
-------^------------------------------------------------------------------------
 No such namespace: operation.on, could not locate operation/on.cljs, operation/on.cljc, or JavaScript source providing "operation.on"
--------------------------------------------------------------------------------
  71 |   (s/with-gen
  72 |     (s/and list? (s/cat :mutate-key symbol? :params (s/? ::params)))
  73 |     #(gen/let [key (s/gen '#{do-something create/this-thing operation.on/space})
  74 |               val  (s/gen ::params)]
--------------------------------------------------------------------------------

wilkerlucio11:02:25

operation.on? my doesn't mention that at all

wilkerlucio11:02:41

started happening after loading test.check and generator things

thheller11:02:37

most likely the :require-macros thing again .. this is really beginning to bother me.

thheller11:02:16

is this just test.check or do you have any macros involved in this?

wilkerlucio11:02:39

just test.check and spec, these are my requires:

wilkerlucio11:02:45

(ns com.wsscode.pathom.core
  (:refer-clojure :exclude [ident?])
  (:require
    [clojure.spec.alpha :as s]
    [clojure.set :as set]
    [clojure.test.check :as tc]
    [clojure.test.check.generators :as gen]
    [clojure.test.check.properties :as prop]
    [clojure.walk :as walk]
    [fulcro.client.primitives :as fp]
    #?(:cljs [goog.object :as gobj]))
  #?(:clj
     (:import (clojure.lang IAtom IDeref))))

thheller11:02:59

seems like a bunch of stuff is relying in this broken behaviour 😞

thheller11:02:42

at this point I feel like giving up and just adding the broken stuff

wilkerlucio11:02:48

I tried to add :include-macros on all of then, but no effect

thheller11:02:09

no the test.check stuff doesn't do it correctly (internally)

thheller11:02:30

nothing you can do really

thheller11:02:12

I have to finish some work stuff. I'll look into this after

wilkerlucio11:02:02

thanks, what is been done wrong? does test.check has to require itself? just trying to understand

thheller11:02:19

see the CLJS issue, it is missing the :require-macros for itself in .cljc files with macros

thheller11:02:43

might also be spec itself

thheller11:02:15

so the gen/let macro is not handled properly internally I assume

thheller11:02:21

back to work

thheller12:02:50

@wilkerlucio I just noticed that (s/gen '#{do-something create/this-thing operation.on/space}) is in your code?

thheller12:02:20

is spec maybe trying to resolve that?

thheller13:02:37

@wilkerlucio [clojure.test.check.generators :as gen :include-macros true] this seems to work?

thheller13:02:06

but I'm not getting a compile error without it, only an error at runtime?

thheller13:02:23

do you have the full code available so I can test this in your setup?

wilkerlucio13:02:26

@thheller sorry the delay, was in meetings

wilkerlucio13:02:32

actually my code has that, but it's quoted (sorry bad info before, didn't even occurred to me to look at quoted things)

wilkerlucio13:02:38

it shouldn't try to eval it

wilkerlucio13:02:57

(s/def ::mutation-expr
  (s/with-gen
    (s/and list? (s/cat :mutate-key symbol? :params (s/? ::params)))
    #(gen/let [key (s/gen '#{do-something create/this-thing operation.on/space})
              val  (s/gen ::params)]
       (list key val))))

wilkerlucio13:02:01

I can send the full source in a min

thheller13:02:03

(do ;; s/def ::mutation-expr
  (s/with-gen
    (s/and list? (s/cat :mutate-key symbol? :params (s/? ::params)))
    #(gen/let [key (s/gen '#{do-something create/this-thing operation.on/space})
               val  (s/gen ::params)]
       (list key val))))

thheller13:02:11

this compiles fine

wilkerlucio13:02:44

I'm going to try a few things, just at work now, limited time, probably going to do more later once I get home

wilkerlucio13:02:35

(def sample-mutations '#{do-something create/this-thing operation.on/space})

(s/def ::mutation-expr
  (s/with-gen
    (s/and list? (s/cat :mutate-key symbol? :params (s/? ::params)))
    #(gen/let [key (s/gen sample-mutations)
              val  (s/gen ::params)]
       (list key val))))

wilkerlucio13:02:01

but that' weird, why I can't use the quoted directly there? I can try on pure cljs to see if it's a problem with cljs ou shadow, not sure at this point

wilkerlucio13:02:05

on clojure side this is not an issue

thheller13:02:51

clj build.clj
WARNING: No such namespace: operation.on, could not locate operation/on.cljs, operation/on.cljc, or JavaScript source providing "operation.on" at line 9 src/test/foo.cljs
WARNING: No such namespace: create, could not locate create.cljs, create.cljc, or JavaScript source providing "create" at line 9 src/test/foo.cljs

thheller13:02:08

default cljs fails as well

wilkerlucio14:02:36

thanks for helping with this debug

wilkerlucio14:02:00

I'm looking if there is an issue on Jira, seems not, I'll open one

thheller15:02:34

I'm trying to get back into blogging. I'll try to capture most of features of shadow-cljs and why they exist in future posts. https://twitter.com/thheller/status/961626241655812097

justinlee17:02:04

you know @thheller when i read through all the work you’ve done on this project, I sometimes wonder if it wouldn’t have been easier if the cljs compiler just did DCE analysis itself on the clojurescript side, then produced normal javascript code that was bundled by webpack, skipping the entire google closure compiler step.

orestis18:02:52

I don’t think when CLJS started out that it was feasible to do that — closure was probably the right decision back then.

wilkerlucio18:02:54

and the Closure Compiler compilation is still one of the best available, also we leverage the goog apis, when CLJS was build this was all state of art

orestis18:02:10

Arguably it still might be.

wilkerlucio18:02:14

yeah, but I guess the thing was to pick something robust, and the closure toolset is a good candidate, after all this is what google was using to build their major apps like gmail

justinlee18:02:57

oh yea i’m sure it was the right choice then. i am really just curious whether symbol renaming is worth it.

justinlee18:02:39

i’m just being selfish in terms of what I want: I think my life would be easier if the cljs portion of my code just built itself into a self-contained js package and interacted with npm modules just like other js code and let me do the packaging with webpack.

colindresj18:02:59

@thheller any interest in a PR for a CLI command that will auto generate a deps.cljs file from the package.json dependencies?

orestis18:02:57

@lee.justin.m isn’t it possible to do this today? It is my impression that with shadow you can create an “npm module” that exports something and then you can consume it as you like.

pepe18:02:25

The problem with shared code, you mention in the article is exactly my problem. I have an app that have two client SPAs, one node rest server and couple of small node services. With shadow-cljs I am actually starting to see the light on the end of the tunnel. Only thing that bother me now is the #dailyprogrammer compatibility for the front end SPAs development. My workflow is very dependent on its functionality.

justinlee18:02:49

@orestis that doesn’t solve the symbol renaming problem or the fact that you have to do so much work to call javascript from cljs. anyway sorry, it’s way off topic. i didn’t mean to clutter the channel.

orestis18:02:09

Things that are exported should be not be renamed, I’m fairly certain that both shadow and the CLJS compiler can do that. Calling cljs from JS should not be that problematic given that CLJS functions are JS functions. You may have to write a JS shim layer on top though.

justinlee18:02:22

Yea I get all that. It’s just super error prone and clumsy as hell. That’s why people write libraries like cljs-oops just to avoid using externs. The npm integration is also clumsy, which is in part why we have shadow-cljs. If you are a medium level programmer like me who doesn’t fully understand (1) the internals of the google closure compiler, (2) the internals of cljs, (3) the intricacies of npm modules resolution and management, then it is a total nightmare to port an existing javascript website over. I don’t really know the answers, but I will say that it seems to me a lot of this chaos stems from (1) the fact that clojurescript takes over dependency management instead of integrating into the js ecosystem way of doing dependency management (2) symbol renaming

justinlee19:02:56

just as an example: these are the notes I took for myself as I worked through all this stuff https://gist.github.com/jmlsf/d691e53e1fea4019a393412f781e2561

wilkerlucio19:02:45

you can mark a symbol as external, so it doesn't get minified eg (def ^:extern some-thing)

wilkerlucio19:02:06

I don't remember for sure if that is the correct keyword, but I'm pretty it exists

justinlee19:02:34

i realize there exist solutions. my point is that they clumsy and error prone and the documentation and tooling around this stuff is crazy complicated. my original point is that if we didn’t do symbol renaming, we could just call javascript and vs versa without any worries.

thheller19:02:17

@lee.justin.m your notes are impressive and I feel your pain. shadow-cljs does things differently precisely because of the things you describe

thheller19:02:33

CLJS itself is pretty broken and clumsy indeed

thheller19:02:19

externs are still a challenging subject but variable renaming is one of the most important things when it comes to saving bytes. so we can't really get away from that.

thheller19:02:40

especially with the huge names CLJS generates for its fns.

thheller19:02:06

externs inference is actually pretty reliable today and will spot most of the issues. I have completely removed all externs from my builds and completely rely on the inference. https://shadow-cljs.github.io/docs/UsersGuide.html#infer-externs

thheller19:02:31

but again ... in CLJS it is still very unreliable

justinlee19:02:20

@thheller well i just did a git checkout -b shadow so i’ll let you know in a few hours how it goes 😛

justinlee19:02:49

the nightmare now is figuring out what this infernal leiningen template is doing for me to so i can use shadow instead

thheller19:02:59

if it is anything but npm install react-dnd and (:require ["react-dnd" :as dnd]) let me know 😉

thheller19:02:30

although IIRC react-dnd did some fancy stuff with HoC components and ES7 decorators

justinlee19:02:33

well i just mean i have this giant lein thing that some tool created for me that has a ring handler and figwheel and piggieback and all this stuff i don’t fully understand

justinlee19:02:51

i’m hoping i can just start a shadow watcher and things will work

thheller19:02:09

@lee.justin.m :npm-module does what you asked. processes CLJS with closure but lets you do the final packaging with webpack or others. I still consider the Closure Compiler to be the most advanced JavaScript tool out there so there are no other options for me.

thheller19:02:29

@colindresj I'd prefer if that was just a normal clojure function so ALL tools could potentially benefit from it. you can run shadow-cljs clj-run your.tool/build-deps-cljs ... to execute it. similary lein run -m your.tool/build-deps-cljs ...

colindresj20:02:28

@thheller that’s what I’m doing on my own, but was wondering if it would be worthwhile to have it available for others when they use shadow-cljs

thheller20:02:10

I'm strill trying to figure out how I want to approach publishing libraries with shadow-cljs. I really wish there was a tool agnostic way of doing this. your fn would fit well into such a tool

thheller20:02:25

not so much into shadow-cljs itself at this point since you can't use it to publish libs yet 😛

colindresj20:02:11

Haha right, that makes sense

colindresj20:02:50

Might put my function up on clojars or something and mention it here in case anyone else is doing libs with shadow-cljs

thheller20:02:35

happy to include it in the readme/docs. still need to write that chapter on publishing libs

justinlee21:02:31

dumb question: what URL am I supposed to load once I have my watcher going? I tried to load but I get a shawdow-cljs generated webpage that has a link to Release Snapshots instead of my index.html

thheller21:02:15

@lee.justin.m you need to configure a separate webserver for your build. see https://shadow-cljs.github.io/docs/UsersGuide.html#_http_server

thheller21:02:18

9630 is the server for shadow-cljs itself which will eventually serve the GUI

justinlee21:02:20

okay i see. i think that’s working (although :http-handler {:http-handler shadow.http.push-state/handle}) gave me this error ClassCastException: clojure.lang.PersistentArrayMap cannot be cast to clojure.lang.Named. now my program is broken in some other way but it does appear to be loading.

justinlee21:02:23

is main! a convention for the entry point? i just followed your medium article and changed my code to use that symbol. in the lein template i had been using, it needed an init! symbol

thheller21:02:24

do you need push-state? it is optional and should just be :http-handler shadow.http.push-state/handle not nested in itself 😛

thheller21:02:57

the medium article was written by @jiyinyiyong. no it is not convention. I always recommend the init/start/stop setup in my template.

thheller21:02:50

ie. call init from HTML, which calls start. live reload calls stop :before-load, then start :after-load

justinlee21:02:31

the push-state issue was my fault doh!

justinlee21:02:57

spiffy. that’s working and, unlike 80% of the time with cljs, I actually understand why 🙂

justinlee22:02:17

by the way, i meant to say that the tweaked http section is very nice.

thheller22:02:38

I also tweaked the config specs so the error you run into with :http-handler gets a reasonable error. keep the feedback coming if you run into anything. it helps a lot.

justinlee22:02:14

one small thing: for some reason, shadow is loading the minified development version of react. I tried to add

:js-options {:resolve {"react" {:target :npm
                                                   :require "react/dist/react.js"}}}}}}}
but it doesn’t seem to change anytning