Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@ node_modules

output
.worker-next
.save.next
.open-next
.wrangler
dist
15 changes: 15 additions & 0 deletions examples/api/open-next.config.ts
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;
2 changes: 1 addition & 1 deletion examples/api/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,5 @@
]
},
"include": ["next-env.d.ts", ".next/types/**/*.ts", "**/*.ts", "**/*.tsx", "worker-configuration.d.ts"],
"exclude": ["node_modules"]
"exclude": ["node_modules", "open-next.config.ts"]
}
8 changes: 4 additions & 4 deletions examples/api/wrangler.toml
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!'
15 changes: 15 additions & 0 deletions examples/create-next-app/open-next.config.ts
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;
2 changes: 1 addition & 1 deletion examples/create-next-app/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,5 @@
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]
"exclude": ["node_modules", "open-next.config.ts"]
}
8 changes: 4 additions & 4 deletions examples/create-next-app/wrangler.toml
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" }
42 changes: 42 additions & 0 deletions examples/middleware/.gitignore
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/
31 changes: 31 additions & 0 deletions examples/middleware/README.md
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):

[![Deploy with Vercel](https://vercel.com/button)](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)).
3 changes: 3 additions & 0 deletions examples/middleware/app/about/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function AboutPage() {
return <h1>About</h1>;
}
3 changes: 3 additions & 0 deletions examples/middleware/app/about2/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function About2Page() {
return <h1>About 2</h1>;
}
3 changes: 3 additions & 0 deletions examples/middleware/app/another/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function AnotherPage() {
return <h1>Another</h1>;
}
18 changes: 18 additions & 0 deletions examples/middleware/app/layout.tsx
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.",
};
3 changes: 3 additions & 0 deletions examples/middleware/app/middleware/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function MiddlewarePage() {
return <h1>Via middleware</h1>;
}
21 changes: 21 additions & 0 deletions examples/middleware/app/page.tsx
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>
);
}
3 changes: 3 additions & 0 deletions examples/middleware/app/redirected/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function RedirectedPage() {
return <h1>Redirected from /about</h1>;
}
3 changes: 3 additions & 0 deletions examples/middleware/app/rewrite/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function RewritePage() {
return <h1>Rewrite</h1>;
}
29 changes: 29 additions & 0 deletions examples/middleware/e2e/base.spec.ts
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");
});
53 changes: 53 additions & 0 deletions examples/middleware/e2e/playwright.config.ts
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,
},
});
16 changes: 16 additions & 0 deletions examples/middleware/middleware.ts
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*"],
};
4 changes: 4 additions & 0 deletions examples/middleware/next.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/** @type {import('next').NextConfig} */
const nextConfig = {};

export default nextConfig;
15 changes: 15 additions & 0 deletions examples/middleware/open-next.config.ts
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;
29 changes: 29 additions & 0 deletions examples/middleware/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"name": "middleware",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint",
"build:worker": "pnpm cloudflare",
"dev:worker": "wrangler dev --port 8774 --inspector-port 9334",
"preview:worker": "pnpm build:worker && pnpm dev:worker",
"e2e": "playwright test -c e2e/playwright.config.ts"
},
"dependencies": {
"next": "catalog:",
"react": "catalog:",
"react-dom": "catalog:"
},
"devDependencies": {
"@opennextjs/cloudflare": "workspace:*",
"@playwright/test": "catalog:",
"@types/node": "catalog:",
"@types/react": "catalog:",
"@types/react-dom": "catalog:",
"eslint": "catalog:",
"typescript": "catalog:",
"wrangler": "catalog:"
}
}
Binary file added examples/middleware/public/favicon.ico
Binary file not shown.
4 changes: 4 additions & 0 deletions examples/middleware/public/vercel.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading