A simple routing library for ClojureScript that uses Express-like syntax.
Egiak ez ditu bi bide
Add the following dependency to your project.clj
file:
[funcool/bide "1.6.0"]
Just import the core namespace and start building the router:
(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
:
(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:
(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:
(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.
Just open an issue or PR ;)
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 bidi routing library:
(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:
(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.
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 bidi:
$ 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.
bide is licensed under BSD (2-Clause) license.