Fork me on GitHub
#clojurescript
<
2018-03-06
>
justinlee00:03:56

looking at another library’s source code: what would be the motivation for defining a function in one namespace and then using set! to put it another namespace like this (set! comp/as-element as-element)?

dpsutton00:03:56

Breaking a circular reference?

justinlee00:03:21

yea there’s a comment about that

justinlee00:03:28

now that you mention it

justinlee00:03:24

but i thought that’s what declare was for

noisesmith00:03:33

you can't declare something in a different namespace

noisesmith00:03:41

a third namespace, either used by both cyclic ns or using both, will usually resolve these things

noisesmith00:03:07

or a first class function argument, or protocol or multimethod - the fact that there's so many answers is proof none of them are great

justinlee00:03:44

i’m sure i’m being silly here, but if you can use declare to essentially tell the compiler to chill for a second on undefined functions, why doesn’t a refer to another namespace do the same thing?

noisesmith01:03:49

what does refer have to do with this? declare only creates vars in the current ns

justinlee01:03:30

i just don’t have a good enough grasp on the way clojurescript namespaces work to ask a smart question here. 🙂

noisesmith01:03:43

oh, and require is depth-first - the rest of your ns is not loaded until all transitive requires namespaces successfully load

boris01:03:17

Poking around latest cljs.main goodness - is there a way to recompile compiled namespaces from the repl so that a ns :reload will get file edits?

boris01:03:30

or do i need to run compiler from another term?

noisesmith01:03:19

require with :reload should recompile the source file and load the result in the repl

boris01:03:51

