Skip to content

Instantly share code, notes, and snippets.

@mhsattarian
Created May 14, 2024 09:01
Show Gist options
  • Save mhsattarian/89d63a6b4494573ba0283e8f53f8cc06 to your computer and use it in GitHub Desktop.
Save mhsattarian/89d63a6b4494573ba0283e8f53f8cc06 to your computer and use it in GitHub Desktop.
Get All the valid routes for a Next.js application using the app router
/**
* Adopted from: https://github.com/Emiyaaaaa/next-routes-list/blob/8a91e25edcf7226b4534f11cfc04b39515162bf1/src/getNextRoutes.ts#L1
*/
import listPaths from 'list-paths';
export function getNextRoutes(
src = './app',
fileNames = ['page', 'route'],
extensions = ['tsx', 'ts', 'js', 'jsx', 'md', 'mdx']
) {
const pagePaths = listPaths(src, { includeFiles: true }).filter((path) => {
const file = path.split('/').at(-1);
const filename = file?.split('.').at(-2);
const extension = file?.split('.').at(-1);
if (!filename || !extension) return false;
return extensions.includes(extension) && fileNames.includes(filename);
});
/**
=> paths = [
'./app/(group)/blog/page.tsx', => route should be '/blog'
'./app/(group)/blog/[...slug]/page.tsx', => route should be '/blog/[...slug]'
'./app/@component/blog/page.tsx', // should remove, because it's not a page
'./app/blog/(..)list/page.tsx', // should remove, because it's not a page
]
*/
const routes = pagePaths
.map((path) => {
const parts = path.split(src)[1]?.split('/').filter(Boolean) ?? [];
const url: string[] = [];
for (let i = 0; i < parts.length; i++) {
const part = parts[i];
if (!part) continue;
const isGroupRoute = part.startsWith('(') && part.endsWith(')');
if (isGroupRoute) continue;
const isInterceptingRoute = part.startsWith('(') && !part.endsWith(')');
if (isInterceptingRoute) return null;
const isParallelRoute = part.startsWith('@');
if (isParallelRoute) return null;
// ignore 'page.tsx' on url path
if (i === parts.length - 1) continue;
url.push(part);
}
return `/${url.join('/')}`;
})
.filter(Boolean) as string[];
const unDuplicatedRoutes = Array.from(new Set(routes));
return unDuplicatedRoutes;
}
@mhsattarian
Copy link
Author

mhsattarian commented May 14, 2024

using this code along with a script like this as a prepare script*:

import fs from 'fs';

import { getNextRoutes } from './utils/next-routes';

const routes = getNextRoutes();

const content = `export const routes = ${JSON.stringify(routes)};`;

fs.writeFileSync('all-routes.ts', content);
  • This script is best to run every time the project is scaffolding, so I would like to add a prepare script in the package.json file to run it:
{
    "scripts": {
        "prepare": "npm run generate-next-routes-list",
        "generate-next-routes-list": "tsx generate-routes.ts"
   },
}

to generate a list of all valid routes in my Next.js application and use it in the middleware to detect invalid routes and redirect them to another address.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment