Nested LWR Client-Side Routing Example
You can use the @lwrjs/router
package to create a single page application (SPA) with nested client-side routing.
Before creating an SPA with nested routing, check out:
- Client-Side Routing in LWR on Node.js
- Simple LWR Client-Side Routing Example
- LWR Client-Side Routing Reference
While an LWR app contains more files than shown here, in this recipe the following example module files are most important:
This example describes creating an SPA with two levels of client-side routing. The root component (example/app
) owns the parent router, and the example/animal
component owns the child router. The sitemap for the app is structured like this:
Owner | View Component | URL |
---|---|---|
parent router | example/home | / |
parent router | example/animal | /animal |
child router | example/animalHome | /animal/ |
child router | example/animalCat | /animal/cat |
child router | example/animalDog | /animal/dog |
The child router lives under the /animal
parent URL, so all of its absolute URLs are prefixed with /animal
. The parent router owns the beginning URL segments (/
and /animal
), while the child router owns the ending URL segments (/
, /cat
, and /dog
).
If a user navigates to any of the /animal/*
URLs, they find two view components on the page:
example/animal
from the parent routerexample/animalHome
,example/animalCat
, orexample/animalDog
from the child router
The first step in creating a router is to set up the root component of your SPA. You specify a rootComponent
value in a routes
object in your app’s lwr.config.json
file. Check out the example below and "Routing Properties" for more information.
The routes defined in lwr.config.json
are server-side. They differ from the RouteDefinition
array that you set up for the client-side routers.
After you set up your root component, you create a router in it.
Start by importing the createRouter()
function from lwr/router
. Next, define a RouteDefinition
array and pass that array to createRouter()
.
Finally, the createRouter()
function returns a router instance for use by lwr/routerContainer
.
Since the preceding child router is attached to the /animal
URI, the RouteDefinition
MUST have exact: false
.
In your root component’s html file, attach the router instance to lwr/routerContainer
:
In the previous step you created a router in your root component. That router includes promises in RouteDefinition.handler
to route handler modules that are called when a location matches a RouteDefinition
. Route handler modules determine the associated "view" that’s displayed when the application navigates to a location. They also allow you to define enhanced routing rules such as branching and pivoting logic based on data and metadata values.
In LWR, modules are always provided via promises. Promises allow the module code to be lazily loaded, improving application performance.
For the root component in this example, the homePageHandler
and animalPageHandler
modules each have forms similar to:
Similarly to how you created a parent router, you create a child router in example/animal
:
And in the associated html file, you attach the router instance to lwr/routerContainer
:
You create the child route handlers similarly to how you created parent route handlers.
The first child route handler, animalHomePageHandler
, has a form similar to that of the homePageHandler
and animalPageHandler
modules discussed previously:
The animalNamedPageHandler
module, however, is more complicated. Here the module is determining the view based on branching logic:
Simple Routing for an SPA provides an example of handling navigation in your application.
Run the following terminal commands from the root of your project:
Open the site at http://localhost:3000. Read Get Started for details on LWR Yarn commands.