:target :esm unable to require native Node modules such as "process"
Here I want to compile ClojureScript to a JavaScript module that will run in Node, and which uses the native Node module "process".
package.json:
{
"devDependencies": {
"shadow-cljs": "^2.28.21"
}
}
shadow-cljs.edn:
{:source-paths ["src"]
:builds
{:go
{:target :esm
:runtime :node
:output-dir "js"
:modules
{:go {:exports {go run/go}}}}}}
src/run.cljs:
(ns run
(:require
["process" :as node-process]))
(defn go []
(println "this is run go"))
$ npx shadow-cljs compile go
shadow-cljs - config: /home/andrew/prj/pull-flow/shadow-cljs.edn
[:go] Compiling ...
The required JS dependency "process" is not available, it was required by "run.cljs".
Dependency Trace:
run.cljs
Searched for npm packages in:
/home/andrew/prj/pull-flow/node_modules
process is part of the node-libs-browser polyfill package to provide node-native package support
for none-node builds. You should install shadow-cljs in your project to provide that dependency.
npm install --save-dev shadow-cljs
See: https://shadow-cljs.github.io/docs/UsersGuide.html#project-install
I tried some :js-options :resolve options but didn't find one that seemed to make a difference.
Is there a way to say, "Believe me, 'process' is there, just go ahead and use it"?
Not particularly urgent because I can pass "process" from JavaScript to my ClojureScript code, but was wondering if there was a way to do this.
The default for :esm is to bundle all dependencies, mainly so it can run in browsers. For node you can either opt to bundle nothing and just let node load it at runtime, or bundle some parts but let node load the rest.
To bundle nothing set :js-options {:js-provider :import} in the build config.
To bundle everything except a few packages set :js-options {:keep-as-import #{"process"}}. This will bundle everything except the process dependency. By "everything" here I mean everything shadow-cljs can see. If you exclude something via that :keep-as-import set, then all its dependencies will also be excluded since shadow can't see those. This may or may not cause problems.
Should we add ":import" to https://shadow-cljs.github.io/docs/UsersGuide.html#js-provider ?
Perhaps something like, if I understand correctly:
:importMaps requires to the JS
import * from "thing";statement. The referenced JS dependencies are not included in the build. Meant to be used with another build tool that will bundle the dependencies or with a program such as node which can resolve the imports natively.
This is all documented under the :target :esm docs. Specifically here, although that should probably mention node.
The docs are here if you want to make a PR: https://github.com/shadow-cljs/shadow-cljs.github.io
For process in particular you could access it as a global like (js/process.nextTick (fn [] ...))