This guide is modeled after the ClojureScript Webpack Guide. If you prefer a more concise guide, feel free to head over there now.
Set the :target
compiler
option
to :bundle
. This will cause the compiler to emit an output file
file that can be bundled a JavaScript bundler like webpack
.
Optionally set the :bundle-cmd
compiler
option
to
{:none {"npx" "webpack" "--mode=development" :output-to "-o"
:final-output-to}}
to ensure the output file is bundled after a compile. Figwheel will fill in :output-to
and :final-output-to
.
Your host page will need to load the final bundled asset.
Relevant Figwheel Options
Npm usage in Figwheel has changed significantly. For reference purposes the original version of this document can be found here
NPM is a package repository for the JavaScript ecosystem. Almost all available JavaScript libraries are packaged, stored, and retrieved via NPM.
We want to use these libraries inside our ClojureScript codebase, but there is some friction because ClojureScript embraced the Google Closure Compiler and its method of declaring libraries, which is quite different than NPM's.
{::comment} We could get into a debate about why ClojureScript designers decided to embrace the less popular ecosystem, but that is largely academic at this point. I will say that the advantages of effortless interactive development via hot-reloading and the amazing capabilities of the Google Closure Compiler's advanced mode are direct benefits of using the GCC's (Google Closure Compiler's) method of defining modules via simple JavaScript object literals. In other words, without the GCC there would most likely not be a Figwheel.
Nevertheless, experiencing friction while importing libraries from the dominant JavaScript ecosystem is a very unfortunate trade-off. {:/comment}
However, with recent changes in the ClojureScript compiler (along with changes in Figwheel) it is now becoming much more straightforward to include NPM modules in your codebase.
We are going to assume you are starting from the base example.
I'm going to use npm
for this example but if you prefer yarn
go
ahead and use that. It doesn't really matter for this.
There are four steps that we are going to follow to add some libraries to
our hello-world.core
project.
package.json
fileWe will need to initialize npm
for our hello-world
project.
One way to do this is to use the npm init
command. You can of course
just create the file from scratch but npm init
is faster.
Make sure you are in the root directory of the project and execute:
$ npm init -y
This will create a package.json
file in the root directory of your
project along side your dev.cljs.edn
file.
We will need webpack to bundle our application along with our moment
dependency to make it available to our ClojureScript code.
Install webpack
and webpack-cli
:
$ npm add --save-dev webpack webpack-cli
This add webpack
and webpack-cli
as development dependencies in
your package.json
. It will also download them to a node_modules
directory in your project.
Let's say we want to use the moment
library in our
application.
We'll use npm
to add a moment
dependency to our package.json
file in the usual manner:
$ npm add moment
This should download and install the moment
library along with its
dependencies if it has any.
Everything we have done up until this point is very similar to what we would normally do if we were using NPM and Webpack for a simple JavaScript project.
In the dev.cljs.edn
file we'll add the following config:
{:main hello-world.core
:target :bundle
:bundle-cmd {:none ["npx" "webpack" "--mode=development" :output-to "-o" :final-output-to]}}
Understanding the above configuration is important, so I'm going to explain each part.
The :target
compiler
option
is set to :bundle
to instruct the ClojureScript compiler to produce
an output file that can be bundled by a JavaScript bundler like Webpack.
The :bundle-cmd
compiler option
Figwheel adds some additional functionality to the :bundle-cmd
. It
interpolates the keywords :output-to
and :final-output-to
into the
command. In this case the :output-to
is going to be replaced by the
default :output-to
path target/public/cljs-out/dev/main.js
. The
:final-ouput-to
is replaced by the default value of :output-to
with a _bundle
added before the extension or
target/public/cljs-out/dev/main_bundle.js
.
Or stated more simply in this case:
:output-to
is replaced with target/public/cljs-out/dev/main.js
:final-output-to
is replaced with target/public/cljs-out/dev/main_bundle.js
If you supply your own :output-to
cljs compiler option, it will be
used instead of the default.
Thus after the ClojureScript compiler is finished compiling it will
call the :bundle-cmd
to bundle up the output.
In this case it will call:
$ npx webpack --mode=development target/public/cljs-out/dev/main.js -o target/public/cljs-out/dev/main_bundle.js
This will bundle up the main.js
file and pull in the moment
dependency along with it.
Now let's modify our source file to use moment
so that we can make
sure that things are working.
Edit the src/hello_world/core.cljs
to look like:
(ns hello-world.core
(:require [moment]))
(js/console.log moment)
(println (str "Hello there it's "
(.format (moment) "dddd")))
OK now that we've setup everything up we can run the build.
$ clojure -m figwheel.main -b dev -r
The browser and REPL should launch as usual:
Except now you can see one additional line in the output which notifies us that the bundle command was called.
And if you look at the dev tools console of the browser window that
just popped open you should see similar output printed as below
verifying that we were able to use moment
successfully.
Well we successfully used an NPM package from our ClojureScript
code. Now you can npm add
other JavaScript NPM packages and use them
from ClojureScript
Can you improve this documentation? These fine people already did:
Bruce Hauman, bpringe, Michael Camilleri, Alan Thompson, Jindrich Mynarz & Jonathon McKitrickEdit on GitHub
cljdoc is a website building & hosting documentation for Clojure/Script libraries
× close