Dynamic Routing
Since version 3.5
This guide explains how you can create dynamic routes for url rewrites in Front-Commerce.
What is dynamic routing?
Dynamic routes are generated based on the data available in your application,
allowing for more meaningful and SEO-friendly URLs. For example, instead of a
generic URL such as /product/sku-6, you can have a more descriptive URL like
/acme-product.html.
Consider a Remix route for your products defined as routes/product.$id.tsx. By
leveraging dynamic routes, you can replace generic product URLs with
SEO-friendly alternatives.
Generic Route Example
- URL:
/product/sku-6
SEO-Friendly Route Example
- URL:
/acme-product.html
By implementing dynamic routes, you enhance the readability and search engine optimization (SEO) of your URLs, which can improve your site's visibility and user experience.
How to create dynamic routes?
Batching and Prioritizing URL Matchers
When multiple URL matchers are registered without any matcherOptions, it will
default the batchOrder and priority to 0. This means that the order in which the
URL matchers are registered will determine the order in which they are executed.
Let's say we have the following list of URL Matchers:
A → fast API (cached)
B → no API (static)
C → slow API (not cached)
D → no API (static)
We would ideally want this to first try to run B and D then A and finally
C. To achieve this we can set the batchOrder and priority fields in the
matcherOptions object.
services.DynamicRoutes.registerUrlMatcher("A", () => new UrlMatcherA(), {
batchOrder: 1,
priority: 1,
});
services.DynamicRoutes.registerUrlMatcher("B", () => new UrlMatcherB(), {
batchOrder: 0,
priority: 2,
});
services.DynamicRoutes.registerUrlMatcher("C", () => new UrlMatcherC(), {
batchOrder: 2, // only run if no other batches have matched
priority: 1,
});
services.DynamicRoutes.registerUrlMatcher("D", () => new UrlMatcherD(), {
batchOrder: 0,
priority: 1,
});
This would result in the following order of execution:
# batch 0
D → no API (static)
B → no API (static)
# batch 1
A → fast API (cached)
# batch 2 (only run if no other batches have matched)
C → slow API (not cached)
Extending the type declarations
For TypeScript support of the type field in your handle export, you can extend
the DynamicRoutesCompositionList interface from the @front-commerce/types
package to include your custom types.
Known Limitations
Matching Catch-All Routes (Splat Routes)
In Remix, you can create a catch-all route that matches any path, for example:
| URL | Matched Route |
|---|---|
/foo/a | routes/foo.$.tsx |
/bar/a | routes/bar.$.tsx |
However, it's not possible to create a URL Matcher for catch-all routes because
the URL will still be matched by Remix. Attempting to match /example to
routes/foo.$.tsx using a URL matcher will result in the following error:
Error: Route "routes/foo.$" does not match URL "/example"
Dynamic Route Catch-All Placeholder
To implement CSR for dynamic routes,
the application requires specific internal logic in the
routes/_main.$.tsx
file.
If you have overwritten this route, you will need to manually apply and maintain this logic to ensure proper functionality.
HMR Reloads with Multiple Dynamic Route Tabs
When working in development mode with Hot Module Replacement (HMR), you might encounter issues when loading multiple dynamic routes in parallel tabs. This can cause the dynamic route manifest to become out of sync, resulting in pages not loading correctly.
Symptoms
Pages with dynamic routes stop working after HMR reloads
TypeError: Cannot read properties of undefined (reading 'module')
Solutions
You can resolve this issue by either:
- Restarting your development server
- Using client-side navigation to the affected pages, which will re-populate the manifest and restore functionality
Known issues
No routeModule available to create server routes
Internal Reference: 67201
Symptoms
In production, you might see the following error:
Error: No `routeModule` available to create server routes
Abnormal rate of 500 errors in your logs.
Cause
When a same URL is loaded in a small amount of time by the same Front-Commerce server process, a race condition occurs on the ServerBuild to be partially built to load Dynamic Routes by multiple threads.
Solution
We have implemented a new experimental way to load Dynamic Routes in memory to prevent the race condition, you can apply this patch by following the dedicated Merge Request patch.
This MR implements
the use of a feature flag to enable the in-memory dynamic route matcher.
However, when applying this patch to your project, we recommend you to replace
the feature flag by a process.env.FRONT_COMMERCE_DYNAMIC_ROUTES_IN_MEMORY
environment variable to enable it.
This way, you'll be able to enable and disable it quickly on your project without the need of a rebuild.