从ClojureScript内部调用npm模块(npm-deps)

简而言之

在 project.clj 中添加编译器选项 :npm-deps 和 :install true。

就是这种感觉。

diff --git a/project.clj b/project.clj
index 24f0146..065a9f6 100644
--- a/project.clj
+++ b/project.clj
@@ -25,6 +25,8 @@
                 :output-to "target/js/compiled/hello_aws_cli.js"
                 :output-dir "target/js/compiled/dev"
                 :target :nodejs
+                :npm-deps {:aws-sdk "^2.167.0"}
+                :install-deps true
                 :optimizations :none
                 :source-map-timestamp true}}
              {:id "prod"

一旦开始写 ClojureScript 的新手很容易陷入一个巨大的陷阱,那就是”从 ClojureScript 代码中调用 npm 代码”。

我试着去搜索一下,发现使用CLJSJS可能会很好用,或者如果没有的话需要自己编写externs文件。虽然找到了很多信息,但是有的不起作用,有的让我感到困惑,花了整整一个星期…

使用npm-deps编译器选项!

在这种情况下,发现了这篇文章。
https://clojurescript.org/news/2017-07-12-clojurescript-is-not-an-island-integrating-node-modules

哇!
我们马上试试看。

$ lein new figwheel-node hello-aws-cli
$ cd hello-aws-cli

在 project.clj 文件中添加 :npm-deps {:aws-sdk “^2.167.0”} 和 :install true。

diff --git a/project.clj b/project.clj
index 24f0146..065a9f6 100644
--- a/project.clj
+++ b/project.clj
@@ -25,6 +25,8 @@
                 :output-to "target/js/compiled/hello_aws_cli.js"
                 :output-dir "target/js/compiled/dev"
                 :target :nodejs
+                :npm-deps {:aws-sdk "^2.167.0"}
+                :install-deps true
                 :optimizations :none
                 :source-map-timestamp true}}
              {:id "prod"

为了将cljs代码转译成JS代码并打开REPL,执行”lein figwheel”命令,其中包括依存关系的安装。

$ lein figwheel
Launching ClojureScript REPL for build: dev
Figwheel Controls:
          (stop-autobuild)                ;; stops Figwheel autobuilder
          (start-autobuild [id ...])      ;; starts autobuilder focused on optional ids
          (switch-to-build id ...)        ;; switches autobuilder to different build
          (reset-autobuild)               ;; stops, cleans, and starts autobuilder
          (reload-config)                 ;; reloads build config and resets autobuild
          (build-once [id ...])           ;; builds source one time
          (clean-builds [id ..])          ;; deletes compiled cljs target files
          (print-config [id ...])         ;; prints out build configurations
          (fig-status)                    ;; displays current state of system
          (figwheel.client/set-autoload false)    ;; will turn autoloading off
          (figwheel.client/set-repl-pprint false) ;; will turn pretty printing off
  Switch REPL build focus:
          :cljs/quit                      ;; allows you to switch REPL to another build
    Docs: (doc function-name-here)
    Exit: Control+C or :cljs/quit
 Results: Stored in vars *1, *2, *3, *e holds last exception object
Prompt will show when Figwheel connects to your application

所以我会打开另一个终端。

$ node target/js/compiled/hello_aws_cli.js
Hello world!
Figwheel: Can't start Figwheel!! Please make sure ws is installed
 do -> 'npm install ws'

嗯??
貌似在lein figwheel中安装的依赖关系只有在project.clj中所记录的(package.json中管理的不会被安装)。

因此,根据所说的,我运行了npm install,然后再次尝试运行…

$ npm install
....

$ lein figwheel
Hello world!
Figwheel: trying to open cljs reload socket
Figwheel: socket connection established

哦,看起来进展顺利。
当我查看另一个终端时,

...
Prompt will show when Figwheel connects to your application
To quit, type: :cljs/quit
dev:cljs.user=> (+ 1 2)
3
dev:cljs.user=>

这感觉不错!现在已经准备好 REPL 了。
那我们来试试能否加载 AWS SDK 吧!

dev:cljs.user=> (require '[cljs.nodejs :as nodejs])
nil
dev:cljs.user=> (def AWS (nodejs/require "aws-sdk"))
#'cljs.user/AWS
dev:cljs.user=> AWS
#js {:util #js {:environment "nodejs", :engine #object[engine], :userAgent #object[userAgent], :isBrowser #object[isBrowser], :isNode #object[isNode], :uriEscape #object[uriEscape], :uriEscapePath #object[uriEscapePath], :urlParse #object[urlParse], ... ; 以下略

哇!太好了。

使用npm-deps编译器选项,npm的使用变得非常简单和方便呢!

请参阅网址

https://cljs.github.io/api/compiler-options/npm-deps 可以引用跳转至cljs.github.io/api/compiler-options/npm-deps网页
https://anmonteiro.com/2017/03/requiring-node-js-modules-from-clojurescript-namespaces/ 包含了如何从ClojureScript命名空间中引用Node.js模块的信息
https://clojurescript.org/news/2017-07-12-clojurescript-is-not-an-island-integrating-node-modules 描述了ClojureScript不是一个孤立的系统,可以集成Node模块的能力

可能只有我上了当…?
我想使用最新的AWS JavaScript SDK和Alexa Skill Kit。
但是请注意,它只能在ClojureScript v1.9.518及以上版本中使用…