Router

Reviewing a React router component implemented with Mosaic for Mosaic

In any frontend or backend application, the router is a place which is one of the most important ones to make plugin-friendly, when using Mosaic. Any amount of routes can be added to it, if it is designed correctly.

This article will demonstrate a router design from @scandipwa/shopify project, which is written completely in Mosaic.

Source implementation

Let's see the router itself! It is also available on this link. This is exactly the form of the router at the moment of writing this article.

It is clearly visible that the router does not actually render any routes! It just provides several convenient points for modification with Mosaic runtime plugins: _beforeSwitchRenderList, _switchRenderList and _afterSwitchRenderList

import { createSortedRenderMap } from '@scandipwa/framework/src/util/SortedMap';
import { createBrowserHistory } from 'history';
import { PureComponent } from 'react';
import { Router as ReactRouter } from 'react-router';
import { Switch } from 'react-router-dom';

export const history = createBrowserHistory({ basename: '/' });

/** @namespace Router/Component/Router/Component/RouterComponent */
export class RouterComponent extends PureComponent {
    static propTypes = {};

    _beforeSwitchRenderList = createSortedRenderMap({});

    _switchRenderList = createSortedRenderMap({});

    _afterSwitchRenderList = createSortedRenderMap({});

    contentRenderList = createSortedRenderMap({
        routerBeforeSwitch: this._beforeSwitchRenderList.render,
        routerRenderSwitch: this.renderSwitch.bind(this),
        routerAfterSwitch: this._afterSwitchRenderList.render
    });

    renderSwitch() {
        return (
            <Switch>
                { this._switchRenderList.render() }
            </Switch>
        );
    }

    renderRouterContent() {
        return this.contentRenderList.render();
    }

    render() {
        return (
            <ReactRouter history={ history }>
                { this.renderRouterContent() }
            </ReactRouter>
        );
    }
}

export default RouterComponent;

Filling such a router by using plugins

A router is pointless without routes, right? So let's add a route to the one defined above! We will use the Mosaic runtime plugins for this purpose.

As you see, the plugin declaration file presented below modifies the namespace of the class above, a member called _switchRenderList of target kind member-property

It implements a plugin (proxy) function addCartPage, which accepts the initial member - sorted render map _switchRenderList declared above, adds an additional item to that map and returns the modified value to the application.

/* eslint-disable @scandipwa/scandipwa-guidelines/jsx-no-props-destruction */
import { createElement, lazy, Suspense } from 'react';
import { Route } from 'react-router';

import CartFallbackPage from '../component/CartFallbackPage';

const CartPage = lazy(() => import('../component/CartPage'));

const addCartPage = (member) => {
    const CART_PAGE_POSITION = 1000;

    member.addItem(
        () => createElement(Route, {
            path: '/cart',
            exact: true,
            render: (props) => (
                <Suspense fallback={ <CartFallbackPage /> }>
                    <CartPage { ...props } />
                </Suspense>
            )
        }),
        'routerCartPage',
        CART_PAGE_POSITION
    );

    return member;
};

export default {
    'Router/Component/Router/Component/RouterComponent': {
        'member-property': {
            _switchRenderList: addCartPage
        }
    }
};

Last updated