To implement a new Route you need to define what component you want to render and in which path. For example, You want to render the component <YourPage>
in the path /yourPage/:query/
.
<aside>
✅ It’s a convention to keep the components used in the Router in the src/route
directory.
If you don’t have a component, consider creating one using the ScandiPWA CLI tool. How to create a Route component?
scandipwa create route <NAME>
This will create the route’s component files under src/route/<NAME>
folder, it will give you some boilerplate code. It is up to you to render the required interface and add functionality.
</aside>
After defining what component and in which path, you need to:
Router
component knows the component you want to render and in which path. For that, we make use of the plugin mechanism.You now have a component, but it's not registered in the router yet. You need to add it to the SWITCH_ITEMS_TYPE
field of the router.
Write a plugin (How to create a plugin?) for the Component/Router/Component
namespace to wrap around the SWITCH_ITEMS_TYPE
field and add your route there.
Most likely, your plugin will look similar to this one:
import { lazy } from 'react';
import { Route } from 'react-router-dom';
import { withStoreRegex } from 'Component/Router/Router.component';
export const YourPage = lazy(() => import(
/* webpackMode: "lazy", webpackChunkName: "extension-name" */
'../route/YourPage'
));
export const ROUTE_NAME = 'SOME_ROUTE_NAME';
const SWITCH_ITEMS_TYPE = (originalMember) => [
...originalMember,
{
component: <Route
path={ withStoreRegex('/yourPage/:query/') }
render={ (props) => <YourPage { ...props } /> }
/>,
position: 25,
name: ROUTE_NAME
},
];
export default {
'Component/Router/Component': {
'member-property': {
SWITCH_ITEMS_TYPE
}
}
};
Make sure to use this import instead of the conventional import
... from
... syntax:
lazy(() => import(/* webpackMode: "lazy", webpackChunkName: "cms" */ 'Route/CmsPage'));
The lazy import syntax helps improve the initial load performance, because the browser only needs to render the currently active page, so loading the code for other routes can be postponed.
What are the configuration options?
You will notice that each route has quite a few parameters you can change:
{
component: <Route
path={ withStoreRegex('/search/:query/') }
render={ (props) => <SearchPage { ...props } /> }
/>,
position: 25,
},
The component
should always be a react-router
Route
component with these props:
path
is the URL at which you want your route to appear. Prefix a segment with a colon (:
) if you want to add a variable to the route.exact
is a boolean prop. If you include it, it will strictly match only the specified path.<aside>
➡️ This is necessary if you don't want the route to match other paths. For example, the homepage needs to match only /
, and not /products
– but both would be matched unless the exact
prop is provided – because /products
start with /
</aside>
render
should be a function rendering your component.react-router
Routes. What props are available?The position
will determine the sort order of your route. In react-router, the order of the routes specified does matter.
<aside>
⚠️ For development-purpose pages like /base-template
, this step is optional.
</aside>
Once you have added a new route on the frontend, you need to ensure that the Magento backend knows about it too.
If you are using ScandiPWA in Magento theme mode and refresh the page you just created, check the response status code from the server in the developer tools. You will see that it responds with a 404 Not Found code. While this may seem insignificant at first, it can actually harm your SEO.
It would be much better to have the correct status codes: 404 for non-existent pages and a 200 Ok response for valid URLs.
Looking at scandipwa/route717/src/etc/di.xml
, we can see an example of how the routes can be configured:
<?xml version="1.0"?>
<config xmlns:xsi="<http://www.w3.org/2001/XMLSchema-instance>"
xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<!-- [...] -->
<type name="ScandiPWA\\Router\\ValidationManager">
<arguments>
<argument name="validators" xsi:type="array">
<item name="cart" xsi:type="string">ScandiPWA\\Router\\Validator\\AlwaysPass</item>
<item name="wishlist" xsi:type="string">ScandiPWA\\Router\\Validator\\Wishlist</item>
<item name="checkout" xsi:type="string">ScandiPWA\\Router\\Validator\\AlwaysPass</item>
</argument>
</arguments>
</type>
<!-- [...] -->
</config>
The validators argument of the ValidationManager
is an array mapping paths to corresponding validators. The validators' job is to determine if a path is valid (200 status code) or invalid (404 not found).
The ScandiPWA\\Router\\Validator\\AlwaysPass
validator will always return 200. This is useful for "static" routes without variables.
However, for more complex cases, you will have variables inside the route. For example, a product
route will be 200 for existing products but 404 for other URLs.
What are response status codes?
How you configure the router will depend on if your route is static (always the same) or dynamic (with a variable in the path). If your route does not include any variables, you can simply tell the backend router that it should always return a 200 Ok status code. If, however, you need custom logic with variables in the route, you will need to implement your own validator.
If your route does not include any variables, you can simply tell the backend router that it should always return a 200 Ok status code.
First, create a new Magento module for this configuration. Then, in its di.xml
file, add an entry for the validators
argument of ScandiPWA\\Router\\ValidationManager
:
<?xml version="1.0"?>
<config xmlns:xsi="<http://www.w3.org/2001/XMLSchema-instance>" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<type name="ScandiPWA\\Router\\ValidationManager">
<arguments>
<argument name="validators" xsi:type="array">
<item name="about-us-page" xsi:type="string">ScandiPWA\\Router\\Validator\\AlwaysPass</item>
</argument>
</arguments>
</type>
</config>
Sometimes, whether a route is valid or not will depend on a dynamic variable. For example, the /product
route is valid for existing products like /product/black_hoodie
but invalid for non-existing URLs like /product/nonexistent-product
.
If that is the case, you need to create a new validator class by implementing the \\ScandiPWA\\Router\\ValidatorInterface
:
<?php
namespace ScandiPWA\\Router\\Validator;
use Magento\\Framework\\App\\RequestInterface;
use ScandiPWA\\Router\\ValidatorInterface;
class CustomValidator implements ValidatorInterface
{
public function validateRequest(RequestInterface $request): bool
{
// custom validation logic
}
}
<aside>
ℹ️ The request object is of type Magento\\Framework\\App\\Request\\Http
</aside>
You can then configure the DI system to inject your validator into the ScandiPWA\\Router\\ValidationManager
object.
SWITCH_ITEMS_TYPE