(require '[cljs.build.api :as b])
(b/build "src"
{:output-dir "out"
:output-to "out/main.js"
:optimizations :none
:main 'example.core
:install-deps true
:npm-deps {:react "15.6.1"
:react-dom "15.6.1"}})
2017 年 7 月 12 日
António Nuno Monteiro
2015 年 Google 暑期代码项目为 ClojureScript 成功地使与外部 JavaScript 模块的交互变得更容易。依赖于 Google Closure Compiler 当时新推出的理解大多数知名 JavaScript 模块格式并将其转换为 Closure 兼容 JavaScript 的功能 [2],Maria Geller 成功地将这些模块功能集成到 ClojureScript 中,以及 自定义预处理 步骤,允许使用诸如流行的 JavaScript 编译技术 Babel 等功能,轻松地在你的 ClojureScript 项目中使用 [3]。
从那时起,Closure Compiler 团队在 2016 年添加了模块解析支持,这在其他方面使能够直接从node_modules
安装中使用模块,而无需为 Closure 提供手工制作的模块路径以进行转换。
我们在 Maria 的模块工作基础上进行了构建,以解决这一新的 Closure 功能,ClojureScript 的下一个版本代表着另一个重要里程碑,它通过对 ClojureScript 如何与 NPM 生态系统交互的方式进行重大改进,使任意 JavaScript 模块对每个 ClojureScript 项目都可用。
从 ClojureScript 命名空间中获取 NPM 模块 自 ClojureScript 1.9.518 版本以来就已成为可能。但是,Node.js 支持多种模式来获取 CommonJS 模块,一个常见的问题是人们想要从 ClojureScript 中获取 "react-dom/server"
形式的模块,这对于:require
规范来说将不是一个有效的符号。
在此版本中,我们在命名空间形式中添加了对基于字符串的获取的支持,以解决上述问题。你现在可以从你的 ns
声明中轻松地获取这些类型的模块。
将这一切整合在一起的是:npm-deps
编译器标志。在其中,我们告诉编译器它应该知道哪些依赖项。ClojureScript 将负责安装这些依赖项并运行它们以通过 Closure Compiler 转换管道,包括我们在下面更详细地描述的优化。
给定一个如下所示的 build.clj
文件
(require '[cljs.build.api :as b])
(b/build "src"
{:output-dir "out"
:output-to "out/main.js"
:optimizations :none
:main 'example.core
:install-deps true
:npm-deps {:react "15.6.1"
:react-dom "15.6.1"}})
你最简单的 src/example/core.cljs
文件可能如下所示
(ns example.core
(:require [react :refer [createElement]]
["react-dom/server" :as ReactDOMServer :refer [renderToString]]))
(js/console.log (renderToString (createElement "div" nil "Hello World!")))
请注意,我们不必在任何地方声明 "react-dom/server"
。我们可以直接获取它。ClojureScript 现在足够智能,可以找到这些 CommonJS 模块并将它们处理成 Google Closure Compiler 兼容的代码。
使用 Google Closure 来使用 JavaScript 模块的影响是巨大的:ClojureScript 项目中使用的外部库不再只是追加到生成的包中,现在可以应用所有 Closure Compiler 的优化,包括死代码消除,以及在利用 代码拆分 的项目中跨模块代码移动。例如,在我们的测试中,React 在 Closure 的高级编译下比使用现有的流行 JavaScript 工具要小很多(大约 16%)[4]。此外,如果你有一个混合的 ClojureScript 和 JavaScript 代码库,你不仅可以现在无缝地使用代码的那些 JavaScript 部分(包括例如 JSX 转换!),还可以共享并将其供应商依赖项与 ClojureScript 部分使用的依赖项打包在一起。