catch all routes and have a cms / api determine what all urls are completely dynamically
There may be situations when you want next js to catch all routes and have a cms / api determine what all urls are completely dynamically. You can use this module to help you load dynamic components for one dynamic page that catches all routes except for the homepage route. Note: The latest version of this module uses the catch all routes functionality only in next js >= 9.5
create a folder called routes
(can be called anything) with an index.js
file and other files aggregated like this
import dynamic from "next/dynamic";
export const homepage = dynamic(() => import("./homepage"));
export const about = dynamic(() => import("./about"));
// the idea is that this routes folder becomes your new "pages" directory in a way
// you can export your own static functions from the files and have them called when a request to the page is made as shown below
create the file lib/dynamic.js
. The make function takes an async function as argument that gets the next context. Once you query your cms / api to get the route id and handle, return an object with the properties shown below. The only required property is handle
. setupAppData
and setupPageData
are called in parallel. onNotFound
is called if handle
is undefined or _error
.
import makeNextDynamic from "@next-tools/dynamic";
export default makeNextDynamic(async (ctx) => {
const route = await someRouteQuery(ctx.asPath);
const handle = route ? route.handle : "_error";
return {
handle,
setupAppData: async () => {
const mod = await import("routes/_app");
// call some app setup function that returns app data that returns data on the prop appData
return await mod.setupData(ctx, route);
},
setupPageData: async () => {
const mod = await import(`routes/${handle}`);
// call some page specific setup function that returns page data on the prop pageData
return await mod.setupData(ctx, route);
},
onNotFound: async () => {
// maybe check for some redirects if not found
const redirects = await queryRedirects();
const redirectTo = checkForRedirects(uri, redirects);
if (redirectTo) {
ctx.res.writeHead(301, { Location: "/" + redirectTo });
ctx.res.end();
return { error404: false };
}
// if you return the prop error404 truthy, the function will try to load setupAppData and setupPageData
// this way you can have a setup function on your routes/_error page if you want
return { error404: true };
}
};
});
create the file pages/[[...args]].js
import * as routes from "routes/index";
import nextDynamic from "lib/nextDynamic";
const Page = ({ handle }) => {
const Cmp = routes[handle];
// the module will handle a 404 error page for you and load ~/routes/_error.js if it exists
return Cmp ? <Cmp /> : null;
};
// pass the context to nextDynamic function
// you could also use getServerSideProps
Page.getInitialProps = async function (ctx) {
// make sure to pass the context in always
const { handle, pageData, appData } = await nextDynamic(ctx);
// do stuff with the pageData here or forward it to the dynamic component
return { handle, pageData, appData };
};
export default Page;