ClojureScript in Legacy Anwendungen

Von Andreas Steffan / @deas

Ausgangssituation

  • Mein erstes ClojureScript Projekt
  • Maven basierte Webapplikation (Alfresco Share)
  • Browserseitiges JavaScript ist unter Kontrolle von AMD (Asychronous Module Definition). Insbesondere auch Build.
  • Vorwiegend Dojo* und YUI
  • Wenig AngularJS Erfahrung, 0 ClojureScript

Legacy Alltag

Pimp my App #1 : AngularJS

AngularJS - nacher ...

..., weil

  • AngularJS ist ein invasives Framwork
  • Es kann nur eins (Framework) geben
  • Es gibt kein "bischen" AngularJS

Pimp my App #2 : ClojureScript

AMD "Integration"

Lifecyle und Dependency Injection


   (defn ^:export init []
  "AMD Glue"
  (let [postcreate (fn []
                     (this-as
                      this
                      (.log js/console "postcreate")
                      (reagent/render-component [todo-app] (.getElementById js/document (.-id this)))))
        dfn (fn []
              (js/define (array "dojo/_base/declare",  "dijit/_WidgetBase", "cr-react/ReactInit")
                (fn [declare WidgetBase React]
                  (declare (array WidgetBase)
                           (js-obj "postCreate" postcreate)))))]
    (->> dfn
         (js-obj "contentreich/sandbox/todomvc")
         (js-obj "cache")
         js/require)))

Maven "Integration"

(lein-npm und lein bower gibt es auch)


    
        org.codehaus.mojo
        exec-maven-plugin
        1.3.2
        
            lein
            
                cljsbuild
                once
            
        
        
            
                generate-resources
                
                    exec
                
            
        
    

Leiningen vs. NPM & Co unter maven

  • Leiningen kein großer Gewinn weil beide Ansätze exec Plugin nutzen
  • Leiningen erspart einem den node.js Stack ;)
  • Obacht, falls auch Web(jar) Assets aus maven genutzt werden (Konflikte!)

Leiningen

project.clj


    :dependencies [[org.clojure/clojure "1.6.0"]
                 [org.clojure/clojurescript "0.0-3115"]
                 [com.cognitect/transit-cljs "0.8.205"]
                 ;; https://github.com/reagent-project/reagent/issues/109
                 ;; reagent-0.5.0 does not work for me today
                 [reagent "0.5.0-alpha"]
                 ;; [cljsjs/react "0.13.0-0"]
                 [reagent-forms "0.4.3"]
                 [reagent-utils "0.1.2"]
                 [secretary "1.2.1"]
                 [weasel "0.6.0"]
                 [figwheel "0.2.5"]
                 [cljs-tooling "0.1.4"]
                 [environ "1.0.0"]
                 [enlive "1.1.4"]]

Emacs + Cider

Bedarf vermutlich keiner Vorstellung ;)

Cursive geht inzwischen sicher auch ganz gut.

Figwheel

Auto all the things!

  • Autobuild und incrementelle Code Updates in Browsern (alle!, kein Page Reload!), auch vanilla JavaScript und CSS
  • Code sollte "reloadable" designed sein. Obacht mit Zustand!
  • REPL bekommt Code Änderungen mit
  • Spielt auch mit node.js
  • Ich hoffe es spielt in Zukunft besser mit Cider. Der @bhaumann hat da so eine Anspielung gemacht.

Figwheel REPL


    Launching ClojureScript REPL for build: dev
Figwheel Controls:
          (stop-autobuild)                ;; stops Figwheel autobuilder
          (start-autobuild [id ...])      ;; starts autobuilder focused on optional ids
          (switch-to-build id ...)        ;; switches autobuilder to different build
          (reset-autobuild)               ;; stops, cleans, and starts autobuilder
          (build-once [id ...])           ;; builds source one time
          (clean-builds [id ..])          ;; deletes compiled cljs target files
          (fig-status)                    ;; displays current state of system
          (add-dep [org.om/om "0.8.1"]) ;; add a dependency. very experimental
  Switch REPL build focus:
          :cljs/quit                      ;; allows you to switch REPL to another build
    Docs: (doc function-name-here)
    Exit: Control+C or :cljs/quit
 Results: Stored in vars *1, *2, *3, *e holds last exception object
Prompt will show when figwheel connects to your application
To quit, type: :cljs/quit
ClojureScript:cljs.user>

REPL++

Piggieback & Weasel


(do (require '[weasel.repl.websocket :as ws]
             '[cemerick.piggieback :as pb])
    (pb/cljs-repl :repl-env (ws/repl-env :port 9000)))
                    
  • Piggieback: nREPL middleware that enables the bootstrap of a ClojureScript REPL on top of an nREPL session.
  • Weasel: nREPL transport über WebSockets (iframe Alternative austin hat Issues).

Reagent

A minimalistic ClojureScript interface to React.js


(def click-count (atom 0))

(defn state-ful-with-atom []
  [:div {:on-click #(swap! click-count inc)}
   "I have been clicked " @click-count " times."])

(defn render-simple []
  (reagent/render-component [state-ful-with-atom] (.-body js/document)))
                    
  • Hiccup like Syntax. Keine extra Files/Sprache für Präsentations-Templates!
  • Komponenten die (Reagent-) Atom nutzen werden bei Änderung automatisch neu darstellt (-> Copy/Paste)

Übrigens ...

Neu seit ClojureScript 0.0-3058

  • REPL support für :reload, :reload-all, doc, source, find-doc, apropos, dir, and pst are all there
  • Schnellere Übersetzung
  • Auf Java 8 auch ohne Leiningen

Außerdem ...

Closure Modules


{ :modules {:foo {:output-to "out/foo.js"
                  :entries #{hello-world.foo}}
            :bar {:output-to "out/bar.js"
                  :entries #{hello-world.bar}}}}
                    

Erlaubt es Anwendungen aufzuspalten. Hier in Module hallo-world.foo, hallo-world.bar und einen (impliziten) shared Teil.

Was unklar blieb ;)

  • Cider Autocomplete. Im Video ging das irgendwie. :) Eigentlich ist cljs-tooling ist Basis für cider-nrepl Quellcode Navigation und Autovervollständigung.

Danke!

Und überhaupt JVM Legacy ...

  • Spring?
  • JEE?
  • Gradle?