Creating & using libraries in both Clojure and ClojureScript
Asked Answered
S

2

12

I've just written some ClojureScript code, only to find out that I couldn't access one of the libraries listed in my project.clj's dependencies. Is this correct, i.e. that you can't use Clojure libraries from CLJS unless they're specifically designed to allow it?

If so, how much extra work is required to take a Clojure library that doesn't use any Java interop, and would itself be valid ClojureScript code, and make it useable from ClojureScript? From looking around GitHub, many libs appear to have separate source directories for clj and cljs code. Can such a library be added to my project.clj and be used immediately from either platform?

Stokehole answered 27/3, 2013 at 13:3 Comment(0)
T
6

There are some ClojureScript differences from Clojure.

Dependecies from "project.clj" can be applicable / visible / usable by ClojureScript, for example, take a look at "jayq". You would include it in "project.clj":

(defproject xyz/xyz "0.1.0-SNAPSHOT"
  :dependencies [[clj-time "0.4.3"]
                 [jayq "2.2.0"]
                  ....

And then use it in the ClojureScript file:

(ns xyz.some.cljs
  (:require ...
            ...
            [clojure.browser.repl :as repl]
            [jayq.core :as jq])

While "jayq" is not a "Clojure" library in the "backend" sense since it just wraps JavaScript, it is an example of using a "project.clj" dependency on the ClojureScript side.

In addition most of the core and several non core libraries are already ported to the ClojureScript side:

  • clojure.set
  • clojure.string
  • clojure.walk
  • clojure.zip
  • clojure.core.reducers
  • fold is currently an alias for reduce
  • core.match
  • core.logic (in works)

Other Clojure libraries will have to conform to the ClojureScript subset in order to work in ClojureScript.

It is worthwhile to clone ClojureScript repo and get a sense of what it supported (plus add your own features if you feel adventurous :)

ClojureScript dependencies are usually "front end" based (included the ones ported from backend). In other words, the end goal is to be compiled by V8 and run as JavaScript, hence anything that can be compiled by the ClojureScript compiler (repo above) can be used.

Tact answered 27/3, 2013 at 15:26 Comment(6)
Thanks. So when I add jayq to my project.clj file, how does the compiler know that it's ClojureScript? I see that jayq's own project file is almost empty: github.com/ibdknox/jayq/blob/master/project.clj So how does it tell?Stokehole
Also, as an extension to the above, if I wanted to write a library that worked from both "ends," how would I go about it?Stokehole
usually when developing in Clojure/ClojureScript, you would use a lein-cljsbuild plugin that allows to configure CLJS compiler via "project.clj", as well as share code where you can reuse namespaces between Clojure and ClojureScript. Of course: "remember that since the namespace will be used by both Clojure and ClojureScript, it will need to only use the subset of features provided by both languages"Tact
OK. So if I wrote a library with a project.clj that pointed to a crossover namespace with all my code in it, that library would work from both Clojure and ClojureScript? If so, how come jayq doesn't have anything in its project.clj?Stokehole
correct. given that a new library files are in :source-dir/:extra-classpath-dirs + they are in "ClojureScript" supported feature subset. Also try it first without building a new library "jar", but using the library ".clj" files directly (e.g. easier for lein-cljsbuild to manage the classpath and monitor changes)Tact
Thanks for answering my questions. I have just one more: I was looking at the core.match source, noting that it works from either Clojure or ClojureScript. In github.com/clojure/core.match/blob/master/project.clj under the cljbuild key, it doesn't list any crossovers. How, then, does it use the same codebase for both platforms?Stokehole
H
0

I see that the answers were given in 2013, but as of 2020, this is still the case with CLJS version 1.10. Its still not possible to use just any Clojure library, unless the library has been made CLJS compatible.Building with shadow-cljs will give build error like:

The required namespace "clojure.data.json" is not available, it was required by "bharati/binita/frontend/demo3/main.cljs".
"clojure/data/json.clj" was found on the classpath. Should this be a .cljs file?

I could not see any solution to that,other than using any other alternative library that is CLJS compatible.

Hansiain answered 19/2, 2020 at 9:19 Comment(2)
Since Clojure 1.8 (2016), if library writers name their source files ".cljc" instead of ".clj", the library is usable in all variants of Clojure. See release notes github.com/clojure/clojure/blob/clojure-1.8.0/changes.md. A cljc file should mainly stick to portable language features, but may provide JVM/JS/CLR variants where it needs to.Onfre
Anyway, clojure.data.json is a salve for JVM programs that must jump through hoops to read JSON. Browsers read JSON natively; no need for such a library. You may read and write JSON using ClojureScript's JS interop.Onfre

© 2022 - 2024 — McMap. All rights reserved.