mount 2018-03-15

@tolitius hello! Can you please clarify this thing for me In dev/user.my namespace I have this:

(ns 
  (:require [clojure.tools.namespace.repl :refer [refresh]]
            [mount.core :as mount]))

(defn start []
  (mount/in-cljc-mode)
  (mount/start))

(defn stop []
  (mount/stop))

(defn go []
  (start)
  :started)

(defn reset []
  (stop)
  (refresh :after ')
  :ok)

I want to to use a mount with cljs, more generally β€” sharing config on clj and cljs side So, in src/cljc I create namespace config.cljc, which look like this
(ns my-lib.config
  #?(:clj
     (:require [config.core :refer [load-env]] ;; this is yogthos/config
               [taoensso.timbre :as log]
               [mount.core :refer [defstate]]))
  #?(:cljs
     (:require-macros [mount.core :refer [defstate]])))

#?(:clj
   (defn load-config []
     (log/info "loading configuration")
     (load-env)))

#?(:clj
   (defstate ^{:on-reload :noop} config
     :start (load-config)))

#?(:cljs
   (defstate ^{:on-reload :noop} frontend-environment
     :start (:env @config)))
When I started repl, all states starting good, then I load namespase with config in repl and try to see what’s happening:
;; this is clj-repl
my-lib.config> (:env @config)
{:host "localhost", :port 3001, :database "data/dev"}

;; this is cljs-repl
my-lib.config> frontend-environment
nil

my-lib.config> @frontend-environment
#object[Error Error: No protocol method IDeref.-deref defined for type undefined: ]
cljs.core.missing_protocol@http://localhost:3449/js/compiled/app.js:129:336
cljs.core._deref@http://localhost:3449/js/compiled/app.js:223:435
cljs.core.deref@http://localhost:3449/js/compiled/app.js:366:402
@http://localhost:3449/js/compiled/app.js line 3469 > eval:1:226
@http://localhost:3449/js/compiled/app.js line 3469 > eval:1:189
@http://localhost:3449/js/compiled/app.js line 3469 > eval:1:2
figwheel.client.utils.eval_helper@http://localhost:3449/js/compiled/app.js:3469:309
What I do wrong?

Even in .cljs namespaces I can’t work with mount, for example

(ns my-lib.state
    (:require-macros [mount.core :refer [defstate]]))
In cljs-repl:
my-lib.state> (defstate a :start 12)
---- Compiler Warning on cljs form line:1 column:1 ----

Use of undeclared Var mount.core/running-noop?

1 (defstate a :start 12)
^---
---- Compiler Warning ----
---- Compiler Warning on cljs form line:1 column:1 ----

Use of undeclared Var mount.core/mount-it
1 (defstate a :start 12)
^---
---- Compiler Warning ----
---- Compiler Warning on cljs form line:1 column:1 ----

Use of undeclared Var mount.core/current-state
1 (defstate a :start 12)
^---
---- Compiler Warning ----
#object[ReferenceError ReferenceError: mount is not defined]
nil

@rustam.gilaztdinov you need to require mount as well so cljs understands how to evaluate defstate macro (i.e. since it is using mount functions):

connected! >>
To quit, type: :cljs/quit
nil
cljs.user=> (require-macros '[mount.core :refer [defstate]])
nil
cljs.user=> (defstate a :start 12)
WARNING: Use of undeclared Var mount.core/running-noop? at line 1 <cljs repl>
WARNING: Use of undeclared Var mount.core/mount-it at line 1 <cljs repl>
WARNING: Use of undeclared Var mount.core/current-state at line 1 <cljs repl>
#'cljs.user/a
but:
cljs.user=> (require '[mount.core :as mount])
nil
cljs.user=> (defstate a :start 12)
#'cljs.user/a
cljs.user=> @a
12

doesn't work for me 😞

(ns my-lib.state
  (:require-macros [mount.core :refer [defstate]])
  (:require [mount.core :as mount]))

my-lib.state> (defstate a :start 12)
#object[ReferenceError ReferenceError: mount is not defined]
nil

ok, one problem at a time

did it fix the warnings?

i.e.

Use of undeclared Var mount.core...

yes

ok, good. which browser are you using to connect to the cljs repl?

chrome

how do you start the cljs repl?

figwheel

from cider in spacemacs

there is something off in a way cljs repl (in your case) evals the forms, in this case defstate

I use neither πŸ™‚ so it is harder to debug, but could you start your cljs repl in a different way and try? for example I use "terminal" and "boot" to start the cljs repl.

do you know boot at all?

(i.e. use it)

it's really dumb -- but after lein clean mount in cljs works now! πŸŽ‰

I remember this error on cljs side when the browser could not evaluate the forms, it was caused by the faulty repl connection. since I don't use emacs/figwheel it is harder for me to guess

ah.. ok. great πŸ™‚

yea, that is one of the reasons I started using boot for everything

thx, can you help me with .cljc files?

to avoid hours of debugging that is caused by stale state introduced by lein

maybe tools.deps will help us in a future?

could be, have not used it yet (docs are interesting though)

agree

> can you help me with .cljc files? do you still have an undefined type problem?

no, another one, give me a minute, pls)

ok, I have to run, post it here. I'll look later on

I have this cljc namespace

(ns my-lib.config
  (:require
   #?@(:clj
        [[config.core :refer [load-env]]
         [taoensso.timbre :as log]
         [mount.core :refer [defstate]]]
       :cljs
       [[mount.core :as mount]]))

  #?(:cljs
     (:require-macros
            [mount.core :refer [defstate]])))

#?(:clj
   (defn load-config []
     (log/info "loading configuration")
     (load-env)))

#?(:clj
   (defstate ^{:on-reload :noop} config
     :start (load-config)))

#?(:cljs
   (defstate ^{:on-reload :noop} frontend-environment
     :start (:env @config)))

and on clj-repl config works well

I want to share this config to cljs-side

In cljs-repl, when I evaluate namespace -- I see this warning

WARNING: Use of undeclared Var my-lib.config/config at line 25 /Users/..../config.cljc

and this error

my-lib.config> @frontend-environment
#object[Error Error: No protocol method IDeref.-deref defined for type undefined: ]
   cljs.core/missing-protocol (jar:file:/Users/../.m2/repository/org/clojure/clojurescript/1.9.908/clojurescript-1.9.908.jar!/cljs/core.cljs:304:4)
   cljs.core/-deref (jar:file:/Users/../.m2/repository/org/clojure/clojurescript/1.9.908/clojurescript-1.9.908.jar!/cljs/core.cljs:659:1)
   cljs$core$deref (jar:file:/Users/../.m2/repository/org/clojure/clojurescript/1.9.908/clojurescript-1.9.908.jar!/cljs/core.cljs:1437:4)
nil

I think -- this is because defstate frontend-environment relies to @config, which is #?clj related

right:

#?(:clj
   (defstate ^{:on-reload :noop} config
     :start (load-config)))
cljs does not see that: i.e. cljs compiler does not compile this, hence config is not known on the cljs side