SkillAgentSearch skills...

Compassus

A routing library for Om Next.

Install / Use

/learn @compassus/Compassus
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

Compassus CircleCI

A routing library for Om Next.

Read the announcement blog post.

Contents

Installation

Leiningen dependency information:

[compassus "1.0.0-alpha3"]

Maven dependency information:

<dependency>
  <groupId>compassus</groupId>
  <artifactId>compassus</artifactId>
  <version>1.0.0-alpha3</version>
</dependency>

Template:

There is a Boot / Leiningen template that provides the minimum boilerplate to help you get started with a Compassus project.

Guide

To get started, require Compassus somewhere in your project.

(ns my-app.core
  (:require [om.next :as om :refer-macros [defui]]
            [compassus.core :as compassus]))

Declaring routes

Your application's routes are represented by a map of keywords (the route handlers of your application) to the respective Om Next component classes. The following example shows the routes for a simple application that has 2 routes, :index and :about:

(defui Index
  ...)

(defui About
  ...)

(def routes
  {:index Index
   :about About})

To specify the initial route of the application, use the :index-route configuration key in the Compassus application configuration map:

(def app
  (compassus/application
    ;; :index is the initial route of the application
    {:routes {:index Index
              :about About}}
     :index-route :index))

Routes can also be idents. Below is an example route definition that uses an ident as the route key.

(defui Item
  ...)

(defui ItemList
  ...)

{:items ItemList
 [:item/by-id 0] Item}

Assembling a Compassus application

Creating a Compassus application is done by calling the application function. This function accepts a configuration map that should contain your routes and an Om Next reconciler. Note that the parser must be constructed with compassus.core/parser. Here's an example:

(def app
  (compassus/application
    {:routes {:index Index
              :about About}
     :index-route :index
     :reconciler (om/reconciler
                   {:state {}
                    :parser (compassus/parser {:read read})})}))

Implementing the parser

The parser is a required parameter to an Om Next reconciler. As such, a Compassus application also needs to have one, with the added advantage that most of the plumbing has been done for you. The parser in a Compassus application will dispatch on the current route. Therefore, all that is required of a parser implementation is that it knows how to handle the routes that your application will transition to. An example is shown below with routes we have previously declared.

For convenience, the parser's env argument contains a :route key with the current route of the Compassus application.

;; we declared routes for `:index` and `:about`.
;; our parser should dispatch on those keys:

(defmulti read om/dispatch)

(defmethod read :index
  [env k params]
  {:value ...
   :remote ...})

(defmethod read :about
  [env k params]
  {:value ...
   :remote ...})

In some cases you may not want the parser to dispatch on your application's current route, but instead on the query that its component declares. This is optionally possible by passing an optional :route-dispatch key in the configuration map passed to compassus.core/parser. If set to false, the parser will not dispatch on the current route, but instead on the query of the component pertaining to that route. Here's an example:

(defui Home
  static om/IQuery
  (query [this]
    [{:menu (om/get-query Menu)}
     {:footer (om/get-query Footer)}])
  Object
  (render [this]
    ...))

(def app
  (compassus/application
    {:routes {:index Home}
     :index-route :index
     :reconciler (om/reconciler
                   {:state {}
                    :parser (compassus/parser {:read read
                                               :route-dispatch false))})}))

;; our parser won't dispatch on the `:index` key (the current route), but instead
;; on the `:menu` and `:footer` keys that are part of `Home`'s query:

(defmulti read om/dispatch)

(defmethod read :menu
  [env k params]
  {:value ...
   :remote ...})

(defmethod read :footer
  [env k params]
  {:value ...
   :remote ...})

Mixins

The configuration map you pass to compassus.core/application can also contain an optional :mixins key. Its value should be a vector of mixins. Mixins hook into the generated Compassus root component's functionality in order to extend its capabilities or change its behavior. The currently built-in mixin constructors are:

compassus.core/wrap-render:

Constructs a mixin that will wrap all the routes in the application. It becomes useful to specify this mixin whenever you want to define common presentation logic for all the routes in your Compassus application. wrap-render takes a function or an Om Next component class. The component class may or may not implement om.next/IQuery — a query that refers to data that you want to have available to the wrapper, e.g. the current logged in user and such.

The wrapper will be passed a map with the keys below. If the wrapper is a simple function, the map will be passed as argument. If it is a component class, the map will be in the component's computed props (accessible through om.next/get-computed). If the wrapper implements om.next/IQuery, its props will be the data that the query asks for.

  • :owner - the parent component instance
  • :factory - the component factory for the current route
  • :props - the props for the current route.

Note: There is only supposed to be one wrap-render mixin under the :mixins key. If there are more than one, Compassus will only use the first it finds.

Example:

;; Wrapper that doesn't implement `om.next/IQuery`
(defui Wrapper
  Object
  (render [this]
    ;; the wrapper doesn't implement `om.next/IQuery`, so the map is accessible
    ;; through `om.next/props`:
    (let [{:keys [owner factory props]} (om/props this)]
      ;; implement common presentation logic for all routes
      ;; call the given factory with props in the end
      (factory props))))

(def app
  (compassus/application
    {:routes ...
     :reconciler (om/reconciler ...)
     :mixins [(compassus/wrap-render Wrapper)]}))

;; Example of a wrapper that implements `om.next/IQuery`
(defui Wrapper
  static om/IQuery
  (query [this]
    [:current-user])
  Object
  (render [this]
    ;; `:current-user` will be in props, the other keys will be in computed props:
    (let [{:keys [current-user]} (om/props this)
          {:keys [owner factory props]} (om/get-computed this)]
      (dom/div nil
        ;; implement common presentation logic for all routes
        (dom/p nil (str "Current logged in user: " current-user))
        ;; call the given factory with props in the end
        (factory props)))))
compassus.core/will-mount:

Constructs a mixin that will hook into the componentWillMount lifecycle method of the generated root component. Takes a function which will receive the component as argument. Useful to perform any setup before the Compassus application mounts.

Example:

(compassus.core/will-mount
  (fn [self]
    ;; sets a property in the state of the root component
    (om/set-state! self {:foo 42})))
compassus.core/did-mount:

Constructs a mixin that will hook into the componentDidMount lifecycle method of the generated root component. Takes a function which will receive the component as argument. Useful to perform any setup after the Compassus application mounts.

Example:

(compassus.core/did-mount
  (fn [self]
    (start-analytics!)))
compassus.core/will-unmount:

Constructs a mixin that will hook into the componentWillUnmount lifecycle method of the generated root component. Takes a function which will receive the component as argument. Useful to perform any cleanup after the Compassus application unmounts.

Example:

(compassus.core/will-unmount
  (fn [self]
    (stop-analytics!)))

A note on mixins

Mixins are just data. Compassus built-in mixin constructors are just helpers around assembling this data. For example, building a mixin to hook into the Compassus root component's query could also be done as shown below:

(def app
  (compassus/application
    {:routes ...
     :reconciler (om/reconciler ...)
     :mixins [{:render MyWrapper}]}))

Utility functions

There are a few utility functions in compassus.core. Below is a description of these functions along with simple examples of their usage.

root-class

Return the Compassus application's root class.

(compassus/root-class app)
mount!

Mount a compassus application in the DOM.

(compassus/mount! app (js/document.getElementById "app"))
get-reconciler

Get the reconciler for the Compassus application.

(compassus/get-r
View on GitHub
GitHub Stars112
CategoryDevelopment
Updated1mo ago
Forks18

Languages

Clojure

Security Score

95/100

Audited on Mar 5, 2026

No findings