Fork me on GitHub
#clojurescript
<
2015-12-26
>
crocket00:12:20

How do I import ES6 modules in clojurescript?

mfikes00:12:05

@crocket See this exposition https://github.com/clojure/clojurescript/wiki/Dependencies#bundling-foreign-javascript-code and the :foreign-libs compiler option https://github.com/clojure/clojurescript/wiki/Compiler-Options#foreign-libs in particular the :es6 :module-type. (This is a relatively new compiler feature.)

crocket01:12:28

@mfikes: How would you import npm modules, then?

crocket01:12:06

On node.js, I could just use js/require. On web browsers, I could bundle npm dependencies with browserify in advance.

mfikes01:12:07

@crocket Well, npm is a whole system for downloading deps, installing them locally etc., right? But, there is now support in ClojureScript at least for CommonJS libs, ignoring how you obtain them.

crocket01:12:36

like :file "node_modules/module_a/index.js"

crocket01:12:17

:foreign-libs [{:file "node_modules/module_a/index.js", :provides ["org.module.a"]}]

crocket01:12:43

This sounds a bit more cumbersome than js/require.

mfikes01:12:55

@crocket: yeah. If you have the path to the JavaScript, do that plus :module-type :commonjs

crocket01:12:15

I forgot to include :module-type.

mfikes01:12:23

@crocket if you are running in Node, perhaps js/require followed by just using JavaScript interop leads to another valid approach

crocket01:12:52

If I'm on a web browser, I could just bundle npm dependencies with browserify and include it in HTML before clojurescript bundle.

crocket01:12:06

But, this would lead to more deployment hassles.

crocket01:12:44

Does :module-type work reliably?

mfikes01:12:32

@crocket I can't speak to its reliability. It maps into capabilities provided by the Google Closure infrastructure. But, I personally have only limited experience with it (see http://blog.fikesfarm.com/posts/2015-12-22-foreign-libs-processing-in-repl.html)

crocket01:12:05

How does it correctly import a plain javascript module like jquery?

crocket01:12:31

jquery and other plain js libraries do not indicate which global variable is the module.

crocket01:12:06

In browserify, I had to specify the global variable to use as the module.

crocket01:12:23

It seems I can't use foreign libs in REPL, yet?

crocket01:12:45

Unless I use the latest master.

mfikes01:12:24

@crocket: My guess is there is no magic. Plain libs are just brought in and you can use JavaScript interop. Again, my experience is limited. Here I am using a plain lib (there are probably other more sophisticated examples out there): https://github.com/mfikes/replete/commit/5c2c6d85f89420b9ce4a52c8d5cfeab8f0d5217f

crocket01:12:16

If I just import jquery, does "$" become a global variable?

mfikes01:12:08

@crocket: You can use foreign libs in a REPL without the stuff in that blog post. The post is just about having the processing done without first doing a separate explicit build step.

mfikes01:12:38

@crocket: I can't help with your jquery question. I'd try js/$.

crocket01:12:57

I think :foreign-libs should capture a single global variable in a plain js module as the module to export.

crocket01:12:23

Otherwise, the global scope becomes congested again.

crocket01:12:15

browserify does it to protect the global scope.

crocket01:12:14

You should note how browserify takes care of plain js modules.

crocket01:12:48

In any case, I would prefer npm modules to plain js modules.

crocket02:12:55

Is there a well-maintained bootstrapped cljs repl on node.js?

mfikes02:12:48

I think someone should build something like Planck, but on Node; maybe name it Max, and flesh it out and maintain it. It could use @richiardiandrea's Replumb.

crocket03:12:14

@mfikes: It takes 0.75second to compile and execute a very simple cljs program on cljs-repl. How long does it take on planck?

mfikes03:12:07

@crocket I think twice as fast in general. This is the best I've seen: https://mobile.twitter.com/mfikes/status/630157629495615488

crocket03:12:50

How fast does "planck sample.cljs" run?

crocket03:12:05

sample.cljs being

(.log js/console "hi")

mfikes03:12:57

I'm away from a computer right now. FWIW Planck can cache compilation. http://blog.fikesfarm.com/posts/2015-11-26-planck-caching.html

richiardiandrea03:12:35

By the way in replumb there is a Repl demo with nodejs..at the moment it is missing eval cache though. I will add it after the holidays

