Fork me on GitHub
#clojurescript
<
2019-11-23
>
Jacques Desmarais12:11:53

Hello! Does (def x) actually do anything, aka does it get translated to a line of code in Javascript?

Jacques Desmarais13:11:59

so after some testing… (def x) definitely does something. After all, if you do (def x) (def x), the compiler complains that x is being redefined. I was trying to figure out a variable’s namespace using resolve and when I saw that (def x) (resolve 'x) returned nil, I was puzzled. But probably a better way of getting a variable’s namespace is doing (:ns (meta #'x)), and using that technique definitely returns the namespace of x even if it is defined using (def x) i.e. without an initial value.

lilactown16:11:38

if you pasted in

(def x)

#'x
you'll see the var that contains the ns metadata etc.

lilactown16:11:12

that information gets stored in the cljs analyzer, but it looks like CLJS doesn't by default emit any JS for just (def x)

Jacques Desmarais18:11:24

ok, got it, thanks!

Eliraz19:11:12

what do you guy use for css-in-js in clojurescript?

lilactown20:11:08

I've had success wrapping emotion

Eliraz20:11:11

oh okay.. I guess you didn't try cljss

roman01la20:11:36

Prefer emotion over cljss, it doesn't really get you anything. Cljss is gonna adopt emotion at some point

Eliraz20:11:29

what do you mean it doesnt get you anything?

Eliraz20:11:35

and how did you wrap emotion?

roman01la20:11:54

You don't need to wrap emotion, use it directly, it's super simple

roman01la20:11:20

Unless you need server side rendering , but cljss doesn't support it anyway

lilactown23:11:27

would it be possible to create a Clojure namespace and intern a var at macroexpansion?

thheller23:11:49

clojure yes, cljs no. see create-ns

lilactown23:11:06

hmm. I specifically want to do this when using a macro in a CLJS file

lilactown23:11:03

(ns my-app.core
  (:require [hx.core :as hx :refer [defnc]])

(defnc MyComponent []
  (d/div "foo"))
Would create MyComponent in the CLJS namespace, and potentially create a Clojure namespace my-app.core and intern a macro like:
(defmacro my-component []
  `(create-element MyComponent))
so that the macro would be available within the namespace and to consumers who require it

lilactown23:11:28

it's probably way too complicated but I'm just trying to cut down on boilerplate

thheller23:11:19

for that to work the user would need to have (:require-macros [app.core]) in app.core

lilactown23:11:09

yeah, and it's in a weird state because the macroexpansion would have to happen before resolving the macro ns which is... not how it works

thheller23:11:26

I thought you are creating function components? why not defnc my-component emitting a (defn my-component?

lilactown23:11:01

the components are defined as functions, but you don't want to call them as functions. you need to create a React element from them

thheller23:11:29

isn't that what you fragment macros does? I mean [my-component {:foo "bar"}]?

lilactown23:11:03

right, if you use hiccup syntax you don't really need to worry about it

lilactown23:11:35

I'm playing with getting rid of hiccup syntax and using factory functions or create-element directly

lilactown23:11:38

($ MyComponent) or (defn my-component [] ($ MyComponent))

lilactown23:11:04

no matter what I try, I feel like I concede either interop, performance or ergonomics. I hate hiccup but going back to factory functions maybe isn't really better?

thheller23:11:38

guess why I'm writing my own stuff? trying to make react happy sucks 😛

lilactown23:11:51

😂 yes trying to follow the JS ecosystem is painful

lilactown23:11:15

maybe I am suffering from sunk cost fallacy at this point

thheller23:11:36

one thing I experimented with was a macro emitting a my-component defn which would be the factory fn. it would then emit a secondary "hidden" function that you could get to when needed by calling @my-component

thheller23:11:55

basically using specify on my-component to implement IDeref

lilactown23:11:13

oh that's neat!

thheller23:11:37

that kinda worked ok since you very rarely need the actual function for much

thheller23:11:28

assuming of course no hiccup syntax 😛

lilactown23:11:54

yeah, the way I do factory functions right now is it specifies a custom protocol that does something similar

(hx/type my-component) ;; => the actual Component type (class/function)

lilactown23:11:56

the thing I am trying to avoid is defining a map that just gets thrown away

lilactown23:11:04

if I use a factory function, then the props that get passed: creates a map, turns it into a JS object, then React takes that JS object and copies when it creates the element...

lilactown23:11:53

I have a macro that, when used, will always emit a JS object instead of creating a map. but it's tedious to create factory macros in a separate file

thheller23:11:08

geez no don't turn them into a JS object

thheller23:11:59

mine would do (defn my-component [props] (react/createElement my-component* #js {:secret$props props}))

thheller23:11:07

and the component would access that secret$props. never actually translating to JS object

lilactown23:11:07

that works, except when you are working with: 1. native elements 2. a lib that expects to be passed Component

thheller23:11:28

native components don't ever go through those factory functions so thats not a problem

thheller23:11:50

things that expect a Component would get @my-component which would do the js->clj

thheller23:11:53

let me see if I can find that code somewhere ... I'm sure its in some branch somewhere

thheller23:11:04

can't find it but note that I opted out of that approach because it generated too much code

thheller23:11:40

so it isn't exactly ideal to generate 2 functions with a bit of boilerplate per component

lilactown23:11:31

yeah good point