platforms
platforms copied to clipboard
Nested path inside _sites is not working
I tried to put the specific path for custom domains, like below
my-domain.localhost:3000/posts/nextjs-awesome -> returns 404
My project | _sites | ----posts |---index.tsx |----[slug].tsx
It does not work. Can someone tell me why?
I believe this is because of
url.pathname = `/_sites/${currentHost}${url.pathname}`;
inside of middleware.ts. The url.pathname includes a / so the pathname ends being something like pathname: '/_sites//fcs' and that double / messes things up.
I think the matcher pattern that's used (src) to exclude paths with . is also excluding paths that contain any subsequent / chars after the prefix /.
This should work (note the regular expression doesn't contain / anymore in the negated set):
export const config = {
matcher: [
"/",
"/([^.]*)", // exclude `/public` files by matching all paths except for paths containing `.` (e.g. /logo.png)
"/site/:path*",
"/post/:path*",
"/_sites/:path*",
],
};
@dstotijn doing that for me broke images loading in Next.js' Image component
That regular expression I proposed doesn't narrow down "public" files, it filters out any path with . in it. So it does what it says in the comment ;) You could write a regexp with a negative lookahead to filter out whatever patterns that you know occur in static file paths, e.g. .png, .jpg, etcetera.
Hey guys, sorry for the late response!
@tandat2209 The reason this is happening is because you need to add an extra matcher item "/posts/:path*" in the matcher config in the middleware file, if that's what you want your route structure to look like. The reason we do this is to make sure the middleware only matches paths that it needs to and does not end up matching absolute paths like "demo.vercel.pub/_sites/steven" and have the content from steven be served.
@dstotijn @JamesSingleton hope this made sense for y'all as well! I also added some detailed comments here explaining everything: https://github.com/vercel/platforms/blob/main/middleware.ts#L3-L28
Will close the issue for now, feel free to reopen it if there's any other confusions! :)
@steven-tey, its not clear to me if its possible (and how) to match nested routes.
I have different first level domain that points to the multi-tenancy app, and need to fetch all url paths, (using a catch all route [...slug].tsx) thats my code :
import { NextRequest, NextResponse } from 'next/server';
const env = process.env.NODE_ENV;
export const config = {
matcher: [
'/',
'/([^/.]*)', // exclude `/public` files by matching all paths except for paths containing `.` (e.g. /logo.png)
'/site/:path*',
'/post/:path*',
'/_sites/:path*',
],
};
export default function middleware(req: NextRequest) {
const url = req.nextUrl;
const hostname = req.headers.get('host') || 'localhost:3000';
// const currentHost = env === 'development' ? 'localhost' : hostname;
const currentHost = hostname.replace(':3001', '');
url.pathname = `/_sites/${currentHost}${url.pathname}`;
console.log(`/_sites/${currentHost}${url.pathname}`);
return NextResponse.rewrite(url);
}
For example, mywebsite.com/hello works while mywebsite.com/hello/there does not.
Any idea on how i can match nested routes?
Facing the same issue!
@tandat2209 @JamesSingleton @dstotijn @nicosh @DevOfManyThings – in light of my recent discovery that you can use negative matchers for middleware, I just pushed a new version of the middleware that uses negative matchers to match all request paths except:
/apiroutes/_next(Next.js internals)/fonts(inside/publicfolder)/examples(inside/publicfolder)- all root files inside
/publicfolder(e.g./favicon.ico)
This should fix all of the issues above! :)
@steven-tey this sound great! however, for my use case, i ended up using conditional statements
export default function middleware(req: NextRequest) {
if (
!req.nextUrl.pathname.includes('.') &&
!req.nextUrl.pathname.includes('/api/revalidate') &&
!req.nextUrl.pathname.includes('/_next')
) {
const url = req.nextUrl;
const hostname = req.headers.get('host') || 'localhost:3000';
// const currentHost = env === 'development' ? 'localhost' : hostname;
const currentHost = hostname.replace(':3001', '');
//console.log(`${currentHost}${url.pathname}`);
url.pathname = `/_sites/${currentHost}${url.pathname}`;
//console.log(`/_sites/${currentHost}${url.pathname}`);
return NextResponse.rewrite(url);
}
}
and changed [slug].tsx to [...slug].tsx