crocket06:12:06

How do I get auto-completion in lein figwheel REPL?

crocket08:12:02

Getting a CLJS nREPL in emacs is unintuitive.

jaen08:12:06

@crocket: re: your modules question the :foreign-libs :module-type functionality is what I was referring to when I said "work done during GSoC". It works reliably, but it is limited in that you have to specify each file separately in foreign libs and the code should preferably be under your control, since you can only use relative requires with it. Here are examples using this functionality - https://github.com/mneise/circle-color and https://github.com/mneise/cljs-present

crocket08:12:58

@jaen: You should refer to browserify's shim on plain js libs.

jaen08:12:36

Hm? I'm not sure I follow?

crocket08:12:13

This teaches how you should handle plain js libs.

crocket08:12:40

Browserify compiles npm modules to web browser codes.

jaen08:12:08

I know, so? I'm not sure what does have to do with using :module-type, which I was talking about.

crocket08:12:49

When :foreign-libs include plain js libs, the libs' global variables are exposed.

jaen08:12:50

Unless I guess you want to turn a non-modular lib into a module before using :foreign-libs which I guess you could, but since all Clojurescript code is namespaced, there's not all that much reason to.

crocket08:12:20

browserify-shim teaches you how to prevent exposing global variables,

crocket08:12:51

I'd prefer to wrap global variables in a module.

jaen08:12:28

I suppose you could if you feel so strongly about that.

jaen08:12:41

But I was talking about libraries that already have modules.

jaen08:12:12

Using it just with :foreign-libs and :module-type would be a nightmare

jaen08:12:38

Believe me, I tried, up to and including extending the compiler.

jaen08:12:59

And really, at the moment the easiest way is to make a browserify or webpack or whatever bundle

jaen08:12:06

Of all the modular libraries you intend to use.

crocket08:12:19

Or, I could use js/require in node.js

crocket08:12:41

On web browsers, exposing require from a browserify bundle would be easy, but it feels like a hack.

jaen08:12:44

Oh yeah, on the server side I suppose you could, since node provides that.

jaen08:12:38

Well, require, import and such work with :foreign-libs that have :module-type, but like I mentioned - with caveats

crocket08:12:40

What did you learn from handling plain js libs with clojurescript web apps?

jaen09:12:59

You can't, I don't know, do require("react/something") and expect it to work. You have to put the lib in a folder besides the one you have your code in and do require("./react/src/something"). That's how it was IIRC.

jaen09:12:27

Which means incorporating webpack, browserify as a build step is a saner thing to do.

crocket09:12:02

Perhaps, :foreign-libs can become simpler.

jaen09:12:21

As for non-modular libs - it is only problematic in so far as a foreign lib could conflict with a foreign lib, which in practice is not that much of a problem (never happened to me when I was doing Rails with plain JS). It won't really conflict with your Clojurescript code since it's namespaced as GClosure modules.

jaen09:12:41

So if you want to not expose globals at the toplevel by using shims, it's mostly your stylistic choice

jaen09:12:47

Not something that can bite you in practice.

jaen09:12:42

As for foreign libs becoming simpler - I did work on that as I mentioned. Here are some experiments I did along the way - https://github.com/jaen/react-with-modular-cljs and https://github.com/jaen/custom-module-loaders (not sure if the latter would work right now), but there just wasn't enough interest from maintainers to keep it up.

jaen09:12:01

So webpack/browserify/etc. as a build step is the current state of art.

crocket09:12:44

@jaen : What do you use for CSS?

crocket09:12:08

I am investigating into clojure's CSS generator, but I used SASS before.

jaen09:12:37

I use SASS

jaen09:12:12

Due to awesome powers of boot I can just use middleman to handle things like that - https://github.com/jgdavey/boot-middleman

crocket09:12:47

Tooling still takes more time than actually writing code.

jaen09:12:04

That's true.

jaen09:12:25

Clojure is not a la carte, like Rails.

crocket09:12:23

Do you mean clojure is a la carte?

rm09:12:00

it's again flexibility vs fast start

rm09:12:18

and frameworks vs libs

rm09:12:08

crocket: if you do want to have kind of framework, create your own lein template and use it in every project

jaen09:12:52

@crocket: well, I've meant a la carte (that is a menu of complete dishes) as opposed to smorgasbord where you compose your meal yourself, but now I've looked up the exact definition of that I can see how it could be confusing.

