create-perfect-template
Version:
Create a modern Next.js SaaS template with progressive feature activation
72 lines (59 loc) • 2 kB
text/typescript
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
import { config as appConfig } from '../config';
let clerkMiddleware: any;
let createRouteMatcher: any;
if (appConfig.auth.enabled) {
const clerkImports = require('@clerk/nextjs/server');
clerkMiddleware = clerkImports.clerkMiddleware;
createRouteMatcher = clerkImports.createRouteMatcher;
}
// Define routes based on enabled services
const getPublicRoutes = () => {
const routes = [
'/',
'/features(.*)',
'/api/webhooks(.*)',
];
if (appConfig.billing.enabled) {
routes.push('/pricing(.*)');
routes.push('/api/autumn(.*)');
}
if (appConfig.auth.enabled) {
routes.push('/sign-in(.*)');
routes.push('/sign-up(.*)');
}
return routes;
};
const isPublicRoute = appConfig.auth.enabled
? createRouteMatcher(getPublicRoutes())
: () => true;
export default function middleware(req: NextRequest) {
const { pathname } = req.nextUrl;
// Redirect pricing page if billing not enabled
if (pathname.startsWith('/pricing') && !appConfig.billing.enabled) {
return NextResponse.redirect(new URL('/', req.url));
}
// Redirect auth pages if auth not enabled
if ((pathname.startsWith('/sign-in') || pathname.startsWith('/sign-up')) && !appConfig.auth.enabled) {
return NextResponse.redirect(new URL('/dashboard', req.url));
}
// No auth required in core mode
if (!appConfig.auth.enabled) {
return NextResponse.next();
}
// Use Clerk middleware for auth-enabled mode
return clerkMiddleware(async (auth: any, req: NextRequest) => {
if (!isPublicRoute(req)) {
await auth.protect();
}
})(req);
}
export const config = {
matcher: [
// Skip Next.js internals and all static files, unless found in search params
'/((?!_next|[^?]*\\.(?:html?|css|js(?!on)|jpe?g|webp|png|gif|svg|ttf|woff2?|ico|csv|docx?|xlsx?|zip|webmanifest)).*)',
// Always run for API routes
'/(api|trpc)(.*)',
],
};