reviewing the pre-release quick start docs - if I “(require ’[hello-world.core :as hello] :reload)” (keep in mind this has some react code and was “pre-compiled” with cljs.main -c option. (i.e. clj --main cljs.main -c hello-world.core --repl)

boris01:03:09

then it doesn’t recompile

boris01:03:11

if in another term i just “clj --main cljs.main -c hello-world.core” then it updates

noisesmith01:03:22

oh, I misunderstood (since require always compiles, I lost the "precompile" destinction)

boris01:03:15

assuming it’s possible to hook in from repl but no idea how

boris01:03:48

quickstart guide is looking amazing but i think some sort of lo-fi recompile instruction would cap it off

boris01:03:27

yeah i think that happened too at some point

mfikes01:03:38

If you are on macOS or Linux, you can revise deps.edn to instead specify a git dep on the latest ClojureScript master :sha to see if it goes away.

boris01:03:12

there’s a fix in master?

mfikes01:03:05

Revising deps.edn to

{:deps {org.clojure/clojurescript {:git/url "" :sha "54b0486dbecc2ec9e6018b308f805d612bb302bb"}}}
instead of the one in the draft Quick Start would result in using the latest from master.

jimbob01:03:38

can you reload a file being in the same namespace?

boris01:03:49

looking good

noisesmith01:03:58

@ben.borders yes, there's no restriction on that

jimbob01:03:07

(in-ns ’blah :reload)?

jimbob01:03:16

>blah.clj (use ’blah :reload)

jimbob01:03:20

one of those?

noisesmith01:03:35

use or require, either one, with the :reload argument

jimbob01:03:53

ah ok, cool.

mfikes01:03:35

In summary @ben.borders

(in-ns 'blah)
(require 'blah :reload)

boris01:03:03

yes definitely success @mfikes

mfikes01:03:10

(You don't have to be in a namespace to reload it. But it often makes testing the vars in it easier.)

mfikes01:03:28

@boris834 Cool. To really perform a valid test, you would have to clone the ClojureScript repo, and script/build and use the resulting version number as your :mvn/version. (This is because using ClojureScript as a git dep disables the shared AOT cache logic that I believe was behind CLJS-2614,)

mfikes01:03:17

But using ClojureScript as a git dep, gets you up and running.

boris01:03:13

yeah i’m seeing possible cache issues (having to :reload ns twice to get expected behaviour)

boris01:03:42

and yet working fine now after a repl restart … i seem to dirty up /out easily at the moment and need to blast it

mfikes01:03:47

As an aside, for those interested, there is a tremendous amount of caching goodness that occurs when you use ClojureScript as a built maven dep (both at the Clojure level (AOT), and the ClojureScript level (shared AOT cache)), and you lose that when using ClojureScript as a git dep, but it a great fallback if you need a bug fix that is in master.

mfikes01:03:11

@boris834 Cool. If you happen to see any issues, by all means log one in JIRA. (ClojureScript 1.10.x is at a point now where the code is complete, and documentation is being polished, and bugs are being found and fixed.)

boris01:03:49

i’ll try to recreate issue and do the “valid test” you mentioned. Working as expected atm though.

boris02:03:42

custom build from master still works (and yes noticeably faster than git checkout)

mfikes02:03:59

Thanks for confirming!

ajwerner05:03:50

Is there a reason why using records would make the generated code slower (with :optimizations :advanced)? I have some code where I keep data with points in sorted maps and changing all the containers to records made the code about 50% slower. This certainly wasn't my expectation.

dnolen11:03:00

@awerner32 sounds unlikely but it’s hard to say, you were using maps before?

ajwerner13:03:40

yes, using maps it's a good 40-50% faster than switching it to all defrecord and using field accesses

ajwerner14:03:09

more specifically, I was using maps with keywords :x and :y as points and changed that out for a Point record with direct field access.

jrychter11:03:28

Is there a way to prevent ClojureScript from inlining strings defined via (def) (no :const)? This is becoming a serious problem for me. I've just integrated Font Awesome 5 icons (SVG), and written a macro that references a global def for a particular SVG path. This should in theory pull in only the paths I actually use. Well it does work, but including an icon multiple times includes the full SVG data multiple times, which doesn't make any sense.

jrychter11:03:44

I've heard it argued that duplicating strings doesn't matter, because compression "will take care of it" — I think this reasoning is fairly thin.

rauh11:03:14

@jrychter CLJS doesn't inline strings. That's Google Closure doing when doing :advanced

jrychter11:03:39

Oh, ok. But in that case, do we have a way to tell it to not do that?

rauh11:03:32

@jrychter There is a new @noinline annotation coming in GCC (I dont think CLJS ships with it yet). But I'm not sure if works for normal JS vars, might only be for functions

rauh11:03:46

Right now you could try a few tricks. Like exporting the var or calling a function on it (def the-big-str (identity "...")) (to be tested)

rauh11:03:17

YEah looks like the @noinline also works for vars:

jrychter11:03:23

Hmm... exporting could work (I'm auto-generating all the vars anyway). But it would bring back some of what I was trying to avoid (all full icon names listed).

jrychter11:03:56

That sounds very promising, any hints on how I can pass that annotation from ClojureScript?

rauh11:03:28

This works for me with a recent CLJS:

(def fooooooooo "@noinline" "bar")

(defn ^:export foooooofn []
  fooooooooo)

rauh11:03:54

The def'd var isn't inlined in that case.

rauh11:03:19

Ignore the ^:export hint, it''s just for testing locally.

jrychter11:03:01

@rauh: Nice! This seems to work with ClojureScript 1.10.126, which I'm trying out right now. No inlining for SVG paths, and I've just saved 45kB in code size!

rauh11:03:38

Nice! Looks like CLJS ships with a GCC version which understands @noinline

jrychter11:03:41

Thank you for your help, @rauh!

jrychter11:03:38

So, GCC in 1.10.126 does understand it, the one in 1.9.946 does not. Hopefully I'll be able to use 1.10.126 — I've been trying it out today and so far haven't seen any problems yet.

jmckitrick15:03:51

Has anyone tried the new figwheel with rebel repl feature?

PB16:03:22

Hey all. Stupid question. How would I write this in cljs:

people.map(function(person){
  console.log("The person is", person);
});

chris16:03:19

(run! println '("mike", "lee", "amy", "claire"))

joelsanchez16:03:24

also valid:

(doseq [person people]
  (js/console.log "The person is" person))

PB16:03:27

(def gun (js/Gun.))
(def people (.. gun (get "people")))

(-> gun (.map (fn [person]
                (prn (str "The person is " person)))))
does not give me what I expevted

PB16:03:04

Hmm really? Map is a function on their library

PB16:03:14

But I haven't tried what you just suggrsted, thanks

athomasoriginal16:03:38

(map #( js/console.log (str "This person is " %)) ["Thomas" "Daniel"])

joelsanchez16:03:25

the above will only work with mapv or wrapped in doall // don't use map for side effects

athomasoriginal16:03:47

The above would be the exact translation of what you were going for. However, because you have a side effect...see @joelsanchez comment

athomasoriginal16:03:54

hahaha you beat me to the punch 😉

athomasoriginal16:03:22

Just to be clear @petr the side effect is the console.log statement

PB16:03:46

I got that thanks

PB17:03:27

So I still feel like a fool. I'm trying to follow this: https://gun.eco/docs/Graph-Databases-101 This is what I have done so far:

(def gun (js/Gun.))
(def people (.. gun (get "people")))
(def alice (-> gun (.get "person/alice") (.put {:name "alice" :age "22"})))
(-> people (.set alice))
v------- app!{:conn 2} -------
#object[Gun [object Object]]

(doseq [person people]
  (js/console.log "The person is" person))
=> #object[Error Error: [object Object] is not ISeqable]
   cljs$core$seq (jar:file:/Users/peter/.m2/repository/org/clojure/clojurescript/1.9.946/clojurescript-1.9.946.jar!/cljs/core.cljs:1212:20)

^^ Suggests that I do need to use their map method?

gunmoo.core> (-> gun (.map (fn [person]
                (prn (str "The person is " person)))))
v------- app!{:conn 2} -------
#object[Gun [object Object]]

PB17:03:33

I feel like a crazy person

joelsanchez17:03:40

I would js/console.log people directly to see what kind of value it is

joelsanchez17:03:03

you may need to convert people to a seq first

PB17:03:05

It returns nil

PB17:03:21

So you don't think that I should be using that map fn they have defined?

joelsanchez17:03:37

if people is nil there is no hope imo

PB17:03:47

That's true

PB17:03:11

I wonder why that is the case. Did I initialize it incorrectly?

benzap17:03:28

On line three, you need to pass in a javascript object, so {:name "alice" :age "22"} becomes #js {:name "alice" :age "22"}

PB19:03:18

This was it, thank you

deas17:03:47

Ok, so pretty sure now it is closure-compiler-unshaded "v20180204" miscompiling React 16 react-dom/index.js (`:optimization :none`) from node_modules. Any suggestion how to put together a bare bones repro for the Closure people?

genekim17:03:36

Thanks so much for the chat and for all the help, @mfikes!!! Keep up all the amazing work!

thheller18:03:27

@deas there was at least one regression in v20180204. not sure if there are others. https://github.com/google/closure-compiler/issues/2822 if you see Cannot call a class as a function that might be it.

thheller18:03:34

there were a lot of changes to their rewriting code though so it may be other things

deas18:03:04

@thheller Perfect! Thanks a lot. Looks exactly like the kind of repro I am after. Will narrow down things tomorrow and let you know.

Garrett Hopper18:03:58

Is there proper documentation for the clojurescript compiler somewhere? I can't make heads or tails of a lot of its behavior. Why would cljs.repl/repl auto-rebuild when I haven't specified :watch "src"?

Garrett Hopper18:03:01

What is the connection between the initial build to an output directory and then a repl to the same directory? Does it keep the settings? Doesn't repl accept all the same arguments are build?

dnolen18:03:19

@ghopper repl doesn’t autobuild

dnolen18:03:02

repl takes a superset of build options - extended with additional REPL specific keys

Garrett Hopper18:03:50

Does my (require 'namespace :reload) do the building then?

dnolen18:03:17

the high level semantics are the same as Clojure, we reload that ns

dnolen18:03:38

additionally because ClojureScript was/is browser-first oriented this means we write to disk

Garrett Hopper18:03:38

But it shouldn't have the updated code from source changes?

dnolen18:03:36

like I said, the behavior is the same as Clojure

dnolen18:03:49

:reload means really reload

Garrett Hopper18:03:03

Ok, I think I'm following. So it is the :reload that's causing the rebuild. How is that different than from :watch on a repl?

Garrett Hopper18:03:18

Would :watch only make sense for e.g. a browser that can be refreshed? (I'm using a node repl)

noisesmith18:03:51

you can still push new code via websocket when files change

borkdude18:03:24

(or js/NaN 10) ;;=> NaN

borkdude18:03:40

(NaN || 10) ;;=> 10 ??

Garrett Hopper18:03:18

@noisesmith Ok, but that would require additional code/an additional library to do that. It's not a component of the compiler itself?

noisesmith18:03:35

right - that's something figwheel does for example

Garrett Hopper18:03:53

Alright, I'll need to look into figwheel more. It works with node?

noisesmith18:03:28

I don't actually know that for sure, I know it's possible in theory, I bet someone else here or in #figwheel knows though

borkdude18:03:48

(number? js/NaN) ;;=> true

Garrett Hopper18:03:03

I guess I'm not seeing the use of the :watch option for repl.

noisesmith18:03:49

@borkdude: cljs truthiness isn't like js truthiness - see also (if 0 ...)

Garrett Hopper18:03:57

Since code isn't actually hot-reloaded. It's just written to disk, and the repl would have to be restarted to actually get the changes.

borkdude18:03:07

I’ll just use js/isNaN

noisesmith18:03:10

and I always found (number? NaN) funny, but it's technically apropriate

noisesmith18:03:24

@borkdude: yeah, that seems like the right plan

noisesmith18:03:07

@ghopper if you write your code to be reloadable, you don't need a restart, just a trigger telling you to load new definitions

noisesmith18:03:48

what figwheel does iirc is send new code over the websocket for cljs to load, but you could also get a signal telling you to reload the files in npm

dnolen18:03:50

@ghopper :watch just autobuilds so when you refresh the browser you see the right thing

dnolen18:03:59

Figwheel actually hot reloads on file system changes

Garrett Hopper18:03:02

@noisesmith So with :watch I don't actually need the :reload to (require) to get new code?

noisesmith18:03:17

you still need that

noisesmith18:03:27

require just says "load this if it doesn't exist yet"

dnolen18:03:52

@ghopper no autoloading

Garrett Hopper18:03:09

@dnolen That makes sense. So :watch really only makes sense for browsers and not node? (Unless I'm perhaps using nodemon?)

dnolen18:03:27

@ghopper more or less, Figwheel can hotload Node.js too

Garrett Hopper18:03:03

Alright, I think I'm following now.

Garrett Hopper18:03:24

Another question; if repl is just a superset of build, should I be able to skip the initial build and just run repl with all the build configuration? How would the first argument to build (the src paths) be set for repl?

Garrett Hopper18:03:15

Or does repl keep all the same settings (when watching and building) from the initial build?

Garrett Hopper19:03:08

@dnolen Do you mind taking a look at this and letting me know how badly I'm bastardizing this poor compiler?

(deftask launch-server []
  (comp
   (with-pass-thru _
     (let [dir (.getAbsolutePath (tmp-dir!))]
       (cljs/build "dev"
                   {:main 'server.core
                    :target :nodejs
                    :output-dir dir
                    :output-to (str dir "/main.js")})
       (future
         (let [env (cljs-node-repl/repl-env)]
           (cljs-repl/repl env
                           :read (fn [_ _] @(promise))
                           :prompt #()
                           :quit-prompt #()
                           :output-dir dir
                           :repl-requires '[[server.core]]
                           :inits [{:type :eval-forms
                                    :forms ['(server.core/main)]}])))))
   (wait)))

Quan Nguyen19:03:18

Anyone know if it's possible to load source from e.g. clojars at runtime so I can use it in cljs.js/eval? I'm basically trying to load libraries in the browser to do dynamic code eval

oliver.holworthy21:03:48

.jar files are essentially zip files (you can extract with tar -xf and unzip) I’m sure there must be a way to extract zip files in javascript. So I think would be possible to load from clojars inside the browser if you wanted to

dnolen19:03:51

@ghopper well I’m assuming you have a good reason to try to and do all the plumbing yourself but I woudn’t bother myself 🙂

richiardiandrea19:03:24

it is basically a compilation server in boot it seems, very nice 😄

Garrett Hopper19:03:50

@dnolen The only real reason is that I wanted this to be a boot task, so I didn't want it actually taking over the repl. Basically I'm trying to use repl without it actually being a repl now that I think about it...

Garrett Hopper19:03:38

Anyways, now to get figwheel to hot-reload my code.

richiardiandrea19:03:17

@ghopper just curious ( because I maintain it 😄) . Isn't boot-figreload working for you for that particular task?

Garrett Hopper19:03:06

@richiardiandrea I'll have to look into that. 🙂 This was mostly just me trying to learn the cljs compiler. I was starting to feel like it might be cleaner to do away with the wrappers around it I was using. (boot-cljs, etc.)

richiardiandrea19:03:56

always good to learn, don't get me wrong 😄

dnolen19:03:48

@ghopper if you want to learn more and possibly contribute #cljs-dev is a good place to lurk

Garrett Hopper20:03:31

@richiardiandrea Do you know of anyone successfully using boot-figreload for a nodejs target?

richiardiandrea20:03:38

I remember someone mentioned it to me yes, as you were saying, it is a wrapper so the main work is done by boot-cljs

Garrett Hopper20:03:56

Well, I think the problem is it expects the process to start and connect to the weasel server. (When it's loaded in a browser) However, with node it makes sense to just start the process.

richiardiandrea20:03:11

keep in mind that figwheel is the one receiving the payloads so boot-figreload is basically just the postman 😄

richiardiandrea20:03:52

doesn't figwheel handle node the same as browser?

Garrett Hopper20:03:51

Apparently not. I think it might if I manually run node on the resulting package.

richiardiandrea20:03:35

unfortunately the node side of cljs is not as advanced as the browser (I guess less people working with it). I have switched to this workflow: lumo for the REPL and CLJS jvm for compilation and creation of the final artifact (in my case lambda functions)

Garrett Hopper20:03:22

@richiardiandrea Alright, I had to npm install ws for it to work, but this works with live reloading:

(deftask dev []
  (comp
   (watch)
   (reload)
   (cljs-repl)
   (cljs)
   (target)))
All I have to do is go to /target and node main.js. It then connects and starts reloading.

richiardiandrea20:03:26

Maybe the only tricky bit is to move to target and run node main.js from there

richiardiandrea20:03:30

I haven't ported to 0.5.15 yet...sorry about that ...

mattboehm20:03:48

Anyone know of a good cljs/closure compression library? I'm storing my serialized app state in a url hash and trying to find ways to make it a bit smaller