jaen09:12:03

You're right.

jaen09:12:50

I wrongly assumed a la carte ~= omakase.

jaen09:12:44

And yeah, there are templates, but nothing approaching the Rails level of just-rails-generate-it.

rm09:12:16

> I am investigating into clojure's CSS generator, but I used SASS before. then use sass :) lein-sass is good enough. It requires sassC installed, but it's ok, just install and use.

jaen09:12:38

Just keep in mind it's libsass, so no Compass for example.

jaen09:12:53

(or at least those parts of compass that use the ability to extend SASS from Ruby)

jaen09:12:15

Using boot-middleman gives you full SASS, without having to install Ruby.

rm09:12:13

I thought rubyists got rid of compass already. Am i wrong?

jaen09:12:58

I'm not sure about the general populace to be honest.

jaen09:12:05

I kind of never liked it, preferred bourbon & co.

jaen09:12:19

But nonetheless libsass not supporting extending SASS with Ruby is a thing that happens to be true, so it's good to be aware of that.

jaen09:12:37

If it's not a constraint, then sure, go ahead with libsass.

rm09:12:41

jaen: > without having to install Ruby. middleman is ruby gem: https://github.com/middleman/middleman so you still have to install ruby

rm09:12:00

yeah, just curious

jaen09:12:31

Though last time I tried it (that was 2-ish years ago though) it would not compile my stylesheets to the same CSS Ruby SASS would.

jaen09:12:45

I think the most problems it had was with selector placeholders %.

jaen10:12:12

@rm: it's true that's a Ruby gem, but boot-middleman runs it in an embedded jRuby. So no, no need to have Ruby installed.

rm10:12:41

hm, interesting. I understood, thank you

jaen10:12:48

Sure. I like boot-middleman because I can keep that Ruby workflow that is friendly to frontend developers, without having to force anyone else to install Ruby.

crocket11:12:49

Is there a decent clojurescript template for node.js apps?

rm11:12:33

crocket: https://github.com/quile/node-cljs-template found this in google, readme looks nice

crocket11:12:44

Why does clojurescript REPL lose 'doc' function after moving to other namespaces?

crocket11:12:26

