This is topic is created for SEO purpose. I asked this question many times during 2016 and 2017. And we got an answer since late 2017 with shadow-cljs. I’m still seeing other people asking the same question today.
The docs you want Shadow CLJS User’s Guide
Try running this project if you want to explore by yourself GitHub - minimal-xyz/minimal-shadow-cljs-importing-npm: Guide on importing npm module in ClojureScript with shadow-cljs
Guide
To run shadow-cljs, you need to install shadow-cljs
from npm locally or globally, and add a shadow-cljs.edn
as a configuration file. Nothing special here in the config(search “shadow-cljs guide” if you need more hints).
{:source-paths ["src"]
:dev-http {8080 "target/"}
:builds {:client {:output-dir "target/"
:asset-path "./"
:target :browser
:modules {:client {:init-fn app.main/main!}}
:devtools {:after-load app.main/reload!}}}}
Say I want to use several npm packages, I installed them from npm with yarn
or npm
:
yarn add dayjs shortid lodash
These libraries can be imported in JavaScript like:
import dayjs from "dayjs"
import shortid from "shortid"
import lodash from "lodash"
import {isString} from "lodash"
In ClojureScript, it’s almost same if you use shadow-cljs:
(ns app.main
(:require ["dayjs" :as dayjs]
["shortid" :as shortid]
["lodash" :as lodash]
["lodash" :refer [isString]]))
The code are being called in JavaScript like:
console.log(dayjs())
console.log(shortid.generate())
console.log(isString("a string"))
console.log(lodash.isObject("a string"))
It’s not much different. Onething to notice here is the syntax in lodash/isObject
, which is using /
rather than .
since lodash
has become a namespace in this file:
(.log js/console "dayjs" (dayjs))
(.log js/console "shortid" (.generate shortid))
(.log js/console "lodash" (isString :a-keyword) (lodash/isObject {}))
Again, you can more details on shadow-cljs docs Shadow CLJS User’s Guide
One more thing to mention is the example above runs in a browser. It should work in Node.js too since the libraries are platform-agnostic. However you need different shadow-cljs.edn
configurations for :node-script
, try this GitHub - minimal-xyz/minimal-shadow-cljs-nodejs: shadow-cljs hot code swapping for Node.js
More
- CommonJS solution
Alternatively in shadow-cljs it’s also possible to compile ClojureScript to JavaScript files in CommonJS format, then you can just bundle them with Webpack or Parcel(maybe…). It worked. But running two bundling tools might be inconvenient. Read more in the topic: Beginner guide to compile ClojureScript to CommonJS and use Webpack - #2 by jiyinyiyong
- Official solution
And you might also have found we can do that without shadow-cljs because of the official works in: New Guide: ClojureScript with Webpack - #17 by dnolen .
Well I’m just so glad I’m not trapped in the problem of using npm modules in ClojureScript any more. It was hard times between 2014 and 2017. Now we have solutions.
Please correct me I have mistakes in my code or maybe just send pull request on this. This guide probably need a review from @thheller.