0.2.0 • Published 2 years ago

@medeor/declarative-route-builder v0.2.0

Weekly downloads
-
License
ISC
Repository
github
Last release
2 years ago

Declarative Route Builder

npm

A declarative way to build the routes for your frontend application. Decouple the routing structure from the UI and navigation libraries, split routes in cohesive modules and then aggregate them all into a complete route hierarchy.

Getting Started

First, install the library using your favorite package manager:

npm i @medeor/declarative-route-builder --save

or

yarn add @medeor/declarative-route-builder

Creating your routing tree

Create a Tree and add routes and navigators into it. The Tree will compute the routes into the navigators, and provide a json-like structure for you to iteratively render the routing hierarchy using your UI navigation library.

import {
    Route,
    StackNavigator,
    Tree,
} from '@medeor/declarative-route-builder'

const router = new Tree();
router.add('namespace', new Route('main', MainComponent));
router.add('namespace', new StackNavigator('settings', [
    new Route('profile-settings', ProfileComponent),
    new Route('billing-settings', BillingComponent)
]))

export const routes = router.getRoutes('namespace')

Namespaces

Use namespaces to control access flow of your routes.

// infra/routes.ts
import {
    Route,
    Tree,
} from '@medeor/declarative-route-builder'

const router = new Tree({
    public: [
        new Route('signup', <SignupComponent />),
    ],
    private: [
        new Route('profile', <ProfileComponent />)
    ]
})

export default router;

or

// infra/routes.ts
import {
    Route,
    Tree,
} from '@medeor/declarative-route-builder'

const router = new Tree()
    .add('public', new Route('signup', <SignupComponent />))
    .add('private', new Route('profile', <ProfileComponent />));

export default router;

then

// presentation/Routes.tsx
import React from 'react'
// ...
import routes from '@infra/routes'

const Routes: React.FC = () => {
    const { isLogged } = useAuthContext()

    return isLogged ?
        <RenderRoutes tree={routes.getRoutes('private')} > :
        <RenderRoutes tree={routes.getRoutes('public')} >
}

export default Routes

Navigators

You can use navigators that group routes inside them. Navigators can have different types, mostly used when building routes using React Native, or nesting routes on the web.

import {
    BottomTabsNavigator,
    Route,
    StackNavigator,
    Tree,
} from '@medeor/declarative-route-builder'

export const routes = new Tree()
    .add('main', new StackNavigator(
        'Main',
        [
            new Route('Welcome', Welcome),
            new BottomTabsNavigator(
                'Home',
                [
                    new Route('Feed', Feed),
                    new Route('Setttings', Settings)
                ]
            )
        ]
    ))

Modules

Split your routes into different files, then group them into one main navigator to split your code into cohesive modules.

// Authentication Module
import {
    Route,
    Tree,
} from '@medeor/declarative-route-builder'

export const authenticationRoutes = new Tree()
    .add('main', new Route('signin', Signin))
    .add('main', new Route('signup', Signup))

// Users module
import {
    Route,
    Tree,
} from '@medeor/declarative-route-builder'

export const userRoutes = new Tree()
    .add('main', new Route('user', User))
    .add('main', new Route('users', Users))

// Main module
import { Tree } from '@medeor/declarative-route-builder'

import { authenticationRoutes } from '@modules/authentication/routes'
import { userRoutes } from '@modules/user/routes'

const router = new Tree()
    .use(authenticationRoutes)
    .use(userRoutes)

Result object

The routes you create result in a JSON-like object you can iterate over to render your own routing hierarchy.

import {
    BottomTabsNavigator,
    Route,
    StackNavigator,
    Tree,
} from '@medeor/declarative-route-builder'

const routes = new Tree()
    .add('main', new StackNavigator(
        'Main',
        [
            new Route('Welcome', 'Welcome'),
            new Route('Feed', 'Feed'),
        ]
    ))

// routes.getRoutes('main')
[
  {
    key: 'Main',
    routes: [
        {
            key: 'Welcome',
            target: 'Welcome',
            type: 'route',
        },
        {
            key: 'Feed',
            target: 'Feed',
            type: 'route',
        }
    ],
    type: 'navigator',
    navigator: 'stack'
  }
]

Type checking

The Tree class can receive a generic that enforces various types, such as allowed namespaces, route names, and more. You can extend the base RouterSpecifications interface and replace any type with a matching one.

// From @medeor/declarative-route-builder
interface RouterSpecifications {
    icons: string;
    routeKeys: string;
    routeTarget: any;
    navigatorKeys: string;
    nodeTitles: string;
    namespaces: string;
}

// In your project
interface CustomSpecifications extends RouterSpecifications {
    icons: 'close' | 'back';
    routeKeys: 'Home' | 'Auth';
    routeTarget: React.ComponentType<any>;
    navigatorKeys: 'MainTabs';
    nodeTitles: 'User' | 'Login';
    namespaces: 'public' | 'private';
}

// You can pass the CustomSpecification via generic to each routing class for type-checking
const tree = new Tree<CustomSpecification>()
    .add('public', new Route<CustomSpecification>('Home', HomeComponent))

// Or you can use the tree's factories to avoid passing the generic to each class
const tree = new Tree<CustomSpecification>();
tree.add('public', tree.Route('Auth', AuthComponent, { icon: 'close' }))
0.2.0

2 years ago

0.1.1

2 years ago

0.1.0

2 years ago

0.0.3

2 years ago

0.0.2

2 years ago

0.0.1

2 years ago