ClojureScript 1.10.x 新技能 cljs.main 快速开启

shxiao 2019-06-26

翻译自 https://github.com/clojure/cl...
遇到问题, 请用英文反馈至 https://clojureverse.org/t/cl...

内容:

  • ClojureScript 编译器
  • 生产环境编译
  • 在 Node.js 环境运行 ClojureScript

    • Node.js REPL
  • 依赖

这个版本基于 macOS 或者 Linux, 需要系统已经依赖 Clojure. Windows 用户请查看英文版.

ClojureScript 编译器

首先创建项目文件:

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 分别是 whitespacesimple.

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 环境运行 ClojureScript

Node.js 安装过程就不说了, 版本号总之别太低. SourceMaps 需要自己安装一下依赖:

npm install source-map-support

生成 Node 项目的话, 需要通过 -t 全称 --target 来指定目标. 默认的目标是浏览器, 其他目标还有 nashornrhino 这类的 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

跟前面浏览器的例子一样, 可以启动一个 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! 的文字了.

相关推荐