Require ClojureScript's Analyzer API - clojurescript

I'm having trouble requiring ClojureScript's analyzer API:
(ns triangle.core
(:require
[cljs.analyzer.api :as ana-api]))
yields:
clojure.lang.ExceptionInfo : No such namespace: cljs.analyzer.api, could not locate cljs/analyzer/api.cljs, cljs/analyzer/api.cljc, or Closure namespace "cljs.analyzer.api" in file ...
Anybody knows, what could be the reason? Requiring cljs.analyzer works without problems.

Works for me, are you using the latest version?

Related

Requiring javascript with Clojurescript :bundle

Using ClojureScript :bundle
I can require other javascript libraries but react-datepicker is causing the followinf error:
react-dom.development.js:23965 Uncaught Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object.
This is how I requires the library
(:require ["react-datepicker" :as DatePicker])
Than I attempt to use it
($ DatePicker {...})
My guess would be that react-datepicker has a default export.
Try ($ DatePicker/default ...) or with the upcoming CLJS release it would be (:require ["react-datepicker$default" :as DatePicker]) but that is not released as of today and would require cloning master.

Failed to construct ‘HTMLElement’: Please use the ‘new’ operator

I am trying to use AWS Amplify Authentication lib in a re-frame app.
The lib provides a higher order component withAuthenticator which is supposed to wrap the main view of your app. I am trying to use reactify-component and adapt-react-class but unfortunately I get the following error:
Uncaught TypeError: Failed to construct ‘HTMLElement’: Please use the ‘new’ operator, this DOM object constructor cannot be called as a function.
(defn main-panel []
[:div
[:h1 "Hello" ]])
(def root-view
(reagent/adapt-react-class
(withAuthenticator
(reagent/reactify-component main-panel))))
(defn ^:dev/after-load mount-root []
(re-frame/clear-subscription-cache!)
(aws-config/configure)
(re-frame/dispatch-sync [::events/initialize-db])
(reagent/render [root-view]
(.getElementById js/document "app")))
Any help is appreciated
I had this issue with reagent + amplify.
Solved it with 2 changes, but I'm unsure if both are needed
#1 Change output of the google closure compiler to es6 (or higher). Amplify seems to use es6 features that Cannot be polyfilled.
This is for shadow-cljs (shadow-cljs.edn), but this should be possible for other build systems as well.
{:builds {:app {:compiler-options {:output-feature-set :es6}}}}
Disclaimer: I switched to shadow-cljs from lein-cljsbuild since I could not get lein-cljsbuild to respect the configuration for es6 output.
#2 Use functional components.
In reagent 1.0.0-alpha1 and up you can change the compiler to produce functional components by default.
(ns core
(:require
[reagent.core :as r]))
(def functional-compiler (r/create-compiler {:function-components true}))
(r/set-default-compiler! functional-compiler)
There are other ways to make functional components. Check the documentation if you don't like, or can't use, this approach.

How can I stop the ClojureScript compiler from resolving certain `require`s?

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.

Can I use arbitrary node modules from clojurescript?

Is it possible to use arbitrary node.js modules in a clojurescript project? If yes, how do I go about including them? If not, why not?
Yes, you can, there is nothing special about it:
(def fs (js/require "fs"))
(println (.readdirSync fs js/__dirname))
Be careful with the externs if you don't use optimizations none.
Edit: Does leiningen play with the various js package managers?:
Nope. Since the language does not have packages, it cannot know. You have to do js dependency management and lein deps too. There is a lein-npm and a lein-bower to help with integrating these two package managers.
Yes, since late 2017. With shadow-cljs or Lumo now it's not problem to import npm modules in ClojureScript code anymore.
(ns app.main
(:require ["dayjs" :as dayjs]
["shortid" :as shortid]
["lodash" :as lodash]
["lodash" :refer [isString]]))
Read this topic for details: Guide on how to use/import npm modules/packages in ClojureScript?
Since ClojureScript 1.9.854, there's better support to declare npm modules as dependencies and to require them from your namespaces.
In order to declare it as a dependency, you need to use the :npm-deps compiler option (together with the :install-deps one, if you want lein/bootto automatically install it).
:npm-deps is a map from keyword to string, where the keyword is the name of the dependency you would use to install it using npm and the string is the version of the dependency.
An example of what you could add to your project.clj (if you use lein-cljsbuild), in order to use left-pad:
:cljsbuild {:builds [{:id "prod"
:source-paths ["src"]
:compiler {:main left-pad-demo.core
:output-to "package/index.js"
:target :nodejs
:output-dir "target"
:optimizations :simple
:install-deps true
:npm-deps {:left-pad "1.2.0"}
:pretty-print true}}]})
And then, from your namespace, you can require it like so:
(ns left-pad-demo.core
(:require left-pad))
Or so:
(ns left-pad-demo.core
(:require ["left-pad" :as lp]))
A full working namespace could look like:
(ns left-pad-demo.core
(:require left-pad))
(defn -main [s length]
(console.log (left-pad s length)))
(set! *main-cli-fn* -main)
References:
Requiring Node.js modules from ClojureScript namespaces
ClojureScript is not an Island: Integrating Node Modules

