Skip to content

Commit 7341821

Browse files
authored
Refactor to prepare for release (#14)
1 parent ceabafa commit 7341821

File tree

15 files changed

+1949
-677
lines changed

15 files changed

+1949
-677
lines changed

.github/workflows/ci.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@ jobs:
88
steps:
99
- uses: actions/checkout@v2
1010

11-
- uses: actions/setup-node@v1
11+
- uses: actions/setup-node@v3
1212

1313
- uses: thomashoneyman/setup-purescript@main
1414
with:
15-
purescript: "0.14.0"
16-
spago: "0.19.1"
15+
purescript: "0.15.4"
16+
spago: "0.20.9"
1717

1818
- name: Cache PureScript dependencies
1919
uses: actions/cache@v2

.vscode/settings.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
"purescript.addNpmPath": true,
33
"purescript.addPscPackageSources": true,
44
"purescript.addSpagoSources": true,
5-
"purescript.editorMode": true,
65
"purescript.buildCommand": "spago build -- --json-errors",
6+
"purescript.formatter": "purs-tidy",
77
"[purescript]": {
88
"editor.formatOnSave": true
99
}

README.md

Lines changed: 143 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,148 @@
11
# purescript-web-router
22

3-
A basic pushstate router for React with support for asynchronous routing logic, built using [react-basic-hooks](https://github.com/spicydonuts/purescript-react-basic-hooks). I recommend [routing-duplex](https://github.com/natefaubion/purescript-routing-duplex) for easy parsing and printing.
4-
5-
For a basic example see [here](https://github.com/robertdp/purescript-web-router-example/tree/master/src).
6-
7-
## How to use with Spago
8-
9-
Add `web-router` to your `packages.dhall`:
10-
11-
```dhall
12-
let additions =
13-
{ web-router =
14-
{ dependencies =
15-
[ "aff"
16-
, "effect"
17-
, "freet"
18-
, "indexed-monad"
19-
, "prelude"
20-
, "profunctor-lenses"
21-
, "routing"
22-
]
23-
, repo = "https://github.com/robertdp/purescript-web-router.git"
24-
, version = "v0.3.0"
3+
A router for browsers that supports asynchronous routing logic. Bring your own printing and parsing (check out [routing-duplex](https://github.com/natefaubion/purescript-routing-duplex)).
4+
5+
For a basic React example see [here](https://github.com/robertdp/purescript-web-router-example/tree/master/src).
6+
7+
## How to use
8+
9+
### 1. Install with Spago
10+
11+
`$ spago install web-router` (coming soon)
12+
13+
### 2. Define your routes
14+
15+
```purescript
16+
data Route
17+
= Page Page
18+
| NotFound
19+
20+
data Page
21+
= Home
22+
| ProductList
23+
| ProductView ProductId
24+
| About
25+
| ContactUs
26+
27+
type ProductId = Int
28+
```
29+
30+
### 3. Implement parsing and printing
31+
32+
This example uses [routing-duplex](https://github.com/natefaubion/purescript-routing-duplex).
33+
34+
<details>
35+
<summary>Imports</summary>
36+
37+
```purescript
38+
import Prelude hiding ((/))
39+
import Data.Either (Either)
40+
import Data.Generic.Rep (class Generic)
41+
import Routing.Duplex (RouteDuplex', default, end, int, parse, print, root, segment)
42+
import Routing.Duplex.Generic (noArgs, sum)
43+
import Routing.Duplex.Generic.Syntax ((/))
44+
import Routing.Duplex.Parser (RouteError)
45+
```
46+
47+
</details>
48+
49+
```purescript
50+
derive instance Generic Route _
51+
derive instance Generic Page _
52+
53+
productId :: RouteDuplex' ProductId
54+
productId = int segment
55+
56+
routes :: RouteDuplex' Route
57+
routes =
58+
default NotFound $
59+
sum
60+
{ "Page": pages
61+
, "NotFound": "404" / noArgs
62+
}
63+
64+
pages :: RouteDuplex' Page
65+
pages =
66+
root $ end $
67+
sum
68+
{ "Home": noArgs
69+
, "ProductList": "products" / noArgs
70+
, "ProductView": "products" / productId
71+
, "About": "about" / noArgs
72+
, "ContactUs": "about" / noArgs
2573
}
26-
}
74+
75+
-- | This is route parser we need to pass to the driver.
76+
-- | It can produce any route which allows the parser to return a value of `NotFound` instead of failing.
77+
parseRoute :: forall String -> Either RouteError Route
78+
parseRoute = parse routes
79+
80+
-- | This is the route printer we need to pass to the driver.
81+
-- | It can only print paths to valid pages, which means a path can't be produced for the `NotFound` route.
82+
-- | With this approach routes can be seperated based on whether they should be a navigation target and have a URL.
83+
-- | Note: assymetry is not required, and a symmetrical printer works as well.
84+
printRoute :: Page -> String
85+
printRoute = print pages
86+
```
87+
88+
### Define how your application reacts to navigation and routing events
89+
90+
<details>
91+
<summary>Imports</summary>
92+
93+
```purescript
94+
import Web.Router as Router
95+
```
96+
97+
</details>
98+
99+
```purescript
100+
onNavigation :: Maybe Route -> Route -> Router.RouterM Route Page Router.Routing Router.Resolved Unit
101+
onNavigation previousRoute requestedRoute =
102+
case requestedRoute of
103+
NotFound ->
104+
case previousRoute of
105+
Just (Page page) -> Router.do
106+
liftEffect showBrokenNavigationMessage
107+
Router.redirect page -- redirect back to the previous page and show a message
108+
_ ->
109+
Router.continue -- no previous page, so just show the "not found" page
110+
_ -> Router.do
111+
access <- liftAff fetchUserAccess
112+
if userHasAccess requestedRoute access then
113+
Router.continue -- they have access, so resolve with the requested page
114+
else
115+
Router.override NotFound -- no access, so pretend the page doesn't exist
116+
117+
118+
onEvent :: Router.RoutingEvent Route -> Effect Unit
119+
onEvent newEvent =
120+
case newEvent of
121+
Router.Routing previousRoute requestedRoute ->
122+
showNavigationSpinner
123+
Router.Resolved previousRoute newRoute ->
124+
hideNavigationSpinner
125+
setCurrentRoute newRoute
126+
```
127+
128+
### Connect up the driver and router
129+
130+
<details>
131+
<summary>Imports</summary>
132+
133+
```purescript
134+
import Web.Router as Router
135+
import Web.Router.PushState as PushState
136+
```
137+
138+
</details>
139+
140+
```purescript
141+
mkRouter :: Effect (Router.Router Route Page)
142+
mkRouter = do
143+
driver <- PushState.mkInterface parseRoute printRoute
144+
router <- Router.mkInterface onNavigation onEvent driver
145+
pure router
27146
```
28147

29-
And then install with
30-
`$ spago install web-router`
148+
Both pushstate and hash drivers are included, or a custom driver can be implemented. An example of a custom driver could be one that synchronises some navigation state over sockets, for an experience where one user's behaviour could be broadcast to multiple users to follow along.

0 commit comments

Comments
 (0)