How to author agnostic JavaScript library in ClojureScript?

為{幸葍}努か 提交于 2019-12-03 15:44:23

shadow-cljs supports output in a CommonJS format via :target :npm-module which does support exactly what you are asking for. Node and other JS tools (eg. webpack) can consume separate namespaces independently. The default CLJS tools do not support this mode.

ClojureScript however is very much written with the assumption that your whole program will be optimized by the Closure Compiler. This makes it less than ideal for writing libraries to be included in other builds. Each "library" built this way will contain its own version of cljs.core and therefore will be pretty large to begin and including 2 libraries built this way is a recipe for disaster since they won't be compatible with each other.

This assumes that you already have a working installation of ClojureScript and Node.js


Given:

math101
|-- package.json
|-- src
|   `-- com
|       `-- example
|           `-- math.cljs

package.json

{
  "name": "math101",
  "version": "1.0.0",
  "main": "dist/index.js",
  "license": "MIT",
  "devDependencies": {
    "shadow-cljs": "^2.8.52",
    "source-map-support": "^0.5.13"
  }
}

Notes:

  • dist/index.js - This will contain our ClojureScript code converted to JavaScript
  • shadow-cljs - The build (and dependency management) tool that we need
  • source-map-support - Required to run ClojureScript on Node.js

📣Please make sure you have installed these two NPM dependencies before you proceed further.

math.cljs

(ns com.example.math)

(defn add [x y]
  (+ x y))

1. Setup the build tool

At the root of math101 run yarn shadow-cljs init.
This will create a file called shadow-cljs.edn with some default settings:

;; shadow-cljs configuration
{:source-paths
 ["src/dev"
  "src/main"
  "src/test"]

 :dependencies
 []

 :builds
 {}}

Let's make some changes.

First you don't need that many source paths for this:

{:source-paths
 ["src"]

 :dependencies
 []

 :builds
 {}}

Then let's add a build configuration:

;; shadow-cljs configuration
{:source-paths
 ["src"]

 :dependencies
 []

 :builds
 {:math101 {:target :node-library
            :output-to "dist/index.js"
            :exports-var com.example.math/add}}}

Notes:

  • :math101 - This the build id that we will use later
  • :target :node-library - This tells shadow-cljs that you intend to author a library
  • :output-to "dist/index.js" - The code you intend to publish
  • :exports-var com.example.math/add - "Fully qualified name" of the function you intend to publish. This will produce a default export.

Additional notes:

The :target :node-library emits code that can be used (via require) as a standard node library, and is useful for publishing your code for re-use as a compiled Javascript artifact.

Source

There is a :npm-module target available but so far :node-library has checked all the boxes for me.

2. Let's build this!

Run yarn shadow-cljs compile math101.
The first time you run this, shadow-cljs will download a bunch of stuff. Eventually it will finish and when it does...

$ node
> var add = require('./dist')
> add(40, 2)
42

✨✨✨

Need to export more than just one function? No problemo.

Let's add subtract:

(ns com.example.math)

(defn add [x y]
  (+ x y))

(defn subtract [x y]
  (- x y))

And now let's update our build config:

;; shadow-cljs configuration
{:source-paths
 ["src"]

 :dependencies
 []

 :builds
 {:math101 {:target :node-library
            :output-to "dist/index.js"
            :exports {:add com.example.math/add
                      :subtract com.example.math/subtract}}}}

Run yarn shadow-cljs compile math101 again and when it finishes:

$ node
> var math101 = require('./dist')
> math101.add(40, 2)
42
> math101.subtract(44, 2)
42

✨✨✨✨✨✨


ADDENDUM

This is only intended to get you started. shadow-cljs compile generates non-production code (i.e. it's not minified, dead code is not removed AFAIK and Google Closure hasn't run any optimisation yet).

The command for generating production-ready code is shadow-cljs release but you may want to tweak your build config before.

I would highly recommend that you invest time reading up the shadow-cljs documentation. It is an amazing tool.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!