Clojure

開発起動時間の改善

ご存知でしたか?

  • ほとんどのライブラリはソースとして配布され、何度もコンパイルされます

  • compileを使って、名前空間を明示的にコンパイルできます

  • 名前空間のコンパイルは推移的です

  • compileはこれらのファイルをディスクに書き込み、requireはそれらを使用します

  • 開発開始時にロードする名前空間、またはuser.clj、またはサーバーとして実行するメインの名前空間に対してcompileを使用すると、起動時間を改善できます

compile関数は、名前空間のシンボルを受け取り、その名前空間と、それがrequireしているすべての名前空間を*compile-path*(デフォルトはclasses)にコンパイルします。そのディレクトリは存在し、クラスパスにある必要があります

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

その後、それらのコンパイル済み名前空間のいずれかがrequireされると、元の.cljファイルではなく、クラスファイルがロードされます。ソースファイルが更新された(つまり新しい)場合、代わりにロードされます。新しい依存関係やコードの変更に対応するには、定期的に再コンパイルする必要があります。

コンパイルはロードの副作用であるため、すでにロードされている名前空間には影響しないことに注意してください。特に、Clojureランタイムによって自動的にロードされるuser.cljファイルは特殊なケースです。開発でuser.cljを使用している(またはすでにコンパイルされている名前空間をコンパイルする必要がある)場合は、コンパイル中に強制的にリロードすることで実行できます

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

以上です!この手法は、特にロードする依存関係の数が増えるにつれて、開発中の起動時間を大幅に短縮できます。

開発用にエイリアスを使用する

deps.ednプロジェクトでは、classesディレクトリを含む開発エイリアス(:devなど)を作成する必要があります

{: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))

オリジナル著者:アレックス・ミラー