diff --git a/docs/advanced-features/middleware.md b/docs/advanced-features/middleware.md index b0f04aa0a5b17..5d38627289a9d 100644 --- a/docs/advanced-features/middleware.md +++ b/docs/advanced-features/middleware.md @@ -9,14 +9,14 @@ description: Learn how to use Middleware to run code before a request is complet | Version | Changes | | --------- | ------------------------------------------------------------------------------------------ | -| `v13.0.0` | Support overriding request headers. | +| `v13.0.0` | Middleware can modify request headers, response headers, and send responses | | `v12.2.0` | Middleware is stable | | `v12.0.9` | Enforce absolute URLs in Edge Runtime ([PR](https://github.com/vercel/next.js/pull/33410)) | | `v12.0.0` | Middleware (Beta) added | -Middleware allows you to run code before a request is completed, then based on the incoming request, you can modify the response by rewriting, redirecting, adding headers, or setting cookies. +Middleware allows you to run code before a request is completed, then based on the incoming request, you can modify the response by rewriting, redirecting, modifying the request or response headers, or responding directly. Middleware runs _before_ cached content, so you can personalize static files and pages. Common examples of Middleware would be authentication, A/B testing, localized pages, bot protection, and more. Regarding localized pages, you can start with [i18n routing](/docs/advanced-features/i18n-routing) and implement Middleware for more advanced use cases. @@ -218,6 +218,45 @@ export function middleware(request: NextRequest) { > **Note:** Avoid setting large headers as it might cause [431 Request Header Fields Too Large](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/431) error depending on your backend web server configuration. +## Producing a Response + +You can respond to middleware directly by returning a `NextResponse` (responding from middleware is available since Next.js v13.0.0). + +To enable middleware responses, update `next.config.js`: + +```js +// next.config.js +module.exports = { + experimental: { + allowMiddlewareResponseBody: true, + }, +} +``` + +Once enabled, you can provide a response from middleware using the `Response` or `NextResponse` API: + +```ts +// middleware.ts +import { NextRequest, NextResponse } from 'next/server' +import { isAuthenticated } from '@lib/auth' + +// Limit the middleware to paths starting with `/api/` +export const config = { + matcher: '/api/:function*', +} + +export function middleware(request: NextRequest) { + // Call our authentication function to check the request + if (!isAuthenticated(request)) { + // Respond with JSON indicating an error message + return new NextResponse( + JSON.stringify({ success: false, message: 'authentication failed' }), + { status: 401, headers: { 'content-type': 'application/json' } } + ) + } +} +``` + ## Related
diff --git a/docs/advanced-features/module-path-aliases.md b/docs/advanced-features/module-path-aliases.md index 8015f82667cd0..ec19e194bbfd3 100644 --- a/docs/advanced-features/module-path-aliases.md +++ b/docs/advanced-features/module-path-aliases.md @@ -7,7 +7,7 @@ description: Configure module path aliases that allow you to remap certain impor
Examples
diff --git a/docs/api-reference/next/link.md b/docs/api-reference/next/link.md index c8261e651f20b..5bcc16e4ce3e0 100644 --- a/docs/api-reference/next/link.md +++ b/docs/api-reference/next/link.md @@ -218,3 +218,43 @@ The default behavior of `Link` is to scroll to the top of the page. When there i Disables scrolling to the top ``` + +## With Next.js 13 Middleware + +It's common to use [Middleware](/docs/advanced-features/middleware) for authentication or other purposes that involve rewriting the user to a different page. In order for the `` component to properly prefetch links with rewrites via Middleware, you need to tell Next.js both the URL to display and the URL to prefetch. This is required to avoid un-necessary fetches to middleware to know the correct route to prefetch. + +For example, if you have want to serve a `/dashboard` route that has authenticated and visitor views, you may add something similar to the following in your Middleware to redirect the user to the correct page: + +```js +// middleware.js +export function middleware(req) { + const nextUrl = req.nextUrl + if (nextUrl.pathname === '/dashboard') { + if (req.cookies.authToken) { + return NextResponse.rewrite('/auth/dashboard') + } else { + return NextResponse.rewrite('/public/dashboard') + } + } +} +``` + +In this case, you would want to use the following code in your `` component (inside `pages/`): + +```js +// pages/index.js +import Link from 'next/link' +import useIsAuthed from './hooks/useIsAuthed' + +export default function Page() { + const isAuthed = useIsAuthed() + const path = isAuthed ? '/auth/dashboard' : '/dashboard' + return ( + + Dashboard + + ) +} +``` + +> **Note:** If you're using [Dynamic Routes](/docs/routing/dynamic-routes), you'll need to adapt your `as` and `href` props. For example, if you have a Dynamic Route like `/dashboard/[user]` that you want to present differently via middleware, you would write: `Profile`. diff --git a/errors/manifest.json b/errors/manifest.json index 5e48d7fa9d44e..9be351338750b 100644 --- a/errors/manifest.json +++ b/errors/manifest.json @@ -757,6 +757,10 @@ { "title": "invalid-segment-export", "path": "/errors/invalid-segment-export.md" + }, + { + "title": "next-router-not-mounted", + "path": "/errors/next-router-not-mounted.md" } ] } diff --git a/errors/next-router-not-mounted.md b/errors/next-router-not-mounted.md new file mode 100644 index 0000000000000..0bdb3f7a9ce73 --- /dev/null +++ b/errors/next-router-not-mounted.md @@ -0,0 +1,13 @@ +# NextRouter was not mounted + +#### Why This Error Occurred + +A component used `useRouter` outside a Next.js application, or was rendered outside a Next.js application. This can happen when doing unit testing on components that use the `useRouter` hook as they are not configured with Next.js' contexts. + +#### Possible Ways to Fix It + +If used in a test, mock out the router by mocking the `next/router`'s `useRouter()` hook. + +### Useful Links + +- [next-router-mock](https://www.npmjs.com/package/next-router-mock) diff --git a/examples/with-absolute-imports/README.md b/examples/with-absolute-imports/README.md index 8a35deaf0acd0..1d30ec808a3d7 100644 --- a/examples/with-absolute-imports/README.md +++ b/examples/with-absolute-imports/README.md @@ -1,6 +1,24 @@ -# Example app with absolute imports +# Absolute Imports and Aliases -This example shows how to configure Babel to have absolute imports instead of relative imports without modifying the Webpack configuration. +This example shows how to configure [Absolute imports and Module path aliases](https://nextjs.org/docs/advanced-features/module-path-aliases) in `tsconfig.json` (or `jsconfig.json` for JavaScript projects). These options will allow absolute imports from `.` (the root directory), and allow you to create custom import aliases. + +If you’re working on a large project, your relative import statements might suffer from `../../../` spaghetti: + +```tsx +import Button from '../../../components/button' +``` + +In such cases, we might want to setup absolute imports using the `baseUrl` option, for clearer and shorter imports: + +```tsx +import Button from 'components/button' +``` + +Furthermore, TypeScript also supports the `paths` option, which allows you to configure custom module aliases. You can then use your alias like so: + +```tsx +import Button from '@/components/button' +``` ## Deploy your own diff --git a/examples/with-absolute-imports/components/button.tsx b/examples/with-absolute-imports/components/button.tsx new file mode 100644 index 0000000000000..1deaded46204c --- /dev/null +++ b/examples/with-absolute-imports/components/button.tsx @@ -0,0 +1,3 @@ +export default function Button() { + return +} diff --git a/examples/with-absolute-imports/components/header.js b/examples/with-absolute-imports/components/header.tsx similarity index 100% rename from examples/with-absolute-imports/components/header.js rename to examples/with-absolute-imports/components/header.tsx diff --git a/examples/with-absolute-imports/jsconfig.json b/examples/with-absolute-imports/jsconfig.json deleted file mode 100644 index 36aa1a4dc28f1..0000000000000 --- a/examples/with-absolute-imports/jsconfig.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "compilerOptions": { - "baseUrl": "." - } -} diff --git a/examples/with-absolute-imports/package.json b/examples/with-absolute-imports/package.json index bf29745bfe271..1412a9c80e177 100644 --- a/examples/with-absolute-imports/package.json +++ b/examples/with-absolute-imports/package.json @@ -9,5 +9,11 @@ "next": "latest", "react": "^18.2.0", "react-dom": "^18.2.0" + }, + "devDependencies": { + "@types/node": "^18.11.9", + "@types/react": "^18.0.25", + "@types/react-dom": "^18.0.8", + "typescript": "^4.8.4" } } diff --git a/examples/with-absolute-imports/pages/index.js b/examples/with-absolute-imports/pages/index.js deleted file mode 100644 index 54c8bf264718a..0000000000000 --- a/examples/with-absolute-imports/pages/index.js +++ /dev/null @@ -1,9 +0,0 @@ -import Header from 'components/header.js' - -export default function Home() { - return ( -
-
-
- ) -} diff --git a/examples/with-absolute-imports/pages/index.tsx b/examples/with-absolute-imports/pages/index.tsx new file mode 100644 index 0000000000000..47f057a3b4813 --- /dev/null +++ b/examples/with-absolute-imports/pages/index.tsx @@ -0,0 +1,11 @@ +import Header from 'components/header' +import Button from '@/components/button' + +export default function Home() { + return ( + <> +
+