やろーじだい

ブログと技術メモです。なにかあればより詳細に書こうということで最初は雑に書くようにしています。質問・要望等あれば Twitter かコメントに下さい。

ClojureScript: :optimizations :advanced で外部ライブラリを用いた時に起こる問題への対処

問題

外部ライブラリを用いて以下のように ClojureScript で実行する場合に

(-> (js/LibHoge. args))
    (.run)

ClojureScript の build の config で :optimizations :advanced にした時に以下のようなエラーが発生する。

TypeError: (intermediate value).Kc is not a function
    at Object.pl ((index):676)
    at Object.<anonymous> ((index):632)
    at Object.componentDidMount ((index):43)
    at commitLifeCycles ((index):197)
    at B ((index):220)
    at A ((index):218)
    at t ((index):217)
    at x ((index):216)
    at y ((index):215)
    at D ((index):214)

これは .run という関数が、 ClojureScript のコンパイル時の外部ライブラリとの名前解決がうまくいかず .Kc という名前に単独で置き換わってしまうことで起こっていた。 解決策がわからず長いこと苦しんだ。

解決策

この記事 Using JavaScript libraries in ClojureScriptReferencing a library outside your compilation で言われている通りのことをすることで解決した。

まず以下の用に html の head 部分等にライブラリを埋め込む。(以下は ClojureScript での例)

[:script {:type "text/javascript" :src "/path/to/Lib.js"}]

更に project.clj の ClojureScript の :optimizations :advanced にしている設定に :externs でライブラリへのパスを通す。

:compiler {:main "..."
           :output-to "..."
           ...
           :optimizations :advanced
           :externs ["/path/to/Lib.js"]}

これらを行った上で ClojureScript のコンパイルを行うと、

WARNING - name define is not defined in the externs.

 WARNING - accessing name window in externs has no effect. Perhaps you forgot to add a var keyword?

といったかなりの量の警告を出されるが、最終的にはうまく言っている。多分 header に挿入した部分を見た時に WARNING が出て、それを解決するために externs 宣言の方の設定が利用されているようだが、あまりよくわかってない。