Skoro udało nam się przeportować RL-Engine do CLR to czemu nie zabrać się za JavaScript?
Ponownie, w teorii – wszystko co musimy zrobić to wziąć gotowy kod i przepuścić przez kompilator ClojureScript.
ClojureScript
Sam ClojureScript jest kompilatorem języka Clojure.
Tylko, że w inaczej niż w oryginale nie wypluwa kodu JVM tylko kod JavaScript.
Dodatkowo stara się nim pluć tak, aby wygenerowany Js był kompatybilny z Google Closure (Optymalizator).
Obecnie najnowszą wersją jest 1.8.51.
Kompilacja za pomocą ClojureScript
Tutaj będziemy musieli troszeczkę bardziej podłubać niż przy porcie do CLR.
Ominiemy sobie większość problemów z edytowaniem istniejącego projektu – stworzymy nowy.
lein new cljs-start rl-engine
Leiningen przygotuje nam podstawowy projekt ClojureScripta ze wszystkimi narzędziami jakie będą nam potrzebne.
Jedyne co poza tym potrzebujemy zrobić to pobrać PhantomJs.
PhantomJs jest “symulatorem” przeglądarki.
Symulatorem – ponieważ nie renderuje żadnego obrazu tylko umożliwia uruchamianie javascriptu w środowiskach bez-przeglądarkowych (np. konsola).
Ok, poza tym musimy dodać sobie naszego upiora do PATH. (inaczej leiningen nie będzie w stanie go znaleść)
Idąc dalej zaktualizujemy wszystkie zależności:
profiles.clj
:dev [:shared {:dependencies [[ring "1.4.0"] [compojure "1.5.0"] [enlive "1.1.6"]] :plugins [[com.cemerick/austin "0.1.6"]]
project.clj
:source-paths ["src/clj" "src/cljs" "src/cljc"] :dependencies [[org.clojure/clojure "1.8.0"] [org.clojure/clojurescript "1.8.51"]] :plugins [[lein-cljsbuild "1.1.3"]] {:builds {... {:source-paths ["src/cljc" "src/cljs"] ...}
W pliku projektu (project.clj) pierwszą, szczególnie ważną, zmianą jest upgrade samego clojure do wersji od 1.7 wzwyż.
W wersji 1.7 pojawił się bardzo wyczekiwany feature: Reader Conditionals
W dużym skrócie polega on na tym, że możliwe teraz jest definiowanie makr zależnie od platformy.
Np.:
#?(:clj Double/NaN :cljs js/NaN :default nil)
Zależnie od docelowej platformy dostaniemy różny wynik.
Przypomina to trochę komendy pre-procesora dla C++ czy C#.
Następnie musimy zmienić rozszerzenia plików z .clj na .cljc – czyli z originalnego clojure na clojure ze wsparciem reader conditionals.
RL-Engine w JavaScript
Teraz dodamy trochę kodu odpowiedzialnego za renderowanie lochów wygenerowanych przez nasz silnik:
(defn draw-dungeon [height width] (let [dungeon ((rl-engine.dungeon-generator/get-generator "bsp") height width) div (.getElementById js/document "dungeon")] (do (set! (.-innerHTML div) "") (.appendChild div (.createElement js/document "TABLE")) (let [table (.-firstChild div) build-cell (fn [content row-element] (let [cell (.appendChild row-element (.createElement js/document "TD"))] (set! (.-innerHTML cell) content))) build-row (fn [content] (let [row (.appendChild table (.createElement js/document "TR"))] (doall (map #(build-cell % row) content))))] (doall (map build-row dungeon)) nil))))
Pozostało nam tylko skompilować:
lein cljsbuild once
I odpalić w przeglądarce (index.html wygenerował nam template cljs-start w .\dev-resources\public)
Nice!
Wszystko ładnie śmiga.
Wymagało to trochę więcej roboty niż przy porcie do CLR – jednakże, efekt jak najbardziej opłacalny.
Bonus
ClojureScript sam w sobie jest już całkiem dojrzałą technologią i ma solidnie rozwinięty wachlarz narzędzi.
Od synchronizacji kodu źródłowego z przeglądarką, poprzez minifikacje, przekierowania po REPL z kontekstem przeglądarki.
Ale jedno z ciekawszych (chociaż działa tylko z Chrome) narzędzi, jakie mnie zaskoczyło, to mapowanie wygenerowanego kodu w Js na nasz kod w Clojure:
A po co nam takie mapowania?
A no dzięki nim możemy debugować nie kod JavaScriptowy tylko kod w Clojure!
Sweet…
Świetna robota ClojureScript Team!
Be First to Comment