ClojureとJavascript、node.js、webフレームワークとの連携

ウェブ技術 デジタルトランスフォーメーション技術 人工知能技術 自然言語処理技術 セマンティックウェブ技術 深層学習技術 オンライン学習&強化学習技術 チャットボットと質疑応答技術 ユーザーインターフェース技術 知識情報処理技術 推論技術  プログラミング   ClojureJavascript

イントロダクション

Clojureは様々な言語と横断的につながるフレームワークを持っている。前回、機械学習の観点からPythonとClojureを連携するフレームワークについて述べ、それらを使って最新のpython機械学習ライブラリをClojure上ど動作させる実装について述べた。

システム的な観点から他の言語との連携について考えると、Clojureは元来Javaのプラットフォーム上で動くLispとして設計されており、現在でも多くのシステムで用いられているJavaのライブラリに対しては、ネィティブなJavaのライブラリを全て利用可能でかつ、JavaでもClojureのライブラリを利用できる。

近年システム構築する際にwebフレームワークは重要な位置を占めている。このwebフレームワークのフロントエンドの開発に用いられる言語としては、Javascript(あるいはそれらの派生言語であるAltJavascript)とそれらを使ったフレームワーク(React、View等)がデファクトとなっている。

Clojureには、それらJavascript/フレームワークとClojureの連携のフレームワーク(Clojurescript)が開発されており、今回はそれらについて述べたいと思う。さらに近年高速なJVMであるGraalVMを介してJavaとJavascriptの相互運用が可能となっており、それを介してClojureとJavascriptの連携も可能との記事もあるが今回は割愛する。

ClojureScript は、JavaScript をターゲットとした Clojure 用コンパイラとなる。他のAitJavascriptと同様に、Google Closure 最適化コンパイラを用いて、高度なコンパイルモードと互換性のある JavaScript コードを生成するフレームワークとなる。ClojureScriptは、JavaScriptプラットフォームのリーチ、Clojureの柔軟性とインタラクティブな開発、Google Closureのプログラム全体の最適化を組み合わせ、Webプログラミングのための最も強力な言語を提供するフレームワークとなる。

ClojurescriptでのHello World!

早速、具体的な実装について述べる。まずClojureの開発環境立ち上げに関しては以下のページを参照のこと。プロジェクトファイルとしては以下のものを作成する

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

これに対して”deps.edn”ファイルに対して、macOSあるいはLinuxでは以下の記述を行う

{:deps {org.clojure/clojurescript {:mvn/version "1.11.54"}}}

さらに”src/cljs_test01/core.cljs”ファイルに以下の記述を行う。

(ns cljs-test01.core)

(println "Hello world!")

これらをビルドして動作させるには、cljs-test01のディレクトリにて以下のコマンドをターミナルを使って入力する。

>clj -M --main cljs.main --compile cljs-test01.core --repl

Windowsの場合は以下を入力する。

>java -cp "cljs.jar;src" cljs.main --compile cljs-test01.core --repl

すべてに問題がなければ、自動でデフォルトのブラウザーが立ち上がり以下の画面が表示される。

またターミナルの画面に以下が表示される。

ClojureScript 1.11.54
cljs.user=> Hello world!

ここで使用したフラグをもう少し詳しく述べる。-mainはClojure関数、この場合はcljs.mainを呼び出す。cljs.main関数は、一般的なタスクを指定するための様々なコマンドライン引数をサポートしている。ここでは –compile を使って cljs-test01.core 名前空間をコンパイルするように指定している。これに続いて –repl を指定し、コンパイルが完了したらすぐに REPL を起動するように指定している。

ここで”src/cljs_test01/core.cljs”ファイルに以下の追加記入を行う。

(ns cljs-test01.core)

;(println "Hello world!")

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

ターミナルで以下のようにREPLを行なってみることができる。