How do you organize function names when building clojure libraries for public consumption?

Let's say I want to build a large clojure library with several components. As a developer, I would like to keep many of the components in separate namespaces since many helper functions can have similar names. I don't necessarily want to make things private since they may have utility outside in extreme cases and the work-arounds behind private is not good. (In other words, I would like to suggest code usage, not completely prevent usage.)
However, I would like the users of the library to operate in a namespace with a union of a subset of many of the functions in each sub library. What is the idiomatic or best way to do this? One solution that comes to my mind is to write a macro that generates :requires and creates a new var mapping by def'ing a given list of var names (see first code example). Are there tradeoffs with this method such as what happens to extending types? Is there a better way (or builtin)?
Macro example (src/mylib/public.clj):
(ns mylib.public
(:require [mylib.a :as a])
(:require [mylib.b :as b]))
(transfer-to-ns [+ a/+
- b/-
cat b/cat
mapper a/mapper])
Again, to clarify, the end goal would be to have some file in other projects created by users of mylib to be able to make something like (src/someproject/core.clj):
(ns someproject.core
(:require [mylib.public :as mylib]))
(mylib/mapper 'foo 'bar)
#Jeremy Wall, note that your proposed solution does not fullfill my needs. Lets assume the following code exists.
mylib/a.clj:
(ns mylib.a)
(defn fa [] :a)
mylib/b.clj:
(ns mylib.b)
(defn fb [] :b)
mylib/public.clj:
(ns mylib.public
(:use [mylib.a :only [fa]])
(:use [mylib.b :only [fb]]))
somerandomproject/core.clj: (Assume classpaths are set correctly)
(ns somerandomproject.core
(:require [mylib.public :as p])
;; somerandomproject.core=> (p/fa)
;; CompilerException java.lang.RuntimeException: No such var: p/fa, compiling: (NO_SOURCE_PATH:3)
;; somerandomproject.core=> (mylib.a/fa)
;; :a
If you notice, "using" functions in mylib/public.clj DOES NOT allow public.clj to PROVIDE these vars to the user file somerandomproject/core.clj.
You might find it interesting to look at how a library like Compojure or Lamina organizes its "public" api.
Lamina has "public" namespaces like lamina.api that serve to alias (using Zach's import-fn from his potemkin library) functions from the "internal" namespaces like lamina.core.pipeline. With a bit of docs, this serves to clearly delineate the public-facing ns's from the likely-to-change internals. I've found the major drawback to this strategy is that the import-fn makes it much more difficult to walk (in emacs) from the use of a function into it's implementation. Or to know which function to use clojure.repl/source on for example.
A library like Compojure uses private vars to separate public/private parts of the functions (see compojure.core for example). The major drawback with "private" functions is that you may later find you want to expose them or that it makes testing more complicated. If you control the code base, I don't find the private aspects to be a big deal. The testing issue is easily worked around by using #'foo.core/my-function to refer to the private function.
Generally I tend to use something more like Compojure's style than Lamina's but it sounds like you'd prefer something more like Lamina.
I'm not exactly sure what your asking here. I think maybe you want to know what the best practice for importing publics from a namespace for shared utility functions? In that case the refer function is what you are looking for I think: http://clojure.github.com/clojure/clojure.core-api.html#clojure.core/refer
(refer mylib.a :only [+])
(refer mylib.b :only [-])
It imports the public items in a namespace into the current namespace. However the preferred method would be to do this in your namespace declaration with a :use directive
(ns (:use (mylib.a :only [+])
(mylib.b :only [-])))