Clojure

提升开发启动时间

你知道吗

  • 大多数库都以源代码形式发布,你需要反复编译它们

  • 你可以使用 compile 显式编译命名空间

  • 命名空间编译是可传递的

  • compile 会将这些文件写入磁盘,require 将使用它们

  • 你可以使用 compile 编译你在开始开发时加载的命名空间,或者编译你的 user.clj,或者编译你作为服务器运行的主要命名空间,从而提升启动时间

compile 函数接受一个命名空间符号,并将该命名空间及其所有依赖项编译到 *compile-path*(默认值为 classes)。该目录必须存在,并且必须在你的类路径中

(compile 'my.namespace)    ;; writes .class files to *compile-path*

之后,当任何这些已编译的命名空间被要求时,将会加载类文件,而不是原始的 .clj 文件。如果源文件更新(因此更新),则会改为加载源文件。你需要定期重新编译,以应对新的依赖项或代码更改。

请注意,编译是加载的副作用,因此对已加载的命名空间没有影响。特别是一个特殊情况是 user.clj 文件,该文件由 Clojure 运行时自动加载。如果你在开发中使用 user.clj(或需要编译已经编译的命名空间),你可以通过在编译时强制重新加载来做到这一点

(binding [*compile-files* true] ;; compile during load
  (require 'user :reload-all))  ;; reload this and all transitively loaded namespaces

就是这样!这种技巧可以显着缩短开发过程中的启动时间,尤其是在加载的依赖项数量增加时。

使用别名进行开发

在 deps.edn 项目中,你应该创建一个开发别名(例如 :dev),其中包含 classes 目录

{:deps { ... }
 :aliases
 {:dev {:extra-paths ["classes"]}}}

你还需要确保 classes 目录存在。将空的 classes 目录作为版本控制项目结构的一部分可能很有用(确保忽略并不要包含已编译的 .class 文件)。

然后,你可以使用别名启动 REPL 并使用 compile 来填充 classes 目录,并开始看到好处

$ clj -A:dev
Clojure 1.10.1
user=> (compile 'my.namespace)

将 user.clj 纳入你的开发别名

如果你想使用自动加载的 user.clj,你应该通过添加源路径 dev 来将其纳入你的开发别名

{:deps { ... }
 :aliases
 {:dev {:extra-paths ["dev" "classes"]}}}

然后创建 dev/user.clj

(ns user
  (:require ... ))

;; dev-only functions, etc

记住对 user.clj 使用修改后的编译过程

$ clj -A:dev
Clojure 1.10.1
user=> (binding [*compile-files* true] (require 'user :reload-all))

原始作者:Alex Miller