An open API service indexing awesome lists of open source software.

https://github.com/funcool/bide

A simple routing library for ClojureScript
https://github.com/funcool/bide

clojurescript html5 html5-history routing

Last synced: 4 months ago
JSON representation

A simple routing library for ClojureScript

Awesome Lists containing this project

README

          

= bide
:sectlinks:

image:http://clojars.org/funcool/bide/latest-version.svg["Clojars Project", link="http://clojars.org/funcool/bide"]

== Introduction

A simple routing library for ClojureScript that uses Express-like syntax.

[quote, A Basque proverb.]
____
Egiak ez ditu bi bide
____

NOTE: **Looking for a maintainer.**

== Install

Add the following dependency to your `project.clj` file:

[source,clojure]
----
[funcool/bide "1.7.0"]
----

== User Guide

Just import the core namespace and start building the router:

[source, clojure]
----
(ns myapp.core
(:require [bide.core :as r]))

(def router
(r/router [["/api/auth" :myapp/auth]
["/api/users/:id" :myapp/user-by-id]]))
----

Now, you can perform basic operations such as `match` and `resolve`:

[source, clojure]
----
(r/match router "/api/auth")
;; => [:myapp/auth nil nil]

(r/match router "/api/users/1")
;; => [:myapp/user-by-id {:id "1"} nil]

(r/match router "/api/users/1?foobar=1")
;; => [:myapp/user-by-id {:id "1"} {:foobar "1"}]

(r/match router "/api/other")
;; => nil

(r/resolve router :myapp/auth)
;; => "/api/auth"

(r/resolve router :myapp/user-by-id {:id 2})
;; => "/api/users/2"

(r/resolve router :myapp/user-by-id {:id 2} {:foobar 1})
;; => "/api/users/2?foobar=1"
----

In addition, you can integrate it in your ClojureScript web application using
the provided builtin helpers. It uses `goog.History` API under the hood:

[source, clojure]
----
(defn on-navigate
"A function which will be called on each route change."
[name params query]
(println "Route change to: " name params query))

(r/start! router {:default :myapp/auth
:on-navigate on-navigate})
----

Also, you can pass factory function that returns instance of
`goog.history.Html5History` as value of `:html5history` key of second argument
and `bide` would use it to manage history events, and/or pass `true` as value of
`:html5?` key to stop using '#' in URLs.

Note that when `:html5?` is `true`, the built-in instance of `Html5History` uses
a custom `goog.history.Html5History.TokenTransformer` to allow it to handle
query parameters. You can construct a transformer with `token-transformer`.

Finally, you can force the navigation trigger by using the `navigate!` helper
function:

[source, clojure]
----
(r/navigate! router :myapp/user-by-id {:id 10})
----

Or if you don't want to add entry into history use `replace!` helper function
instead.

== How to Contribute?

Just open an issue or PR ;)

== FAQ

=== Why another routing library?

Existing solutions out there are complex and generally bloated wih irrelevant
documentation.

Most libraries work with native Clojure data structures for representing the
routing configuration. It's a great idea, but it does not work very well once
your project scales. Things get out of hand pretty fast.

An example of this with link:https://github.com/juxt/bidi[bidi] routing library:

[source, clojure]
----
(def routes
["/" [["auth/login" :auth/login]
[["auth/recovery/token/" :token] :auth/recovery]
["workspace/" [[[:project-uuid "/" :page-uuid] :workspace/page]]]]])
----

The mental effort required to read and understand the configuration defined like this
is considerable. Now, let's see an example using *bide*:

[source, clojure]
----
(def routes
[["/auth/login" :auth/login]
["/auth/recovery/token/:token" :auth/recovery]
["/workspace/:project-uuid/:page-uuid" :workspace/page]])
----

As you can imagine, a simple library like *bide* does not offer all the features
provided by other solutions. New features will be added on-demand. However, we plan
to stay as *small and simple* as possible.

== How fast is *bide*?

Before talking about real performance comparisons and benchmarks, you
should know that *bide* design is very simple and maybe can be considered
naive. The worst case for the matching algorithm is *O(N)* and *O(1)*
for resolve operation.

Considering that having thousands of entries is very unlikely to happen,
the match algorithm works pretty well. This is a comparison against the
same operations with link:https://github.com/juxt/bidi[bidi]:

[source, text]
----
$ node out/benchmarks.js
op=resolve lib=bidi ops=10000
"Elapsed time: 90.989215 msecs"
op=resolve lib=bide ops=10000
"Elapsed time: 19.447844 msecs"
op=match lib=bidi ops=10000
"Elapsed time: 1070.330668 msecs"
op=match lib=bide ops=10000
"Elapsed time: 98.864120 msecs"
----

I've been a _bidi_ user for quite some time, that's why I choose this library to
run the benchmarks.

== License

_bide_ is licensed under BSD (2-Clause) license.