shoreleave
A smarter client-side in ClojureScript
###Shoreleave is a collection of integrated libraries that focuses on:
- Security
- Idiomatic interfaces
- Common client-side strategies
- HTML5 capabilities
- ClojureScript's advantages
Installing and using
You can pull all the pieces of Shoreleave into your project by adding the following to your project.clj
(defproject ...
:dependencies [[org.clojure/clojure "1.4.0"]
[shoreleave "0.3.0"]
[shoreleave/shoreleave-remote-ring "0.3.0"]
...
]
...
)
Individual utilies can be pulled in with [shoreleave/UTILITY "0.3.0"]
. See the specific repo/artifact names below.
Overview
Shoreleave has support for the following:
Common client-side interactions
- An idiomatic interface to cookies
- An idiomatic interface to browser history (with extended support for HTML5 History API)
- HTML Blob construction and on-demand asset building
- An idiomatic interface to browser storage (Local Storage, Session Storage. App Cache coming soon)
- Common auxiliary functions out-of-the-box to handle query strings, browser-repl, hash strings, and CLJS/JS interop
- and more...
A remotes package
Shoreleave's remotes package includes XHR, Pooled-XHR, JSONP, and HTTP-RPC capabilities.
CSRF protection is built in if your Clojure server is using the ring-anti-forgery middleware. See shoreleave-baseline for anti-forgery details.
The HTTP-RPC allows for exposing a server-side namespace as a client-side API, via a single server-side call, remote-ns
.
A typical Compojure setup might look like:
(ns baseline.handler
(:require [compojure.handler :as handler]
[baseline.routes :as routes]
[baseline.config :refer [config]]
[ring.middleware.gzip]
[ring.middleware.file-info]
[ring.middleware.anti-forgery]
[ring.middleware.session.cookie :refer [cookie-store]]
[shoreleave.middleware.rpc]
[hiccup.middleware]))
(def app routes/all-routes)
(defn get-handler [app]
(-> app
(shoreleave.middleware.rpc/wrap-rpc)
(ring.middleware.anti-forgery/wrap-anti-forgery)
(ring.middleware.gzip/wrap-gzip)
(handler/site {:session {:cookie-name "baseline"
:store (cookie-store {:key (config :session-secret)})
;:store (cookie-store)
:cookie-attrs {:max-age (config :session-max-age-seconds)
:http-only true}}})
(ring.middleware.file-info/wrap-file-info)
(hiccup.middleware/wrap-base-url)))
(def war-handler (get-handler app))
With a routes file that might look like this:
(ns baseline.routes
(:require [compojure.core :as c-core :refer [defroutes
GET POST PUT DELETE
HEAD OPTIONS PATCH
ANY]]
[compojure.route :as c-route]
[shoreleave.middleware.rpc :refer [remote-ns]]
;; Controllers
[baseline.controllers.site :as cont-site]
;; Public APIs
[baseline.controllers.api]))
;; Remote APIs exposed
;; -------------------
(remote-ns 'baseline.controllers.api :as "api")
;; Controller routes, ROA oriented
;; -------------------------------
(defroutes site
(GET "/" {session :session} (cont-site/index session))
(GET "/test" [] (cont-site/test-shoreleave)))
;; Core system routes
;; ------------------
(defroutes app-routes
(c-route/resources "/")
(c-route/not-found "404 Page not found."))
;; The top-level collection of all routes
;; --------------------------------------
(def all-routes (c-core/routes site
app-routes))
You can also define single "global" rpc functions:
(defremote ping []
(do
(println "Pinged by client!")
"PONG - from the server"))
See the full example in the shoreleave-baseline project
A pub/sub abstraction (and implementations)
Why would I ever want to use this?
Shoreleave's pub/sub system enables you to completely decouple parts of your app and declaratively bind them together. New features and functionalities can be built by composing pre-existing services/publishables.
Additionally you can express cross-cutting functionality (like logging or metrics reporting) as a service.
Reactive ClojureScript
This gives you the heart of Reactive JavaScript (RxJS), without the additional verbs (both a benefit and a tradeoff). It's often most beneficial to use DOM listeners as entry-points into the pub/sub system.
Shoreleave's pub/sub system is built upon two protocols: "brokers" and "publishables"
Out of the box, Shoreleave allows you to publish funtions, atoms, web workers, and anything that implements (str ...)/.toString, as topics.
The simple
pub/sub bus has very little overhead, but operates synchronously. You can trade-off some performance for an async bus, the event
pubsub bus.
(In-progress) The cross document bus has a small amount of overhead, but allows you to publish and subscribe from/to functions that live in other web workers or windows (in-browser concurrency for "free").
In most cases, the simple bus is the best choice.
Common external API support
Shoreleave has JSONP-wrapped support for external APIs including:
- Google Maps
- DuckDuckGo Zero-Click
- (Coming soon) Wikipedia and Alpha
An enhanced ClojureScript experience
- The ability to create embedded web workers
Where's the code?
There is a starter project that you can use as template, similar to how ClojureScript:One worked. It's also a great source to see how to build out Shoreleave+Compojure projects.
- shoreleave-baseline application - marg docs of the kitchensink branch
Shoreleave is a big project and has been split up into smaller pieces within the Shoreleave organization:
- shoreleave-core - Marg docs
- shoreleave-browser - Marg docs
- shoreleave-pubsub - Marg docs
- shoreleave-remote - Marg docs
- shoreleave-remote-ring - Marg docs
- shoreleave-services - Marg docs
Deprecated
- shoreleave-remote-noir - No published marg docs
- shoreleave-worker - Marg docs
What's new in the latest version?
The latest version is 0.3.0
- Example application and template project, shoreleave-baseline
- Finalized protocols and support for browser web storage (localStorage, sessionStorage)
- Ring middleware updated and moved to be the standard Shoreleave server-side component
- Dropped Noir support
- Updated remotes support for better error handling
- Improved pub/sub handling of various flow combinations
subscribe->
added the pub/sub bus procotol - allows threading of flows- Replaced deprecated CLJS protocol usage
- Code migrated from this project to CLJS proper
- removed jQuery support from remotes
- Updated all interfaces to their HTML5 finalized specs
- bug fixes and performance improvements
- Added more documentation
Plays well with others
Shoreleave makes no assumptions about other libraries you might be using in your app.
I have found it to pair particularly well with Enfocus
Examples and usage
Please the github doc pages (ie: Marginalia docs) above for library specifics.
There is a community-contributed demo app thanks to the hard work of Robert Stuttaford
Google Group and General Help
There is a Shoreleave CLJS Google Group. Please feel free to post all questions and general comments there.
Additionally, you can ping ohpauleez
in #clojure on Freenode.
License
Copyright (C) 2012-2013 Paul deGrandis
Distributed under the Eclipse Public License, the same as Clojure.