2

In my ClojureScript code I am requiring a JavaScript module called seedrandom which is in the node_modules folder, like this:

(ns something.core
  (:require ["seedrandom" :as rnd]))
(js/console.log (.quick (rnd "x")))

According to the seedrandom documentation it is intended for both nodejs and the browser, and I've previously included and used it successfully in ClojureScript code via a <script> tag, confirming it works in the browser.

Running this cljs file in lumo on the command line works well and outputs a deterministically random number.

When I try to use this same cljs file in my Reagent frontend project I see the following error:

Compiling build :app to "public/js/app.js" from ["src" "env/dev/cljs"]...
events.js:183
      throw er; // Unhandled 'error' event
      ^

Error: module not found: "crypto" from file /home/chrism/dev/something/node_modules/seedrandom/seedrandom.js
    at onresolve (/home/chrism/dev/something/node_modules/@cljs-oss/module-deps/index.js:181:30)
...

Inside seedrandom.js we see the following:

  // When in node.js, try using crypto package for autoseeding.
  try {
    nodecrypto = require('crypto');
  } catch (ex) {}

Clearly this code is intended to ignore the built-in nodejs crypto module when running in the browser. The problem, as far as I can tell, is that the ClojureScript compiler does not know that - it sees that require('crypto') and tries to pull it into the compilation phase, but can't find it because it's a nodejs built-in.

Is there some way I can tell the compiler to ignore that particular require? Or can I shim the 'crypto' module somehow? What is the cleanest way to solve this?

Note: I have previously experienced this same issue with JavaScript modules which check for the fs node module. Hope we can find a general solution to use again in future. Thanks!

Relevant versions: [org.clojure/clojurescript "1.10.520"] and [reagent "0.8.1"].

This answer is related, asking a similar question from the perspective of Google Closure, which ClojureScript uses, but I'm looking for an answer I can use specifically with cljs.

Chris McCormick
  • 4,356
  • 1
  • 21
  • 19
  • What tool are you using to build your project (Lein, ShadowCljs, etc.)? Are you adding configuration to target the browser (something like `:target :browser`)? – Denis Fuenzalida Sep 25 '19 at 05:30
  • I am using `lein` and my project was bootstrapped with `lein new reagent-frontend something`. – Chris McCormick Sep 25 '19 at 05:31
  • According to the ClojureScript compiler options documentation, valid options for `:target` are `:nodejs` and `:webworker` and if no option is specified the default is to target the browser. There is no `:target` set in `project.clj`. – Chris McCormick Sep 25 '19 at 05:34
  • My recommendation would be to try again creating a new project with `lein new reagent-frontend +shadow-cljs`, because Shadow CLJS works nicely with npm too. Note that I haven't tested this template myself, but worked starting with this demo project instead: https://github.com/minimal-xyz/minimal-shadow-cljs-browser – Denis Fuenzalida Sep 25 '19 at 05:39
  • Thank you, will check that out. In the meantime I have got a working build by following David Nolan's [ClojureScript with Webpack](https://clojurescript.org/guides/webpack) tutorial. – Chris McCormick Sep 25 '19 at 06:38

0 Answers0