This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2015-07-06
Channels
- # beginners (20)
- # boot (221)
- # cider (16)
- # clojure (140)
- # clojure-berlin (2)
- # clojure-dev (2)
- # clojure-germany (2)
- # clojure-japan (4)
- # clojure-korea (44)
- # clojure-russia (2)
- # clojure-uk (6)
- # clojurescript (202)
- # core-async (7)
- # datomic (9)
- # editors (1)
- # euroclojure (3)
- # ldnclj (21)
- # liberator (4)
- # off-topic (4)
- # om (8)
- # reagent (17)
I am trying to write a node module in ClojureScript based on this post http://www.matthewstump.com/misc/2012/06/04/writing-nodejs-modules-in-clojurescript/ - I tried the following
;; /src/sample/base.cljs
(ns sample.base
(:require [cljs.nodejs :as node]))
(defn blargl
[]
(println "blargl!"))
(node/enable-util-print!)
(set! *main-cli-fn* #())
;; compile it at the command line
cljsc src '{:optimizations :simple :pretty-print true :target :nodejs}' > lib/sample.js
;; in the newly created lib directory introduce a main.js file that makes the functions available to NodeJs
;; In /lib/main.js
var sample = require("./sample.js")
exports.core = sample.sample.base
Then create a simple package.json
with "main": "lib/main.js”
and run npm pack
. In another project npm install
it, and require <module-name
. But it turns out that blargl
is never visible.
The only way I could make this work is by setting the ^:export
metadata like so.
(defn ^:export blargl
[]
(println "blargl!”))
Am I missing something really obvious here?I thought simple
optimizations would not require the export
metadata. I do notice that with ^:export
I see this in the generated sample.js
goog.exportSymbol("sample.base.blargl", sample.base.blargl);
But that line isn’t there without ^:export
@looselytyped: I highly recommend taking a look at Mori
I will add that writing Node modules with ClojureScript doesn’t make that much sense at least to me due to a large standard library that cannot be shared. Writing Node.js applications - yes. Writing Node.js modules - no.
Thanks for the prompt response @dnolen - I really appreciate it. I will certainly take a look at Mori. Just so I understand completely - > doesn’t make that much sense at least to me due to a large standard library that cannot be shared How do you mean? What library are you speaking of?
the standard library is nearly 10,000 lines of ClojureScript. If you include all the stuff that people actually use like pprint
, set
etc. it’s more like 14,000 lines of ClojureScript.
this code can’t be shared without changing how ClojureScript loads code (via Google Closure) which isn’t going to happen.
I see. Thanks for the insight. Again, I really appreciate it. The library I was thinking of writing was a simple wrapper for making calls to an internal REST API - We already have a version of it in Clojure, and figured that we could re-use a lot of the code. Perhaps I should rethink that 😕
@looselytyped: you can totally reuse that code, just don’t bother with Node modules
totally unnecessary when targeting Node.js, everything that works for the browser just works
we treat Node.js like any JavaScript engine, it has no real special treatment beyond a very very small number of things
Ah! I see … That makes sense. That’s good to know. Again - thank you! thank you! thank you!
A survey of where we currently stand with respect to ClojureScript and React Native: http://blog.fikesfarm.com/posts/2015-07-06-clojurescript-with-react-native.html
@mfikes: thanks for the writeup, so many things happening and sometimes is a bit rough to keep up with all updates
In six weeks, David’s ClojureScript in Action talk will be available online: https://qconnewyork.com/video-schedule
Hi, I have 2 separate and disjoint (one doesn’t require the other) cljs files (both of them contain ^:exported functions). I notice that the compiled version keeps only 1 of them and I often have to edit the js to make the import work. What am I doing wrong ?
@shriphani: Not enough info. Maybe post the line containing ^:export
for each?
@shriphani: Are you finding that :advanced
is re-writing symbols?
@shriphani: Is it declared (ns main-content)
?
Hmm… perhaps something more fundamental is wrong… do you see any compiler warnings when building it?
Successfully compiled "out-adv/web_structure.min.js" in 2.937 seconds.
Compiling "out/web_structure.js" from ["src-cljs"]...
Successfully compiled "out/web_structure.js" in 0.178 seconds.
Compiling "out-adv/web_structure.min.js" from ["src-cljs"]...
Successfully compiled "out-adv/web_structure.min.js" in 3.007 seconds.
So, if you look in your emitted JS, the symbols from one file appear, but not the other?
@shriphani: sanity checking question - are these files that you are compiling separately getting loaded into the same JS environment?
@shriphani: why are you doing it that way? There’s really no support for that
@shriphani: I believe @dnolen is referring to loading two separate JS files produced by the compiler (via :advanced
)
If you are using cljsbuild
, then lein cljsbuild once xxx
where xxx
identifies the :advanced
build
@shriphani: Ahh. So with :none
one of the files is not compiled at all?
this is web_structure.js : https://www.refheap.com/105360
You could have a top-level namespace which itself requires all of the namespaces you need loaded.
@shriphani: FWIW, I run in to this when loading :none
into iOS. Nothing magical makes non-required namespaces be loaded on their own. https://github.com/mfikes/shrimp/blob/master/iOS/Shrimp/AppDelegate.m#L31
I’m curious, one question I don’t know the answer to is whether ^:export
prevents DCE in :advanced
mode. I would hope so.
@shriphani: sorry for misunderstanding earlier, was thrown off by the incremental output paste.
@dnolen: nah I goofed up with my question. Sorry I am a bit of a n00b at this and ask questions poorly.
If any cljs developers ran into problems using boot in the past, I'm happy to say that boot-cljs-repl has gotten some loving recently and is working well. If you give it a try and run into any issues please let me know. https://github.com/adzerk-oss/boot-cljs-repl
@samueldev: well, you've got domina, dommy, Google Closure dom, and the dom capabilities that come with most of the reactive tools out there
@samueldev: I'd say you need to start with what your requirements are. For simple stuff, the google closure library is already used by cljs so you get it for free and it has good, basic dom tools. Domina and dommy and the others have slightly different intents so you need to match the one that fits your needs best.
@shriphani: I’m so looking forward to the next version of ClojureScript: Up and Running. I expect it will be the silver bullet that clarifies everything related for us
Until then, we all have to ask ill formed questions, and stumble around in the dark, or read the source.
@shriphani: I took a stab at adding some copy to the documentation for :main
that may have helped. Feel free to revise it if you find things are inaccurate: https://github.com/clojure/clojurescript/wiki/Compiler-Options#main
@mfikes: On this page you wrote "There is currently no require function..." but it looks like there is one now, right? Or am I missing something? https://github.com/clojure/clojurescript/wiki/The-REPL-and-Evaluation-Environments
cljs.user=> (doc require)
-------------------------
require
([& args])
REPL Special Function
Loads libs, skipping any that are already loaded. Each argument is
either a libspec that identifies a lib or a flag that modifies how all the identified
libs are loaded. Use :require in the ns macro in preference to calling this
directly.
This isn't what I expected. What's the right way to reference the current namespace in a repl:
cljs.user=> (dir cljs.user)
nil
cljs.user=>
@mfikes: oops - I saw you had edited it and I actually thought it was fairly new for some reason
does figwheel do an implicit/behind-the-scenes (require '[app.namespace])
thus allowing users of its repl to simply do in-ns 'app.namespace
?
@meow: in-ns
works regardless of whether the namespace is loaded or not - it’s a REPL feature not a language one
Advanced Compilation & Externs https://developers.google.com/closure/compiler/docs/api-tutorial3
Fig wheel question… working on a luminous project, it seems no amount of wrap-reload will get my server side code to reload when running under fig wheel. Thoughts?
@canweriotnow: isn’t figwheel just the REPL bit? What does it have do w/ your server side bits?
That’s what I can’t figure out. It shouldn’t matter. But the handler doesn’t see to be picking up the dev env when I start the whole thing from lein figwheel
instead of lein run
I think it's new changes to Luminus I'm not used to, I usually just start with compojure and ring but I was in a hurry
When I start with lein run
I get figwheel websocket issues... maybe need to just clean my cljs and not use figwheel when I'm messing with my servery bits
oh god, turning off autocrrect in Slack makes life so much more legible
uh, mostly 😉
@dnolen: par for the course, I'm confused. Inside a boot-cljs-repl session when I use in-ns
to access the namespace of the app that is running in the browser I get the following pseudo-error:
cljs.user=> (in-ns 'app.core)
nil
app.core=> (get-title)
WARNING: Use of undeclared Var app.core/get-title at line 1 <cljs repl>
"Informing v0.1.0"
app.core=>
So I'm able to call my app/core get-title
function and have it return a string, but I get those undeclared Var warnings. I thought I had come across information indicating that a require
of the namespace was, um, required, but you say otherwise. Hence, my confusion.@meow: only puts your REPL into the namespace. It doesn't require it and this doesn't cause analysis
@canweriotnow: yeah I can’t offer more than you probably want to run figwheel sans the built in webserver, don’t know anything about how to do that bit though
@meow: http://blog.fikesfarm.com/posts/2015-06-10-analyze-path-ftw.html and https://github.com/clojure/clojurescript/wiki/REPL-options#analyze-path
@dnolen: I see. Ok. That's what I thought. And doing a (require '[app.namespace])
which in my example would be (require '[app.core])
is the canonical way to load the symbols into the namespace, right?
it just allows your forms entered at the REPL to be subject to the resolution rules present in the namespace as supplied by the ns
form there.
@mfikes: I've read your posts and they are great - still trying to get my head around in-ns and analyze-path
@meow: Here is a mental model: There is the JavaScript environment and then there is what your REPL happens to know about that environment. When namespaces are analyzed, the REPL learns about namespaces and which symbols are in those namespaces: ns-interns
works, etc.
@meow: :analyze-path
is for a problem that doesn’t exist in Clojure, because the evaluation environment is Clojure itself and Clojure has ns & var info at runtime.
@meow: but when you connect a ClojureScript REPL to a running ClojureScript compiled application in a browser … how can it know what’s there?
Okay, tell me where I am wrong. A namespace is basically (or literally) a map. Being in a namespace means code that subsequently gets executed is executed in the context of that map. So any symbols are "looked up" in that map. If I'm in a REPL that is connected to a running browser app and I use in-ns
to put myself into that namespace, then why do I see errors?
thus :analyze-path
hints the REPL - analyze this stuff so that interactions at the REPL match your expectations
@meow: When you type foo.bar/baz
in the REPL, it compiles that to access foo.bar.baz
, but the REPL may or may not know that this symbol exists.
But I did a lot of Python, including writing a GUI REPL and so I learned a lot of its namespace tricks
@meow: Unfortunately, I don’t know where you would learn the above mental model from stuff in the Wiki or otherwise. (My reaction to learning something new is to try to document it, but I think I learned this one through experience, working on Ambly, etc.)
Yeah, I started working with Clojure and ClojureScript on May 15th, so almost 2 months now.
I took over maintenance of boot-cljs-repl and am trying to make sure it is working as expected.
A lot of details about the repl in clj and cljs make way more sense now. Thank you all for your patience.
@meow: You asked a great question a few days ago about something that I thought was common knowledge, but was actually documented nowhere in the wiki.
I have to say that I'm really enjoying the language and the community. I picked up Python in 1999 and now the Clojure community reminds me of those days.
It's kind of funny. The first real app I wrote in Python was a repl (PyCrust) and now here I am learning a new language and one of the first things I do is get involved with the repl side of things.
One challenge with the documentation is: once you know something, it is hard to see that the documentation is lacking it. But when you don’t know something, its easy to see it is lacking. The sweet spot is when you know enough to feel comfortable contributing to the documentation when you happen to see the missing bits.
@meow: I can attest (twice over), that writing a ClojureScript REPL is a great way to learn things!
@mfikes: That is so true. And once I've gotten over the hump I know I will quickly lose interest in whatever those missing bits were. That's why I try to raise these issues as I find them. I assume that if I'm confused then others must surely also be confused (though I could be wrong about that) and that something needs to be improved and if I don't point it out then it's just making it harder for the next developer that comes along.
@meow: Yeah, the documentation is only 3/4 the way there (you could argue about what the actual level is).
That's why I kept finding this cljs repl stuff so confusing based on my python experience and what I knew about clojure namespaces being maps, just like python's were dictionaries, so I couldn't understand why I was running into this issue in the boot-cljs-repl. But now I know. ClojureScript doesn't have reified namespaces so we have to fake it by giving it hints about what is likely in the namespace.
I think the pattern should roughly be this: 1. I don’t understand something and it is not clearly documented 2. I ask for help and the community clarifies it 3. (If I’m somewhat experienced and comfortable) go back and add the missing clarification to the document 4. Go to 1
@meow: Heh. And we’ll likely go through another round of interesting, perhaps different stuff, related to bootstrapped ClojureScript, and what is and isn’t possible in that platform
Another variation for me was to pester the boot folks with all my problems until @alandipert decided to turn the tables on me by offering to make me a maintainer...
@meow: and the hinting issue is subtler than that. It’s really the remote REPL problem.
In Clojure Programming it uses language like “they are dynamic mappings between symbols and either vars or imported Java classes.” (and the same language is used in the page David just linked)
Oops. Thought David linked this: http://clojure.org/namespaces
Well, I can't find where I thought I read that clojure namespaces were implemented as maps and it isn't worth the effort. So basically they are map-like things but not maps. That's cool. And the cljs implementation is different for performance and code size reasons. That's cool. I think my confusion has been solved.
Check this out, though. Figwheel does do some work behind the scenes in its repl:
This REPL is a little different than other REPLs in that it has live compile information from the build process. This effectively means that you will not have to call (require or (load-namesapce unless it is a namespace that isn't in your loaded application's required dependencies. In many cases you can just (in-ns 'my.namespace) and everything you need to access will be there already.
The section of the figwheel docs about "Writing reloadable code" should be required reading for cljs developers: https://github.com/bhauman/lein-figwheel#writing-reloadable-code