LispでWebやりてぇ

LispでWeb

ClojureScriptという選択

LispでWebがやりたいと思った際に、選択肢で候補に上がるのが下記の2つ

  • ClojureScript
  • Wisp

しかし、Wispの更新が止まっており(2015/12/13現在)、npmによるインストールが出来ない状態になっています。よってClojureScript一択になるかと思います

導入

さて導入ですが、結構面倒です。
基本的にここを参照してください。スケルトンもいただきましょう。

セットアップ

まずは、上記の参照先と同じ手順でプロジェクトのセットアップを行います。(詳しく書いてもいいけどコピペになるので元記事参照してね。)

プラグイン追加

ここから、ちょっと変更を加えていきます。leiningen環境でJavaScriptライブラリを操作したいので、lein-bowerを追加します。

  :plugins [[lein-cljsbuild "1.0.3"]
            [lein-bower "0.5.1"]] ; ここを追加

JavaScriptのライブラリを追加

leiningenとbowerの連携をとってライブラリの追加を行なっています。bowerに必要なファイルを教える為に下記のプロパティを追加します。
取り敢えずここでは、jQuery, enchant.js, three.jsを指定しています。

  :bower-dependencies [[jquery "2.1.4"]
                        [enchant.js "0.8.2"]
                        [three.js "https://github.com/mrdoob/three.js.git#r73"]
                        ]

bowerの設定追加

bower側の設定を追加します。

  :bower {:directory "public/lib"    ; DLしたライブラリの出力先
          :package-file "bower.json" ; パッケージ管理ファイル(bower.jsonという値はデフォルト値と同じです)
          :config-file ".bowerrc"}   ; bowerコンフィグファイル(.bowerrcという値はデフォルト値と同じです)

ライブラリのインストール

lein-bowerで設定したライブラリ群をインストールします。

lein bower install

設定ファイルの再生成

 ここでプロジェクトの再実行をしてみるとわかりますが、エラーで落ちます。原因はbower.jsonファイルがないからです。
 よくわかりませんが、lein-bowerは内部でbower.jsonと.bowerrcを管理しているらしく、コマンド実行後に対象ファイルがあると消すようになっているみたいです。
 今回はこのファイルが消えてしまうと、gulpで実行できなくなるので再生成します。簡単に再生成出来る様になっていないので、下記のスクリプトを作成しました。pythonを知らないとよくわからないと思いますが、概要てしては下記の様になります。

  • lein bower pprintコマンドでbower.json, .bowerrcの中身が表示されるので一時的にファイルにダンプ
  • 分離して、それぞれのファイルを作成

取り敢えず、これで再実行できると思いますので実行してみてください。

#!/usr/bin/env python
# coding: utf-8

u"""
gulp watch用にlein bower pprint結果をファイルに出力する
"""

import os
import json
import subprocess

DUMMY_FILE = "__dummy_bower_json__"

BOWER_JSON = "bower.json"
BOWER_CONFIG = ".bowerrc"

def main():
    subprocess.call("lein bower pprint > {0}".format(DUMMY_FILE), shell=True)
    bower_json = None
    bower_config = None
    with open(DUMMY_FILE) as fp:
        for i, line in enumerate(fp.readlines()):
            if i == 2:
                bower_json = json.loads(line)
            elif i == 6:
                bower_config = line
    with open(BOWER_JSON, "w") as fp:
        json.dump(bower_json, fp)
    with open(BOWER_CONFIG, "w") as fp:
        fp.write(bower_config)
    if os.path.exists(DUMMY_FILE):
        os.remove(DUMMY_FILE)
    print "Done"
    pass

if __name__ == '__main__':
    main()

コンパイル対象のプロジェクトを分離

DLしたそのままの設定であると、プロジェクト毎にコンパイル環境が分離していないので、分離方法を載せておきます。

:cljsbuild {
  ;; buildsの中身をリストからDestructuring Bindに変更
  :builds {
            ;; 今までのやつ(src/mainに移動する)
            :main {:source-paths ["src/main"]                      ; ここをsrc/mainディレクトリに変更
                  :compiler {:output-to "public/main.js"
                              :optimizations :whitespace
                              :pretty-print true}}
            ;; 新規追加したやつ(src/graygameを作成してその仲にソース群を作成)
            :graygame {:source-paths ["src/graygame"]
                      :compiler {:output-to "public/graygame.js"
                                  :optimizations :whitespace
                                  :pretty-print true}}
            }
  }

分離したプロジェクトの監視&コンパイルは下記コマンドによって行う。

# mainのみ
lein cljsbuild auto main
# graygameのみ
lein cljsbuild auto graygame
# main, graygameの両方
lein cljsbuild auto

コマンドまとめ

一応まとめておく

# bowerによるJavaScriptライブラリのインストール
lein bower install
# clojurescriptファイルの監視&コンパイル
lein cljsbuild auto ターゲットのプロジェクト名
# サーバ起動
gulp watch

参考になる資料群

文法
関数等のチートシート
プラクティス

最後に

 作ったプロジェクトはpublicフォルダ以下が全てなので、コレをgulp以外のサーバ起動フレームワークで実行する事も可能なはずです。私はgulpの使い方がさっぱりわからないので、別なやつにそのうち置き換えたいと思っています。
 今回ClojureScriptを触りましたが、当初は導入(特にleiningen回り)がよくわからなかったので、触るつもりはありませんでした。というのも元々Wispを導入までやってたので、Wispをやろうと最新版をインストールしようとした所、現状出来ない状態にあることがわかりましてClojureScriptになったという感じです。
 因みにWispがnpmでインストール出来ないのは、escodegenというライブラリの依存が解決出来ないからのようです。
 WispとClojureScriptの大きな違いとしては、吐出されるJavaScriptファイルの読みやすさに尽きると思います。ClojureScriptで吐いたファイルを見てもらうとわかりますが、20k行ぐらいあります。その殆どが環境用のコードで、実際のコードは一番したの方にある数十行だったりします。また、ClojureScriptの吐いたコードは決して人間にとって見やすい様には書かれていません。その点Wispは人間が見れるコードを吐いてくれるので良かったんですけどねぇ。

TODO 要検討項目

  • gulpの使い方
  • gulp以外の奴を検討
    • nw.jsとか?