cljs.repl loses lots of functions when I invoke (ns 'namespace)

rm11:12:00

I guess because the functions defined in cljs.user namespace

rm11:12:45

try

(require '[cljs.user :as u])
(u/doc <your function name>)

jaen12:12:31

Yeah, that is a pretty annoying thing. Would be a nice feature to able to overlay (or underlay) some functions over all namespaces.

crocket13:12:04

I created https://clojars.org/nrepl-figwheel-node/lein-template for developing nodejs clojurescript apps with figwheel on nREPL.

crocket13:12:18

Does advanced optimization break npm modules?

jaen13:12:51

Advanced optimisation doesn't optimise foreign libs.

crocket13:12:53

I want to package npm modules and clojurescript into one bundle.

jaen13:12:20

So as long as you have proper externs to avoid renaming on the Clojruescript output side, this should work.

crocket13:12:04

Do commonjs modules need extern?

jaen13:12:29

Foreign libs need externs.

jaen13:12:03

GClosure doesn't care what the external Javascript is, it just needs to know what references in your code are references to libs external to the compilation

jaen13:12:06

So it won't rename them.

crocket13:12:53

Do you know how to package a clojurescript nodejs app?

jaen13:12:17

I never used Clojurescript with node.js, but I don't imagine it would be all that different than compiling for the browser - Clojurescript compiler outputs Javascript after all, you just have to run it. You would use node/require as usual, but you will have to provide externs for functions you use from required modules if you use advanced optimisations, so Clojurescript doesn't rename the references in the compilation output. And you would probably not specify node libs as :foreign-libs (foreign libs are pasted into the output verbatim), but rely on npm and node to resolve those. But you would probably have to wait for someone with actual expertise for more concrete information.

crocket14:12:05

That was good, but I wanted to hear about how to package an app and deliver it to end users.

crocket14:12:30

Delivering a clojurescript app with npm_modules sounds weird.

jaen14:12:09

I'd put that in .gitignore and just require the end user to do npm install before using your application.

crocket14:12:15

Delivering it as an npm module is an option, though.

jaen14:12:49

This seems to be a working example of a Cljs node app - https://github.com/kissaten/cljs-nodejs-example

crocket14:12:56

I can't imagine it becoming an OS package.

crocket14:12:31

Ok, I was thinking about writing a shell script.

jaen14:12:32

Hmm, what sort of application you are doing you expect other people to run it?

jaen14:12:44

Did you consider something like node-webkit or electron?

crocket14:12:50

A command line shell script

crocket14:12:57

electron creates a desktop GUI application.

crocket14:12:38

npm install -g cljs-module is an option, but I was looking for a more elegant solution.

jaen14:12:47

Ah, I see.

jaen14:12:09

But isn't npm install -g whatever what node world does for modules that have executables anyway?

crocket14:12:36

I wanted to package my command line shell script for linux distros.

jaen14:12:19

Then I guess you'd want to look at how each distro does it for node packages.

jaen14:12:22

Other distros will probably have different guidelines

jaen14:12:33

I'd first look at getting it to work as a npm package

crocket14:12:46

Ok, thanks

jaen14:12:48

And then see what are the guidelines for the distros you want to make it available to.

jaen14:12:58

No problem.

crocket14:12:30

According to my benchmark, the simplest program takes 0.09 second to launch after advanced optimization.

jaen14:12:16

Hm, I'd check if there is any noticeable difference between using :simple and :advanced

crocket14:12:21

startup time is 3-4 seconds for clojure.

jaen14:12:55

With :simple you won't need to worry about externs

jaen14:12:01

Which simplifies things considerably

jaen14:12:08

Since only :advanced does global renaming.

jaen14:12:42

And it's not the browser, where every byte counts.

crocket14:12:04

It causes headache. Why can clojure not boot up fast?

jaen14:12:24

It's the way it's written.

crocket14:12:38

For :simple, it takes 0.16s to launch.

crocket14:12:50

So, twice as slow

crocket14:12:06

twice as slow in bigger programs, maybe

jaen14:12:12

Blogposts here will be informative why Clojure is so slow to boot - http://blog.ndk.io/

crocket14:12:18

A simple nodejs program takes 0.06s to launch.

jaen14:12:25

Hmm, 0.16s doesn't seem like much.

crocket14:12:49

A gloomy prospect is that clojurescript might be slow to boot in non-trivial programs

crocket14:12:15

For that, I might need the power of ocaml, haskell, or scheme.

jaen14:12:46

Well, programs that compile to native code will always be faster to boot.

crocket14:12:50

OCaml is known to boot blazingly fast.

crocket14:12:23

Would boot time substantially increase in bigger programs?

crocket14:12:28

like 1.5seconds

jaen14:12:23

I wouldn't know - in general the bigger the program is, the slower it is to boot, but that's how it is for any sufficiently complex program.

jaen14:12:51

I don't imagine boot time would be prohibitive for Clojurescript and node, but I don't have or know of any big enough codebase

jaen14:12:07

To have any concrete data

crocket14:12:53

For a shell script, a long startup time annoys.

crocket14:12:10

3 seconds are not acceptable for repetitively launched scripts.

jaen14:12:22

That is certainly true, but I don't think it should be this much of a problem. But maybe then again there is someone here with a bigger node codebase to say how it behaves in practice.

bherrmann15:12:06

One can cheat at getting the JVM/Clojure to start fast by using nailgun http://www.martiansoftware.com/nailgun/

jaen15:12:17

Or drip, I think. But yeah, that's cheating.

jbaiter17:12:08

Does anybody know how I can access an "id" property on a JS object? I can access all properties except for the one with the key "id"

jbaiter17:12:45

I tried both (.-id myobj) and (aget myobj "id"), neither works

jbaiter17:12:13

chrome debugging console says the object has an "id" property and also shows a value for it

jbaiter18:12:05

that works, thanks!

jbaiter18:12:37

it's the first i've heard of that fn, most docs I could find tell you to use "aget" or the ".-" form, do you know why neither of these work in my case?

jaen18:12:32

No idea. What I know is .- is equivalent to dot access (`a.b`), aget is eqivalent to indexing (`a[b]`).

jbaiter18:12:56

thanks jaen!

richiardiandrea18:12:53

An idea I had to increase Leiningen speed, port it to self-hosted ClojureScript! 😄