Skip to content
metametadataPublic

About

ClojureScript application framework.

Topics

Resources

Stars

148 stars

Watchers

10 watching

Forks

Latest commit

 

History

602 Commits

Folders and files

Repository files navigation

Carry

ClojureScript single-page application framework inspired by re-frame, Elm Architecture, Redux and Cerebral.

Carry provides a structure for making GUI application code easier to modify, debug, test and be worked on by multiple programmers.

The core of the framework is a simple state management library. UI bindings, routing, debugger, etc. are implemented as separate optional packages.

Clojars Project Gitter Slack

Status

Stable. Was used in production.

I now focus on the successor Aide framework instead.

Features

Pattern

Carry enforces:

  • Separation of presentation code.
  • Events as first-class citizens.
  • Splitting event handling code into side-effectful and "pure" model updating phases.
  • Storing model in a single observable atom.

It also advises to decouple view and view model code in the presentation layer:

pattern

  • An app is defined by its initial model value, signal handler and action handler.
  • All app state is stored inside a single model atom.
  • Anyone can read model value at any given time and subscribe to its changes.
  • Signal handler performs side effects and dispatches actions.
  • Anyone can dispatch a new signal: signal handler, views, timers, etc.
  • Typically UI layer dispatches signals on UI events and subscribes to model changes to redraw the GUI when needed.
  • Model can be modified only by dispatching actions.
  • Only signal handler can dispatch actions.
  • Action handler is a pure function which returns a new model value based on an incoming action.

Example (counter app)

Demo, Source code

HTML:

<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Carry • Counter</title>
    <link rel="icon" href="data:;base64,iVBORw0KGgo=">
</head>
<body>
    <div id="root"></div>
    <script src="js/compiled/frontend.js" type="text/javascript"></script>
</body>
</html>

Main file:

(ns app.core
  (:require [counter.core :as counter]
            [carry.core :as carry]
            [carry-reagent.core :as carry-reagent]
            [reagent.core :as r]))

(let [app (carry/app counter/blueprint)
      [_ app-view] (carry-reagent/connect app counter/view-model counter/view)]
    (r/render app-view (.getElementById js/document "root"))
    ((:dispatch-signal app) :on-start))

UI (using Reagent and carry-reagent):

(ns counter.core
  (:require [cljs.core.match :refer-macros [match]]
            [reagent.ratom :refer [reaction]]))

(defn view-model
  [model]
  {:counter (reaction (str "#" (:val @model)))})

(defn view
  [{:keys [counter] :as _view-model} dispatch]
  [:p
   @counter " "
   [:button {:on-click #(dispatch :on-increment)} "+"] " "
   [:button {:on-click #(dispatch :on-decrement)} "-"] " "
   [:button {:on-click #(dispatch :on-increment-if-odd)} "Increment if odd"] " "
   [:button {:on-click #(dispatch :on-increment-async)} "Increment async"]])

Blueprint:

(def -initial-model {:val 0})

(defn -on-signal
  [model signal _dispatch-signal dispatch-action]
  (match signal
         :on-start nil
         :on-stop nil

         :on-increment
         (dispatch-action :increment)

         :on-decrement
         (dispatch-action :decrement)

         :on-increment-if-odd
         (when (odd? (:val @model))
           (dispatch-action :increment))

         :on-increment-async
         (.setTimeout js/window #(dispatch-action :increment) 1000)))

(defn -on-action
  [model action]
  (match action
         :increment (update model :val inc)
         :decrement (update model :val dec)))

(def blueprint {:initial-model -initial-model
                :on-signal     -on-signal
                :on-action     -on-action})

Packages

UI Bindings

Middleware

Documentation

More information can be found at the project site:

License

Copyright © 2016 Yuri Govorushchenko.

Released under an MIT license.

About

ClojureScript application framework.

Topics

Resources

Stars

148 stars

Watchers

10 watching

Forks

Releases

Packages

Contributors

Languages