NextJS: Run middleware for /pages only - next.js

With the recent change regarding middleware https://nextjs.org/docs/messages/middleware-upgrade-guide.
Now the middleware also gets triggered by requests for /_next and /favicon.ico.
What is the best way to only trigger it for requests for /pages folder. There is the matcher but it would be cumbersome to type all of the pages in it.
I'm currently using middleware to check if cookies exist and redirect the user if the user accesses a page. E.g Redirect the user to /login if the user accesses / and the user is not logged in yet.

To avoid the middleware running when "/_next" or "/favicon.ico" routes are requested simply start your middleware function with:
const { pathname } = req.nextUrl
// Allow the requests if the following is true...
// 1) if the request is a system request /_next
// 2) if the request is to get the favicon.ico
if (pathname.startsWith('/_next') || pathname.startsWith('/favicon.ico')) {
return NextResponse.next()
}
Not sure it's the cleanest way but it works fine for me. Don't hesitate to tell me if I can make this better.

Now that middleware is stable (>=12.2), you can use a regex on the matcher to exclude some paths.
export const config = {
// matcher solution for public, api, assets and _next exclusion
matcher: "/((?!api|static|.*\\..*|_next).*)",
};
Ref: https://github.com/vercel/next.js/discussions/36308#discussioncomment-3758041

Here is the snippet of middleware:
// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
// This function can be marked `async` if using `await` inside
export function middleware(request: NextRequest) {
return NextResponse.redirect(new URL('/about-2', request.url))
}
// See "Matching Paths" below to learn more
export const config = {
matcher: '/about/:path*',
}
If you want middleware to run on all paths:
export const config = {
matcher: '/:path*',
}
Have you tried this.

Related

How to use the same slug for different routes in Next.js? [duplicate]

I have quite a lot of routes defined and one of the routes is dedicated to user profiles.
Each user has a public profile accessible from HTTP://example.com/#username.
I have tried creating file pages/#[username].js but it doesn't seem to work.
Is there a way to have this behavior without passing # sign with the username because this would greatly complicate index.js handling homepage and I would like to have that code separated.
You can now do this like so in next.config.js
module.exports = {
async rewrites() {
return [
{
source: '/#:username',
destination: '/users/:username'
}
]
}
}
This will make any link to /#username go to the /users/[username] file, even though the address bar will show /#username.
Then, in your /pages/[username].tsx file:
import { useRouter } from 'next/router'
export default function UserPage() {
const { query = {} } = useRouter()
return <div>User name is {query.username || 'missing'}</div>
}
Next.js does not support this yet.
You should watch this issue.

Headers are removed from middleware in production Next js

I have such a strange thing. Project on next js 12.3. I use middleware to add canonical link to headers. Everything works locally, and the required headers are added, but when deployed in production, the header I need is not added.
if the subdomain is not www, the canonical must be a link to the www version
import { NextRequest, NextResponse } from 'next/server';
export function middleware(req: NextRequest, res: NextResponse) {
const { protocol, href } = req.nextUrl;
const subdomain = href.replace('https://','').split('.')[0];
if (subdomain !== 'www') {
const urlArr = href?.split('//');
const afterSubdomainUrl = urlArr?.slice(1, urlArr.length)?.join('//');
const response = NextResponse.next();
response.headers.append(
'Link',
`<${protocol}//www.${afterSubdomainUrl}>; rel="canonical"`,
);
return response;
}
}
The problem was at DockerFile - need to implement next code at
app/Dockerfile
COPY middleware.ts /app/middleware.ts
RUN true

NextJS middleware does not seem to be triggered

I have the middleware.js file within /myproject/pages/middleware.js:
export function middleware(request) {
console.log(1);
return NextResponse.redirect(new URL('/', request.url));
}
// See "Matching Paths" below to learn more
export const config = {
matcher: ['/test'],
};
Now what I expect is when i go to the page /test then it should redirect me to /. However nothing happens and I see my standard 404 page.
Any ideas why?
NextJs version: 12.2.2
Latest versions of NextJS requires user to have a single middleware on the root folder.
Instead of {root}/pages/_middleware.js, try {root}/middleware.js
For next 13.0.2 / 13.0.1
if you are using appDir: true ( experimental )
if you want to hit middleware:
put middleware.ts in root project:
( as the same hierarchy as "app" folder, not inside app folder... )
make sure tsconfig has include: [..., "middleware.ts"]
make empty "pages" folder. ( based on issue )
will hit every request:
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
export function middleware(request: NextRequest ) {
console.log('lol!!!')
}
export const config = {
matcher: '/',
}
if your pages and middleware are not on the same level, then it won't work.
here is an example of middleware working with Cookies.
import { NextResponse } from "next/server";
export default function middleware(req){
let verify = req.cookies.get("loggedin");
let url = req.url
if(!verify && url.includes('/dashboard')){
return NextResponse.redirect("http://localhost:3000/");
}
if (verify && url === "http://localhost:3000/") {
return NextResponse.redirect("http://localhost:3000/dashboard");
}
}

Next Js: Middleware is ignored for a directory with re-writes

I have a file system like this
Pages
secure/
_middleware.ts
protectedResource.tsx
_app.tsx
_document.tsx
index.tsx
I have next configured like this
module.exports = {
...
async rewrites() {
return [
{
source: '/protectedResource',
destination: '/secure/protectedResource'
}
]
}
}
The rewrite works correctly, when accessing http://localhost:3000/protectedResource the user sees the correct route. The middleware from the 'secure' directory, however, is not invoked during the request pipeline. Aside from moving the middleware to the pages directory, how can I resolve this?

Adding prefix to Nextjs dynamic route

I have quite a lot of routes defined and one of the routes is dedicated to user profiles.
Each user has a public profile accessible from HTTP://example.com/#username.
I have tried creating file pages/#[username].js but it doesn't seem to work.
Is there a way to have this behavior without passing # sign with the username because this would greatly complicate index.js handling homepage and I would like to have that code separated.
You can now do this like so in next.config.js
module.exports = {
async rewrites() {
return [
{
source: '/#:username',
destination: '/users/:username'
}
]
}
}
This will make any link to /#username go to the /users/[username] file, even though the address bar will show /#username.
Then, in your /pages/[username].tsx file:
import { useRouter } from 'next/router'
export default function UserPage() {
const { query = {} } = useRouter()
return <div>User name is {query.username || 'missing'}</div>
}
Next.js does not support this yet.
You should watch this issue.

Resources