Fork me on GitHub
#clojurescript
<
2018-02-06
>
xiongtx00:02:43

Evaluating cljs.core/macroexpand-1 for a clj / cljs project in a clj buffer differs from the result in a cljs buffer. E.g. given a file:

(ns om-tutorial.core
  (:require [om.dom :as dom]
            [om.next :as om :refer-macros [defui]]))

(defui HelloWorld
  Object
  (render [this]
          (dom/div nil (get (om/props this) :title))))
Callling cljs.core/macroexpand-1 '(defui ...) in a clj buffer does nothing, which calling it from a cljs buffer gives:
(do
 (do
  (clojure.core/defn
   HelloWorld
   []
   (cljs.core/this-as
    this__41180__auto__
    (.apply js/React.Component this__41180__auto__ (cljs.core/js-arguments))
...
as expected. Why is this?

xiongtx01:02:32

Refining the question: what is the env being passed to cljs.analyzer/macroexpand-1? Right now CIDER passes the cljs compiler env, which doesn’t seem right.

Charleshd09:02:20

I have an issue with clojurescript 1.9.946

Charleshd09:02:32

when I try to compile my codebase with 1.9.908 I have no worries, but when I do with 1.9.946 I get the following error : No reader function for tag Inf

Charleshd10:02:24

I guess it comes from Clojure 1.9.0 new tag litterals for Inf and NaN. But I don't see why there was no problem with 1.9.908

Charleshd10:02:55

Looks like CLJS-2352 should had fixed that. Maybe I have an old lib somewhere

thheller11:02:53

@chu this is cause by an outdated tools.reader version somewhere in your deps

thheller11:02:34

you can either add [org.clojure/tools.reader "1.2.1"] to your deps directly to ensure you get a compatible version

thheller11:02:53

or upgrade whichever library is bringing in the old one

thheller11:02:03

lein deps :tree should complain about a conflict

roklenarcic13:02:02

I'm using Figwheel and nREPL, but I don't understand how importing namespaces works in clojurescript. I use (ns myns) to change to my ns, but any of my symbols I try to evaluate are reported to be undefined

dnolen13:02:36

@roklenarcic (in-ns 'myns) is what you want

dnolen13:02:36

(ns ...) is only for defining namespaces

bmaddy15:02:10

Does anyone know the trick to getting gen/generate working in cljs? Here's what I'm trying:

cljs.user> (require '[cljs.spec.alpha :as s])
nil
cljs.user> (require '[cljs.spec.gen.alpha :as gen])
nil
cljs.user> (gen/generate (s/gen int?))
#object[Error Error: Var clojure.test.check.generators/simple-type-printable does not exist, clojure.test.check.generators never required]
The relevant part of my :dependencies:
[org.clojure/clojure "1.9.0"]
[org.clojure/clojurescript "1.9.946"]
[org.clojure/test.check "0.9.0"]
Is there somewhere I should be looking for an example of how to do this in cljs? I couldn't find anything on http://clojurescript.org or in the official spec guide.

Charleshd15:02:41

@thheller Thanks ! I'll try asap to add a recent tools.reader

Charleshd15:02:43

It worked 👌

tungsten18:02:35

In theory - should I be able to add material-ui-next as a npm-deps compiler option and be able to use it? Not sure if it picks up the module type correctly

justinlee19:02:20

in my experience npm-deps is kind of a crap shoot. it apparently depends on how that module specifies its require statements. for instance, i tried to use it with react-dnd and it dies (I think) because that module has a require('react') statement in its UMD header. but at any rate I couldn’t get it to work so i just used foreign-libs

juhoteperi19:02:01

@lee.justin.m Not sure what you mean, if module works with CommonJS/ES6, it should work with npm-deps, even if it uses UMD module (which react-dnd doesn't seem to use)

juhoteperi19:02:09

(should work = if Closure-compiler and ClojureScript were complete, which they aren't currently)

justinlee19:02:22

really? the fully built minified version that you grab off of a CDN seems to have UMD header

juhoteperi19:02:41

But npm-deps won't use that file, it will use one from npm

juhoteperi19:02:02

Which is just CJS module compiled by Babel or something: https://unpkg.com/[email protected]/lib/index.js

justinlee19:02:37

i dunno. i’m not an expert in all of these competing module standards (and, ironically, I never had to be to get things done in javascript). all i know is that i added

:npm-deps {:react-dnd "2.4.0"}
:install-deps true
to my project.clj and it died with a
Error: Can't resolve 'react' in
error

juhoteperi19:02:38

Ah yes, the npm package also contains browserified UMD module under dist/ but package.json main property points to lib/index.js so that is what will be used

juhoteperi19:02:55

React-dnd lists React as peer-dependency, so it won't get automatically installed, you need to list React on :npm-deps also

justinlee20:02:36

I see. There’s a difference between having it in your normal dependencies and your npm-deps I guess? Basically this is what I tried before I gave up and tried it a different way: https://gist.github.com/jmlsf/d691e53e1fea4019a393412f781e2561#try-1-lets-use-npm-deps

justinlee20:02:10

it was super hard for me to figure out what npm-deps was actually doing

raheel20:02:01

I was in a similar boat till recently. A newbie who wanted to be able to use libraries via npm without having a deep understanding of the build setup. I am a very happy user of shadow-cljs now: https://shadow-cljs.github.io/docs/UsersGuide.html. Do give it a try

justinlee20:02:24

Yea next foreign lib I need to add I’m giving it a try. I’m a little worried that it’s going to mess up my tooling so I’m not messing with it until I need to

juhoteperi20:02:20

Normal dependencies would be the cljsjs/react foreign-lib? Foreign-libraries and Node packages won't work together

justinlee20:02:44

i mean, i’m using something like reagent, which is already importing react. i guess I should have excluded it and then imported it using npm-deps? but it isn’t clear to me if reagent would then be able to get to react if i import react using npm-deps

juhoteperi20:02:09

Reagent 0.8 will fix this, you can check the changelog for details

Michael Stokley20:02:00

can i ask a really naive question about clojurescript? does it "merely" compile to js or are there also libraries for dom manipulation similar to jquery?

justinlee20:02:27

@michael740 clojurescript itself is just a compiler. But it interoperates with JavaScript so you can certainly manipulate the dom using jquery itself, or react. There are cljs libs like reagent and rum that wrap react to look like more idiomatic clojure code.

benreyn20:02:57

@lee.justin.m Do you know if there are any tutorials for reagant or rum that show Clojurescript along side Javascript that would accomplish the same goal?

justinlee20:02:21

What do you mean by alongside?

benreyn20:02:21

I mentioned something to this effect in the #cljsrn room, but Im having trouble seeing how the two equate. Im pretty new to clojurescript but have a decent amount of Scheme / Elisp experience, And im pretty fresh in the React world

benreyn20:02:02

Like… Here is a simple react App / Component that does x and here is the equivalent component in clojurescript / reagant

benreyn20:02:19

A great one would be tic tac toe game from the official react tutorial

Michael Stokley20:02:17

I'd also be interested to see something like that

Michael Stokley20:02:51

something even simpler might be helpful, too - simpler dom manipulation / event handling, for example

Michael Stokley20:02:17

(please excuse these comments if this is not the proper channel or forum for this topic)

justinlee20:02:50

well, there’s the infamous todomvc example. you could compare the various pure react flavors: http://todomvc.com/examples/react/#/ with the various cljs flavors: https://github.com/gadfly361/cljs-todomvc

Michael Stokley20:02:56

which is lighter-weight, om or reagent?

justinlee20:02:04

i do everything in reagent, and I think these super complicated frameworks are totally the wrong way to do things if you are just learning. they add about 6 layers of indirection to everything, which is only beneficial if you have a large app and/or a large team. fulcro is a bit different since it is trying to do the whole stack from database to frontend in an idiomatic clojurey way, but i haven’t used it

Michael Stokley20:02:21

reagent looks good. it looks super plain. i guess you'd need to be familiar with react/vue conventions, but still

Michael Stokley20:02:56

in the rendered js, is it easy to expose an interface?

justinlee20:02:32

i’m not sure what you mean

justinlee20:02:26

and regarding reagent, eventually it will be helpful to know react, but one of the weirder things about it is that it actually does not look like react at all.

justinlee20:02:40

also: some of the best documentation on reagent is actually on the re-frame site: https://github.com/Day8/re-frame/wiki/Creating-Reagent-Components

Michael Stokley20:02:57

like, suppose i'm building a module and i want to expose a function that could be called by other code in the larger project. i suppose that function would be translated into vanilla js?

justinlee20:02:06

one day i will collect all the documentation for reagent and submit a PR

justinlee20:02:59

you can call cljs code from js and vs versa

justinlee20:02:22

there is some marshalling you have to do to get in and out of cljs collections but it’s pretty straightforward

tungsten20:02:33

use figwheel template and start playing around. That's that fastest way to get a handle on reagent

justinlee21:02:23

@bfast you know it’s a bit unfortunate that guide is sitting out there on a third-party website. that guide is basically what i had in mind in terms of submitting to reagent. that’s basically what the reagent readme should look like

dehli21:02:29

Is it possible to mock a function before you require it in your test?

dehli21:02:49

I have a function that executes right when the namespace is loaded, and i’d like to mock it out

noisesmith21:02:07

never run code at the top level of a namespace

noisesmith21:02:28

(other than defining constants with no side effects, or functions you might call later of course)

noisesmith21:02:55

you can use with-redefs, but that doesn't work before loading the namespace containing the definition

noisesmith21:02:08

and even with-redefs has pitfalls

dehli21:02:00

Thanks. The reason I’m doing it is b/c it’s a lambda function, and I’d like to run some setup code right when the function boots. I can probably stick it in the handler function though. What sort of pitfalls?

noisesmith21:02:47

it is a global change - and come to think of it it probably doesn't even work in cljs

dehli21:02:00

I’ve used with-redefs in clojurescript

noisesmith21:02:02

it's less tricky in cljs than clj - the main drawback would be that laziness that escapes the block would call the original definition if realized later

noisesmith21:02:26

but with-redefs can't mock out a function in code that hasn't even loaded yet

dehli21:02:45

Ya, I noticed that while I was writing tests. Future tests would continue using the mocked version. I forgot what I had to do to fix it.

dehli21:02:22

Thanks! I’ll see if lambda itself has an onload i could hook into

noisesmith21:02:38

if some function needs other setup to run, that would be the job of your top level code, to set up any initialization needed. Putting it at the top level of the namespace breaks things like tests.

jmromrell22:02:34

I'm having trouble creating a reagent component that can accept other components as parameters. Is that something that is supported?

noisesmith22:02:54

a common idiom is to have a -init function for each namespace that needs it, with documentation that a consumer must call it before using applicable code

dehli22:02:19

I like that. Thanks again for your help!

dehli22:02:01

Yep. How are you passing them?

jmromrell22:02:07

(defn simple-node [node-content & children]
  (let [node-state (r/atom {})]
    (fn [node-content & children]
      [:li.tree-node
       [:div.tree-content node-content]
       [:ul.tree-body
        (doall (for [i (range (count children))]
                 (let [child (nth children i)]
                   (with-meta child {:key i}))))]])))

jmromrell22:02:34

I am trying to create a tree view where each node is a component with its own internal state (expanded, collapsed, etc.)

dehli22:02:56

what’s with-meta look like?

dehli22:02:33

Oh, it’s a built in function

jmromrell22:02:34

I'm using that to attach keys to the children after the fact, since they don't know their index when provided

jmromrell22:02:42

This is what a use-case looks like

jmromrell22:02:45

[simple-node [:p (session/get [:a])]
 [simple-node [:p (session/get [:b])]
  [simple-node [:p (session/get [:c])]]]]

jmromrell22:02:24

Ideally, I'd want each to update independently as their corresponding values change, so I don't have to rerender all children

dehli22:02:29

Could you try wrapping the last line in []?

jmromrell22:02:00

[(with-meta child {:key i})] or [with-meta child {:key i}]?

dehli22:02:09

the first one

jmromrell22:02:27

Uncaught Error: Invalid arity: 0

jmromrell22:02:57

My current use case, as shown above, will render initially, but when I change a referenced value in the session, I get either:

jmromrell22:02:08

Uncaught DOMException: Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node.

jmromrell22:02:32

Uncaught TypeError: Cannot read property 'getHostNode' of null

jmromrell22:02:56

I can get something like this to render without errors https://codepaste.net/c5djck , but updating the value one node references, will cause all nodes to re-render