ClojureScript クイックスタート (1.10.238 Release)


ClojureScript の[本家サイト](https://clojurescript.org/)にある [Quick Start](https://clojurescript.org/guides/quick-start) の記事をざっくりとまとめる。


1.10.238 Release 以前の古い記事は[こちら](https://qiita.com/snufkon/items/76bb0044da1437625a65#dependencies)
(だいぶ、短くなった)

**事前準備**

- macOS or Linux ユーザ
  - Web ブラウザ
  - [Clojure のインストール](https://clojure.org/guides/getting_started)
  
- Windows ユーザ
  - [Java 8](http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html)
  - [Standalone ClojureScript JAR の DL](https://github.com/clojure/clojurescript/releases/download/r1.10.238/cljs.jar)


## Hello, ClojureScript

このチュートリアルでは、単純な CloureScript のプロジェクトのコンパイルと実行、および REPL を実行し、インタラクティブにコードを開発、テストする方法について説明する。

まず、以下の構成のプロジェクトを作成する。ディレクトリ構造とアンダースコア(hello_world)は変更しないこと。


```sh
hello-world        # Our project folder
├─ src             # The CLJS source code for our project
│  └─ hello_world  # Our hello_world namespace folder
│     └─ core.cljs # Our main file
├─ cljs.jar        # (Windows only) The standalone Jar you downloaded earlier
└─ deps.edn        # (Mac/Linux only) A file for listing our dependencies
```

Mac or Linux ユーザは以下を記述した `deps.edn` を用意する。

```cljs:deps.edn
{:deps {org.clojure/clojurescript {:mvn/version "1.10.238"}}}
```

お好きなエディタで `src/hello_world/core.cljs` を以下のように編集する。

```core.cljs
(ns hello-world.core)

(println "Hello world!")
```

これで簡単なプログラムの完成。以下のコマンドでビルド＆実行してみましょう。

**Mac or Linux**

```sh
clj --main cljs.main --compile hello-world.core --repl
```

**Windows**

```sh
java -cp "cljs.jar;src" cljs.main --compile hello-world.core --repl
```

デフォルトのブラウザで以下のようなページが表示される。

![Browser](https://clojurescript.org/images/content/guides/quick-start/browser.png)

数秒後、ターミナルに "Hello world"が出力され、REPL のプロンプトが表示される。

REPL で以下の式が評価できることを確認。

```cljs
(inc 1)
(map inc [1 2 3])
(.getElementById js/document "app")
```

実行したコマンドを詳しく確認する。

`--main` は Clojure 関数を呼び出すためのフラグ。ここでは `cljs.main` 関数を呼び出している。`cljs.main` 関数はいくつかのタスクを行うコマンドをサポートしており、ここでは `--compile` で `hello-world.core` 名前空間のコンパイルを実行している。後に続く `--repl` フラグでコンパイル完了後、REPL を起動することを指定している。


`src/hello_world/core.cljs` を以下のように書き直してみましょう。

```cljs:core.cljs
(ns hello-world.core)

(println "Hello world!")

;; ADDED
(defn average [a b]
  (/ (+ a b) 2.0))
```

REPL プロンプトで以下を評価し、名前空間のリコンパイル＆リロードを行う。

```cljs
(require '[hello-world.core :as hello] :reload)
(hello/average 20 13)
```

結果として `16.5` が出力されるはず。

以下の式を評価し、わざとエラーを発生させてみましょう。

```cljs
(ffirst [1])
```

JavaScript ではなく、ClojureScript のソース位置を示すスタックトレースが出力され、デバッグを容易にしてくれます。


`cljs.main` で指定できるオプションは `--help` オプションで確認できる。

```sh
clj --main cljs.main --help
```

今まで使ったオプションの省略フラグ(`--main`の代わりに`-m`)が使えることが確認できる。

`--compile`, `--main`, `--repl`といったメインオプションは常に最後に記述する必要があることに注意する。


## Production Builds

コンパイルされた全ての JavaScript を含む `out` ディレクトリは約6.1MB ある。ClojureScript のコンパイラは Google Clojure Compiler に最適化された出力を生成する。Google Clojure Compiler では 最も重要な縮小化とデッドコードの削除を含む、多くの最適化が実行される。

`src/hello_world/core.cljs` を元に戻す。

```cljs:core.cljs
(ns hello-world.core)

(println "Hello world!")
```

`--optimizations` フラグに適切な値を設定することにより、リリース用のビルドを作成することができる。デフォルトの最適化レベルは `none` に設定されているがここでは、ClojureScript と Google Closure Compiler で提供されている全ての最適化を利用したいため、`advanced` を指定する。その他に `whitespace`, `simple` が `--optimizations` として指定することができる。

**Mac or Linux**

```
clj -m cljs.main --optimizations advanced -c hello-world.core
```

**Windows**

```
java -cp "cljs.jar;src" cljs.main --optimizations advanced -c hello-world.core
```

`advanced` コンパイルには時間がかかるため、開発中には使用しない。

`out/main.js` を調べるとファイルサイズは約90Kだとわかる。zip に圧縮すると 20Kほどになり、jQuery の依存関係よりもかなり小さいことがわかる。ただし、ClojureScript には ClojureScript standard library (10KLOC) と Google Closure Library (300KLOC) への暗黙的な依存がある。

`--serve` フラグにより、ビルドインされているシンプルなウェブサーバを起動し、`main.js` 動作を確認することができる。

**Mac or Linux**

```sh
clj -m cljs.main --serve
```

**Windows**

```sh
java -cp "cljs.jar;src" cljs.main --serve
```

このコマンドでは REPL が起動しないので、直接ブラウザで http://localhost:9000 にアクセスして動作を確認する。
`Hello world!`が出力されていることを、JavaScript のコンソールで確認することができる。


## Running ClojureScript on Node.js

まず、Node.js がインストールされていることを確認。インストールされていない場合は、[Node.js wiki](https://github.com/nodejs/node/blob/master/README.md)を参考にインストールする。

先に進む前に、source mapping を有効にする。

```sh
npm install source-map-support
```

`--target` オプションで特定の JavaScript をターゲットにしたコードを生成することができる。`--target`が指定されていない
場合、ブラウザ向けのコードが生成される。ここでは、出力されるファイル名を指定するため、`--output-to` オプションも利用している。

**Mac or Linux**

```
clj -m cljs.main --target node --output-to main.js -c hello-world.core
```

**Windows**

```
java -cp "cljs.jar;src" cljs.main --target node --output-to main.js -c hello-world.core
```

以下で、実行することができる。

```sh
node main.js
```

**Note**
最新の JavaScript エンジン (V8, SpiderMonkey and JavaScriptCore) の最適化が優れているため、Node.js では :advanced で最適化を行う理由はほとんどない。 :simple or :none の最適化で十分。


### Node.js REPL

`--repl-env` で JavaScript の評価環境を指定することができる。デフォルトでは、ブラウザ REPL が設定されている。

**Mac or Linux**

```
clj -m cljs.main --repl-env node
```

**Windows**

```
java -cp "cljs.jar;src" cljs.main --repl-env node
```

今までブラウザ REPL で試した式の評価は、Node.js でも正しく機能する。


## Dependencies

ClojureScript は ClojureScript と JavaScript の dependencies を扱う様々な方法がある。
詳しくは [Dependencies](https://clojurescript.org/reference/dependencies)を参照。

[React](https://reactjs.org/) は ClojureScript のプロジェクトで人気の dependency で、[cljsjs](http://cljsjs.github.io/) により [bundled version](https://github.com/cljsjs/packages/tree/master/react)が提供されている。この使用法を確認する。

`deps.edn` ファイルを修正する。

```cljs:deps.edn
{:deps {org.clojure/clojurescript {:mvn/version "1.10.238"}
        cljsjs/react-dom {:mvn/version "16.2.0-3"}}}
```

React が使われるように `src/hello_world/core.cljs` を修正する。

```cljs:core.cljs
(ns hello-world.core
  (:require react-dom))

(.render js/ReactDOM
  (.createElement js/React "h2" nil "Hello, React!")
  (.getElementById js/document "app"))
```

以下で、ビルド＆実行。

```sh
clj -m cljs.main -c hello-world.core -r
```

ブラウザで一瞬、デフォルトのページが表示されたあと、`h2`タグに `Hello React!` が記載されたページに置き換わることを確認することができる。