shxiao 2019-06-26
内容:
在 Node.js 环境运行 ClojureScript
这个版本基于 macOS 或者 Linux, 需要系统已经依赖 Clojure. Windows 用户请查看英文版.
首先创建项目文件:
mkdir hello_world; cd hello_world mkdir -p src/hello_world; touch src/hello_world/core.cljs
在项目中创建 deps.edn
文件, 其中添加依赖:
{:deps {org.clojure/clojurescript {:mvn/version "1.10.145"}}}
在文件 src/hello_world/core.cljs
中填写代码:
(ns hello-world.core) (println "Hello world!")
新手需要注意一下, 这里的文件路径, 跟 src/
这个默认的资源路径, 和 hello-world.core
这个命名空间对应. 同时, 连字符在 Java 世界需要在文件名当中改成 _
. 这个对于新手很容易造成误会.
然后可以启动 ClojureScript 环境了:
clj -m cljs.main -c hello-world.core -r
这个命令将会启动一个浏览器, 同时在命令行打印 "Hello World!", 以及启动一个 REPL. 接下来可以在 REPL 当中尝试运行一些代码:
(inc 1) (map inc [1 2 3]) (.getElementById js/document "app")
回来看下命令参数, -m
全称是 --main
, 调用 Clojure 函数, 这里是 cljs.main
当中的默认的 -main
函数. cljs.main/-main
支持一些其他的参数对应具体的任务, 比如这里 -c
全称 --compile
表示编译. 后面的 -r
全称是 --repl
表示同时启动一个 REPL:
然后试一下更新代码, 刚才那个文件更新成:
(ns hello-world.core) (println "Hello world!") ;; ADDED (defn foo [a b] (+ a b))
(require '[hello-world.core :as hello] :reload) (hello/foo 2 3)
正常的话你会看到结果 5
. (注: 然而看上去这里是有 bug 的. 实际运行代码并没有更新成功. 而且报错也没有预期的 .cljs
文件.)
clj -m cljs.main -h
你注意到生成的 out/
目录的话, 会发现其中有好几个 M 的文件内容. 这就需要 Google Closure Compiler 来帮助编译优化, 从而得到适合浏览器环境使用的代码. 主要依赖代码压缩和 Dead Code Elimination.
我们先把文件代码恢复到 src/hello_world/core.cljs
之前的:
(ns hello-world.core) (println "Hello world!")
用 -O
全称 --optimizations
参数来构建. 默认的构建 level 是 none
, 这里我们需要 Google Closure Compiler 全部的优化, 就制定 advanced
. 此外 -O
还有两个 level 分别是 whitespace
和 simple
.
clj -m cljs.main -O advanced -c hello-world.core
这个编译过程会有点费时间.
最后生成的 out/main.js
文件应该是 90k
左右, zip 之后还回到 20k
. 这已经比 jQuery 要小了. ClojureScript 依赖的标准库大约 10kloc
, 依赖的 Google Closure Library 大约(200kloc), 可以看到 Dead Code Elimination 是起作用了的.
你可以通过 -s
全称 --sever
参数启动一个服务器来确认文件正常工作:
clj -m cljs.main -s
这个命令仅仅启动服务器, 你需要自动打开 http://localhost:9000 的网页来看运行结果, 包括在 Console 里看 Hello World!
的内容. 这个服务器开启了 gzip, 在调试工具当中应该看到 js 文件体积大约应该是 20k.
Node.js 安装过程就不说了, 版本号总之别太低. SourceMaps 需要自己安装一下依赖:
npm install source-map-support
生成 Node 项目的话, 需要通过 -t
全称 --target
来指定目标. 默认的目标是浏览器, 其他目标还有 nashorn
和 rhino
这类的 JavaScript 运行环境. 这里还用到了 -O
全称 --output-to
来指定输出文件:
clj -m cljs.main -t node -o main.js -c hello-world.core
然后可以运行生成的文件:
node main.js注意: 对于 Node 环境来说, 优化代码的意义就不太大了, 引擎能力就很强大了, 一般用
simple
或者 none
作为 level 已经够了.跟前面浏览器的例子一样, 可以启动一个 Node.js 的 REPL. 指定 REPL 的环境用 -re
全称 --repl-env
. 默认情况下是浏览器, 所以这里需要指定是 node
:
clj -m cljs.main -re node
然后应该就启动了一个运行在 Node.js 上的 ClojureScript REPL.
ClojureScript 支持多种加载依赖的方式... 需要参考一下其他文档.
惯例 React 可以再 CLJSJS 项目当中找到一个处理过的可以直接引用的版本(注: 直接从 npm 引用更简单, 这个教程不涉及到). 总之这个例子从 CLJSJS 引用 React.
{:deps {org.clojure/clojurescript {:mvn/version "1.10.126"} cljsjs/react-dom {:mvn/version "16.2.0-3"}}}
我们来使用调用一下 react-dom
模块的代码
(ns hello-world.core (:require react-dom)) (.render js/ReactDOM (.createElement js/React "h2" nil "Hello, React!") (.getElementById js/document "app"))
运行一下浏览器环境:
clj -m cljs.main -c hello-world.core -r
然后你应该能看到一个页面渲染很大的 Hello react!
的文字了.