-
Notifications
You must be signed in to change notification settings - Fork 73
Add middleware support #113
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
2d18dc3
0435b82
8c022f7
29aa483
280bad0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,5 +3,6 @@ node_modules | |
|
||
output | ||
.worker-next | ||
.save.next | ||
.open-next | ||
.wrangler | ||
dist |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import type { OpenNextConfig } from "@opennextjs/aws/types/open-next"; | ||
|
||
const config: OpenNextConfig = { | ||
vicb marked this conversation as resolved.
Show resolved
Hide resolved
|
||
default: {}, | ||
|
||
middleware: { | ||
external: true, | ||
override: { | ||
wrapper: "cloudflare", | ||
converter: "edge", | ||
}, | ||
}, | ||
}; | ||
|
||
export default config; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,10 @@ | ||
#:schema node_modules/wrangler/config-schema.json | ||
name = "api" | ||
main = ".worker-next/index.mjs" | ||
compatibility_date = "2024-09-16" | ||
compatibility_flags = ["nodejs_compat_v2"] | ||
main = ".open-next/index.mjs" | ||
compatibility_date = "2024-09-23" | ||
compatibility_flags = ["nodejs_compat"] | ||
|
||
assets = { directory = ".worker-next/assets", binding = "ASSETS" } | ||
assets = { directory = ".open-next/assets", binding = "ASSETS" } | ||
|
||
[vars] | ||
hello = 'Hello World from the cloudflare context!' |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import type { OpenNextConfig } from "@opennextjs/aws/types/open-next"; | ||
vicb marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
const config: OpenNextConfig = { | ||
default: {}, | ||
|
||
middleware: { | ||
external: true, | ||
override: { | ||
wrapper: "cloudflare", | ||
converter: "edge", | ||
}, | ||
}, | ||
}; | ||
|
||
export default config; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,9 @@ | ||
#:schema node_modules/wrangler/config-schema.json | ||
name = "create-next-app" | ||
main = ".worker-next/index.mjs" | ||
main = ".open-next/index.mjs" | ||
|
||
compatibility_date = "2024-08-29" | ||
compatibility_flags = ["nodejs_compat_v2"] | ||
compatibility_date = "2024-09-23" | ||
compatibility_flags = ["nodejs_compat"] | ||
|
||
# Use the new Workers + Assets to host the static frontend files | ||
assets = { directory = ".worker-next/assets", binding = "ASSETS" } | ||
assets = { directory = ".open-next/assets", binding = "ASSETS" } |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. | ||
|
||
# dependencies | ||
/node_modules | ||
/.pnp | ||
.pnp.js | ||
.yarn/install-state.gz | ||
|
||
# testing | ||
/coverage | ||
|
||
# next.js | ||
/.next/ | ||
/out/ | ||
|
||
# production | ||
/build | ||
|
||
# misc | ||
.DS_Store | ||
*.pem | ||
|
||
# debug | ||
npm-debug.log* | ||
yarn-debug.log* | ||
yarn-error.log* | ||
|
||
# local env files | ||
.env*.local | ||
|
||
# vercel | ||
.vercel | ||
|
||
# typescript | ||
*.tsbuildinfo | ||
next-env.d.ts | ||
|
||
# playwright | ||
/test-results/ | ||
/playwright-report/ | ||
/blob-report/ | ||
/playwright/.cache/ |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,31 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||
# Middleware | ||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||
This example shows how to use [Middleware in Next.js](https://nextjs.org/docs/app/building-your-application/routing/middleware) to run code before a request is completed. | ||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||
The index page ([`app/page.tsx`](app/page.tsx)) has a list of links to pages with `redirect`, `rewrite`, or normal behavior. | ||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||
On the Middleware file ([`middleware.ts`](middleware.ts)) the routes are already being filtered by defining a `matcher` on the exported config. If you want the Middleware to run for every request, you can remove the `matcher`. | ||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||
## Deploy your own | ||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||
Deploy the example using [Vercel](https://vercel.com?utm_source=github&utm_medium=readme&utm_campaign=next-example): | ||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||
[](https://vercel.com/new/clone?repository-url=https://github.com/vercel/next.js/tree/canary/examples/middleware&project-name=middleware&repository-name=middleware) | ||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||
## How to use | ||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||
Execute [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app) with [npm](https://docs.npmjs.com/cli/init), [Yarn](https://yarnpkg.com/lang/en/docs/cli/create/), or [pnpm](https://pnpm.io) to bootstrap the example: | ||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||
```bash | ||||||||||||||||||||||||||||||||||||||||||||||||
npx create-next-app --example middleware middleware-app | ||||||||||||||||||||||||||||||||||||||||||||||||
``` | ||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||
```bash | ||||||||||||||||||||||||||||||||||||||||||||||||
yarn create next-app --example middleware middleware-app | ||||||||||||||||||||||||||||||||||||||||||||||||
``` | ||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||
```bash | ||||||||||||||||||||||||||||||||||||||||||||||||
pnpm create next-app --example middleware middleware-app | ||||||||||||||||||||||||||||||||||||||||||||||||
``` | ||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||
Deploy it to the cloud with [Vercel](https://vercel.com/new?utm_source=github&utm_medium=readme&utm_campaign=next-example) ([Documentation](https://nextjs.org/docs/deployment)). | ||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+9
to
+31
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What are the changes here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just removing the vercel specific documentation |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export default function AboutPage() { | ||
return <h1>About</h1>; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export default function About2Page() { | ||
return <h1>About 2</h1>; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export default function AnotherPage() { | ||
return <h1>Another</h1>; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import type { Metadata } from "next"; | ||
|
||
export default function RootLayout({ | ||
children, | ||
}: { | ||
children: React.ReactNode; | ||
}) { | ||
return ( | ||
<html lang="en"> | ||
<body>{children}</body> | ||
</html> | ||
); | ||
} | ||
|
||
export const metadata: Metadata = { | ||
title: "Next.js Middleware example", | ||
description: "Redirect and rewrite pages using Next.js Middleware.", | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export default function MiddlewarePage() { | ||
return <h1>Via middleware</h1>; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import Link from "next/link"; | ||
|
||
export default function Home() { | ||
return ( | ||
<div> | ||
<h1>Index</h1> | ||
<p> | ||
<Link href="/about">Go to about page (will redirect)</Link> | ||
</p> | ||
<p> | ||
<Link href="/another">Go to another page (will rewrite)</Link> | ||
</p> | ||
<p> | ||
<Link href="/about2">Go to about 2 page (no redirect or rewrite)</Link> | ||
</p> | ||
<p> | ||
<Link href="/middleware">Go to middleware page (using NextResponse.next())</Link> | ||
</p> | ||
</div> | ||
); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export default function RedirectedPage() { | ||
return <h1>Redirected from /about</h1>; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export default function RewritePage() { | ||
return <h1>Rewrite</h1>; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import { test, expect } from "@playwright/test"; | ||
|
||
test("redirect", async ({ page }) => { | ||
await page.goto("/"); | ||
await page.click('[href="/about"]'); | ||
expect(page.waitForURL("**/redirected")); | ||
expect(await page.textContent("h1")).toContain("Redirected"); | ||
}); | ||
|
||
test("rewrite", async ({ page }) => { | ||
await page.goto("/"); | ||
await page.click('[href="/another"]'); | ||
expect(page.waitForURL("**/another")); | ||
expect(await page.textContent("h1")).toContain("Rewrite"); | ||
}); | ||
|
||
test("no matching middleware", async ({ page }) => { | ||
await page.goto("/"); | ||
await page.click('[href="/about2"]'); | ||
expect(page.waitForURL("**/about2")); | ||
expect(await page.textContent("h1")).toContain("About 2"); | ||
}); | ||
|
||
test("matching noop middleware", async ({ page }) => { | ||
await page.goto("/"); | ||
await page.click('[href="/middleware"]'); | ||
expect(page.waitForURL("**/middleware")); | ||
expect(await page.textContent("h1")).toContain("Via middleware"); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
import { defineConfig, devices } from "@playwright/test"; | ||
|
||
declare const process: { env: Record<string, string> }; | ||
|
||
/** | ||
* See https://playwright.dev/docs/test-configuration. | ||
*/ | ||
export default defineConfig({ | ||
testDir: "./", | ||
/* Run tests in files in parallel */ | ||
fullyParallel: true, | ||
/* Fail the build on CI if you accidentally left test.only in the source code. */ | ||
forbidOnly: !!process.env.CI, | ||
/* Retry on CI only */ | ||
retries: process.env.CI ? 2 : 0, | ||
/* Opt out of parallel tests on CI. */ | ||
workers: process.env.CI ? 1 : undefined, | ||
/* Reporter to use. See https://playwright.dev/docs/test-reporters */ | ||
reporter: "html", | ||
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ | ||
use: { | ||
/* Base URL to use in actions like `await page.goto('/')`. */ | ||
baseURL: "http://localhost:8774", | ||
|
||
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ | ||
trace: "on-first-retry", | ||
}, | ||
|
||
/* Configure projects for major browsers */ | ||
projects: [ | ||
{ | ||
name: "chromium", | ||
use: { ...devices["Desktop Chrome"] }, | ||
}, | ||
|
||
{ | ||
name: "firefox", | ||
use: { ...devices["Desktop Firefox"] }, | ||
}, | ||
|
||
{ | ||
name: "webkit", | ||
use: { ...devices["Desktop Safari"] }, | ||
}, | ||
], | ||
|
||
/* Run your local dev server before starting the tests */ | ||
webServer: { | ||
command: "pnpm preview:worker", | ||
url: "http://localhost:8774", | ||
reuseExistingServer: !process.env.CI, | ||
}, | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import { NextRequest, NextResponse } from "next/server"; | ||
|
||
export function middleware(request: NextRequest) { | ||
console.log("middleware"); | ||
if (request.nextUrl.pathname === "/about") { | ||
return NextResponse.redirect(new URL("/redirected", request.url)); | ||
} | ||
if (request.nextUrl.pathname === "/another") { | ||
return NextResponse.rewrite(new URL("/rewrite", request.url)); | ||
} | ||
return NextResponse.next(); | ||
} | ||
|
||
export const config = { | ||
matcher: ["/about/:path*", "/another/:path*", "/middleware/:path*"], | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
/** @type {import('next').NextConfig} */ | ||
const nextConfig = {}; | ||
|
||
export default nextConfig; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import type { OpenNextConfig } from "@opennextjs/aws/types/open-next"; | ||
|
||
const config: OpenNextConfig = { | ||
default: {}, | ||
|
||
middleware: { | ||
external: true, | ||
override: { | ||
wrapper: "cloudflare", | ||
converter: "edge", | ||
}, | ||
}, | ||
}; | ||
|
||
export default config; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shall we remove
.worker-next
if it's not used anymore?