cljs.user=> (require '[cljs_test01.core :as cljs] :reload)
nil
cljs.user=> (cljs/average 20 13)
16.5
cljs.user=>
Javascriptファイルのビルド

前述で作成したファイルを用いてビルドを行う

>clj -M -m cljs.main --optimizations advanced -c cljs-test01.core

Windowsでは以下を実行する。

>java -cp "cljs.jar;src" cljs.main --optimizations advanced -c cljs-test01.core

“cljs-test01″フォルダの中に”out”フォルダが生成され、その中に様々なファイル/フォルダが生成される。”out/main.js”を見てみるとファイルサイズは90K程度で以下のようにJavascriptのファイルにコンパイルされている。

f(typeof Math.imul == "undefined" || (Math.imul(0xffffffff,5) == 0)) {
    Math.imul = function (a, b) {
        var ah  = (a >>> 16) & 0xffff;
        var al = a & 0xffff;
        var bh  = (b >>> 16) & 0xffff;
        var bl = b & 0xffff;
        // the shift by 0 fixes the sign on the high part
        // the final |0 converts the unsigned value into a signed value
        return ((al * bl) + (((ah * bl + al * bh) << 16) >>> 0)|0);
    }
}


/*

 Copyright The Closure Library Authors.
 SPDX-License-Identifier: Apache-2.0
*/
            ;var f;function w(a){var b=typeof a;return"object"!=b?b:a?Array.isArray(a)?"array":b:"null"}var aa="closure_uid_"+(1E9*Math.random()>>>0),ba=0;function da(a){const b=[];let c=0;for(const d in a)b[c++]=d;return b};function fa(a){const b=a.length;if(0<b){const c=Array(b);for(let d=0;d<b;d++)c[d]=a[d];return c}return[]};function ha(a,b){null!=a&&this.append.apply(this,arguments)}f=ha.prototype;f.Pa="";f.set=function(a){this.Pa=""+a};f.append=function(a,b,c){this.Pa+=String(a);if(null!=b)for(let d=1;d<arguments.length;d++)this.Pa+=arguments[d];return this};f.clear=function(){this.Pa=""};f.toString=function(){return this.Pa};var ia={},ka={},la;if("undefined"===typeof ia||"undefined"===typeof ka||"undefined"===typeof A)var A={};if("undefined"===typeof ia||"undefined"===typeof ka||"undefined"===typeof ma)var ma=null;if("undefined"===typeof ia||"undefined"===typeof ka||"undefined"===typeof na)var na=null;var oa=!0,pa=null;if("undefined"===typeof ia||"undefined"===typeof ka||"undefined"===typeof ra)var ra=null;
function sa(){return new ta....

これに対して以下のようにテストを行うと

>clj -M -m cljs.main --serve

Windowsでは

>java -cp "cljs.jar;src" cljs.main --serve

ブラウザでlocalhost:9000にアクセスして、JavaScript Consoleを見てみるとHello World!が表示されていることが確認できる。

ClojurescriptをNode.jsで動かす

node環境の設定に関しては以下のページを参照のこと。まず環境設定のおまじないとして以下のコードを実行させる。

>npm install source-map-support

次にノードプロジェクトをビルドする。

>clj -M -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

Nodeを実行させる。

>node main.js
Hello World!
Reactとの連携

Reactを用いるには”deps.edn”ファイルに以下のライブラリ依存関係を追記する。

{:deps {org.clojure/clojurescript {:mvn/version "1.11.54"}
        cljsjs/react-dom {:mvn/version "16.2.0-3"}}}

さらに、”src/cljs_test01.core”ファイルを以下のように記述する。Reactの詳細は以下のページを参照のこと。

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

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

ビルドして動作させる。

clj -M -m cljs.main -c hello-world.core -r

ブラウザが自動で立ち上がり、以下の画面が表示される。(h2タグにHello React!が代入されたもの)

ターミナルを見ると、REPLの画面が表示されている。(必要なライブラリのダウンロードの後)

>clj -M -m cljs.main -c cljs-test01.core -r
Downloading: cljsjs/react-dom/16.2.0-3/react-dom-16.2.0-3.pom from clojars
Downloading: cljsjs/react/16.2.0-3/react-16.2.0-3.pom from clojars
Downloading: cljsjs/react/16.2.0-3/react-16.2.0-3.jar from clojars
Downloading: cljsjs/react-dom/16.2.0-3/react-dom-16.2.0-3.jar from clojars
ClojureScript 1.11.54
cljs.user=>

Clojurescriptのプロジェクトテンプレートとしては、leiningen用、boot用にそれぞれ様々なものが提供されている。

コメント

  1. […] ClojureとJavascriptやwebフレームワーク(node.js)との連携 […]

タイトルとURLをコピーしました