A typical SPA application is defined in a few simple steps:
boostrap the application with init or initNoShared
add pages with addPublicPage and addProtectedPage
finalize the application with application (with the possible help of mapSharedMsg
main =
Spa.init
{ defaultView = View.defaultView
, extractIdentity = Shared.identity
}
|> Spa.addPublicPage mappers Route.matchHome Home.page
|> Spa.addPublicPage mappers Route.matchSignIn SignIn.page
|> Spa.addProtectedPage mappers Route.matchCounter Counter.page
|> Spa.addPublicPage mappers Route.matchTime Time.page
|> Spa.application View.map
{ toRoute = Route.toRoute
, init = Shared.init
, update = Shared.update
, subscriptions = Shared.subscriptions
, toDocument = toDocument
, protectPage = Route.toUrl >> Just >> Route.SignIn >> Route.toUrl
}
|> Browser.applicationAdd a public page to the application
|> Spa.addPublicPage (View.map, View.map) matchHome Pages.Home.pagemappers is a Tuple of view mappers. For example, if the application view is
a Html msg, the mappers will be: ( Html.map, Html.map ). The duplication
is for technical reasons (see the addPage function implementation).
match is a function that takes a route and returns the page flags if and
only if the route matches the page. This is the place where data can
be extracted from the route to be given to the page init function.
A simple match function can be:
matchHome : Route -> Maybe ()
matchHome route =
case route of
Home ->
Just ()
_ ->
NothingA match function that extracts data from the route:
matchSignIn : Route -> Maybe (Maybe String)
matchSignIn route =
case route of
SignIn redirect ->
Just redirect
_ ->
Nothingpage is a page constructor. A public page constructor is a function that
takes the shared state:
page : shared -> PageAdd a protected page to the application
|> Spa.addProtectedPage (View.map, View.map) matchProfile Pages.Profile.pageThe parameters are the same as addPublicPage, except that the page constructor takes the current identity in addition to the shared state:
page : shared -> identity -> PageOnce all the pages are added to the application, we can change it into a record
suitable for the Browser.application function.
Set a message for reacting to a route change, before the page is (re-)initialized
The shared state after handling this message will be passed to the page, but the effect will be combined to the page init effects.
Finalize the Spa application into a record suitable for the Browser.application
appWithPages
|> Spa.application View.map
{ toRoute = Route.toRoute
, protectPage = Route.toUrl >> Just >> Route.SignIn >> Route.toUrl
, init = Shared.init
, update = Shared.update
, subscriptions = Shared.subscriptions
, toDocument = toDocument
}
|> Browser.applicationIt takes a view mapper, then:
toRoute changes a Url.Url into a (custom) routeprotectPage produces a redirection url when a protected route is accessed
without being identifiedinit is the init function of the shared moduleupdate is the update function of the shared modulesubscriptions is the subscriptions function of the shared moduletoDocument is a function that convert a view to a Browser.DocumentSet a custom message for handling the onUrlRequest event of the Browser application.
The default handler does what most people expect (Nav.push internal urls, and Nav.load external urls).
The intermediate type for building an application.
The Application Model
The Application Msg type
A custom setup error for the underlying PageStack.Stack
The Application type that can be passed to Browser.application
Bootstrap a Spa application
defaultViewis the default view that will be used when no other pages can be viewed. This should never happen once your app is properly setup (more on that a little further).extractIdentityis a function that returns aMaybe identityfrom aSharedrecord. The actualidentitytype can be anything you want.