Skip to content

Commit

Permalink
introduce new initOpenNextCloudflareForDev utility and make `getClo…
Browse files Browse the repository at this point in the history
…udflareContext` synchronous (#265)

Co-authored-by: Victor Berchet <[email protected]>
  • Loading branch information
dario-piotrowicz and vicb authored Jan 27, 2025
1 parent 4983a36 commit 8de2c04
Show file tree
Hide file tree
Showing 23 changed files with 361 additions and 206 deletions.
28 changes: 28 additions & 0 deletions .changeset/chilly-dryers-begin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
---
"@opennextjs/cloudflare": minor
---

introduce new `initOpenNextCloudflareForDev` utility and make `getCloudflareContext` synchronous

this change introduces a new `initOpenNextCloudflareForDev` function that must called in the [Next.js config file](https://nextjs.org/docs/app/api-reference/config/next-config-js) to integrate the Next.js dev server with the open-next Cloudflare adapter.

Also makes `getCloudflareContext` synchronous.

Additionally the `getCloudflareContext` can now work during local development (`next dev`) in the edge runtime (including middlewares).

Moving forward we'll recommend that all applications include the use of the `initOpenNextCloudflareForDev` utility in their config file (there is no downside in doing so and it only effect local development).

Example:

```js
// next.config.mjs

import { initOpenNextCloudflareForDev } from "@opennextjs/cloudflare";

initOpenNextCloudflareForDev();

/** @type {import('next').NextConfig} */
const nextConfig = {};

export default nextConfig;
```
5 changes: 2 additions & 3 deletions examples/api/app/api/hello/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,8 @@ export async function GET() {
return new Response("Hello World!");
}

// Retrieve the bindings defined in wrangler.toml
const { env } = await getCloudflareContext();
return new Response(env.hello);
// Retrieve the bindings defined in wrangler.json
return new Response(getCloudflareContext().env.hello);
}

export async function POST(request: Request) {
Expand Down
4 changes: 3 additions & 1 deletion examples/api/e2e/playwright.config.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { defineConfig, devices } from "@playwright/test";
import type nodeProcess from "node:process";

declare var process: { env: Record<string, string> };
declare const process: typeof nodeProcess;

/**
* See https://playwright.dev/docs/test-configuration.
Expand Down Expand Up @@ -49,5 +50,6 @@ export default defineConfig({
command: "pnpm preview:worker",
url: "http://localhost:8770",
reuseExistingServer: !process.env.CI,
timeout: 70_000,
},
});
3 changes: 2 additions & 1 deletion examples/api/e2e/playwright.dev.config.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { defineConfig, devices } from "@playwright/test";
import type nodeProcess from "node:process";

declare var process: { env: Record<string, string> };
declare const process: typeof nodeProcess;

/**
* See https://playwright.dev/docs/test-configuration.
Expand Down
4 changes: 4 additions & 0 deletions examples/api/next.config.mjs
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
import { initOpenNextCloudflareForDev } from "@opennextjs/cloudflare";

initOpenNextCloudflareForDev();

/** @type {import('next').NextConfig} */
const nextConfig = {};

Expand Down
4 changes: 3 additions & 1 deletion examples/create-next-app/e2e/playwright.config.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { defineConfig, devices } from "@playwright/test";
import type nodeProcess from "node:process";

declare const process: { env: Record<string, string> };
declare const process: typeof nodeProcess;

/**
* See https://playwright.dev/docs/test-configuration.
Expand Down Expand Up @@ -49,5 +50,6 @@ export default defineConfig({
command: "pnpm preview:worker",
url: "http://localhost:8771",
reuseExistingServer: !process.env.CI,
timeout: 70_000,
},
});
4 changes: 4 additions & 0 deletions examples/create-next-app/next.config.mjs
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
import { initOpenNextCloudflareForDev } from "@opennextjs/cloudflare";

initOpenNextCloudflareForDev();

/** @type {import('next').NextConfig} */
const nextConfig = {};

Expand Down
24 changes: 23 additions & 1 deletion examples/middleware/app/middleware/page.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,25 @@
import { headers } from "next/headers";

export default function MiddlewarePage() {
return <h1>Via middleware</h1>;
const cloudflareContextHeader = headers().get("x-cloudflare-context");

return (
<>
<h1>Via middleware</h1>
<p>
The value of the <i>x-cloudflare-context</i> header is: <br />
<span
style={{
display: "inline-block",
margin: "1rem 2rem",
color: "grey",
fontSize: "1.2rem",
}}
data-testid="cloudflare-context-header"
>
{cloudflareContextHeader}
</span>
</p>
</>
);
}
9 changes: 9 additions & 0 deletions examples/middleware/e2e/cloudflare-context.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { test, expect } from "@playwright/test";

test("middlewares have access to the cloudflare context", async ({ page }) => {
await page.goto("/middleware");
const cloudflareContextHeaderElement = page.getByTestId("cloudflare-context-header");
expect(await cloudflareContextHeaderElement.textContent()).toContain(
"typeof `cloudflareContext.env` = object"
);
});
4 changes: 3 additions & 1 deletion examples/middleware/e2e/playwright.config.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { defineConfig, devices } from "@playwright/test";
import type nodeProcess from "node:process";

declare const process: { env: Record<string, string> };
declare const process: typeof nodeProcess;

/**
* See https://playwright.dev/docs/test-configuration.
Expand Down Expand Up @@ -49,5 +50,6 @@ export default defineConfig({
command: "pnpm preview:worker",
url: "http://localhost:8774",
reuseExistingServer: !process.env.CI,
timeout: 70_000,
},
});
54 changes: 54 additions & 0 deletions examples/middleware/e2e/playwright.dev.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { defineConfig, devices } from "@playwright/test";
import type nodeProcess from "node:process";

declare const process: typeof nodeProcess;

/**
* 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:3334",

/* 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 dev --port 3334",
url: "http://localhost:3334",
reuseExistingServer: !process.env.CI,
},
});
16 changes: 15 additions & 1 deletion examples/middleware/middleware.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { NextRequest, NextResponse, NextFetchEvent } from "next/server";
import { clerkMiddleware } from "@clerk/nextjs/server";

import { getCloudflareContext } from "@opennextjs/cloudflare";

export function middleware(request: NextRequest, event: NextFetchEvent) {
console.log("middleware");
if (request.nextUrl.pathname === "/about") {
Expand All @@ -16,7 +18,19 @@ export function middleware(request: NextRequest, event: NextFetchEvent) {
})(request, event);
}

return NextResponse.next();
const requestHeaders = new Headers(request.headers);
const cloudflareContext = getCloudflareContext();

requestHeaders.set(
"x-cloudflare-context",
`typeof \`cloudflareContext.env\` = ${typeof cloudflareContext.env}`
);

return NextResponse.next({
request: {
headers: requestHeaders,
},
});
}

export const config = {
Expand Down
4 changes: 4 additions & 0 deletions examples/middleware/next.config.mjs
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
import { initOpenNextCloudflareForDev } from "@opennextjs/cloudflare";

initOpenNextCloudflareForDev();

/** @type {import('next').NextConfig} */
const nextConfig = {};

Expand Down
3 changes: 2 additions & 1 deletion examples/middleware/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
"build:worker": "pnpm opennextjs-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"
"e2e": "playwright test -c e2e/playwright.config.ts",
"e2e:dev": "playwright test -c e2e/playwright.dev.config.ts"
},
"dependencies": {
"@clerk/nextjs": "6.9.6",
Expand Down
6 changes: 5 additions & 1 deletion examples/middleware/wrangler.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,9 @@
"assets": {
"directory": ".open-next/assets",
"binding": "ASSETS"
}
},
"vars": {
"MY_VAR": "my-var"
},
"kv_namespaces": [{ "binding": "MY_KV", "id": "<id>" }]
}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"prettier:fix": "prettier --write .",
"lint:check": "pnpm -r lint:check",
"lint:fix": "pnpm -r lint:fix",
"fix": "pnpm prettier:fix && pnpm lint:fix",
"ts:check": "pnpm -r ts:check",
"test": "pnpm -r test",
"code:checks": "pnpm prettier:check && pnpm lint:check && pnpm ts:check",
Expand Down
67 changes: 1 addition & 66 deletions packages/cloudflare/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,72 +6,7 @@ Deploy Next.js apps to Cloudflare!

## Get started

You can use [`create-next-app`](https://nextjs.org/docs/pages/api-reference/cli/create-next-app) to start a new application or take an existing Next.js application and deploy it to Cloudflare using the following few steps:

## Configure your app

- add the following `devDependencies` to the `package.json`:

```bash
npm add -D wrangler@latest @opennextjs/cloudflare
# or
pnpm add -D wrangler@latest @opennextjs/cloudflare
# or
yarn add -D wrangler@latest @opennextjs/cloudflare
# or
bun add -D wrangler@latest @opennextjs/cloudflare
```

- add a `wrangler.json` at the root of your project

```json
{
"$schema": "node_modules/wrangler/config-schema.json",
"main": ".open-next/worker.js",
"name": "<your-app-name>",
"compatibility_date": "2024-12-30",
"compatibility_flags": ["nodejs_compat"],
"assets": {
"directory": ".open-next/assets",
"binding": "ASSETS"
}
}
```

- add a `open-next.config.ts` at the root of your project:

```ts
import type { OpenNextConfig } from "open-next/types/open-next";

const config: OpenNextConfig = {
default: {
override: {
wrapper: "cloudflare-node",
converter: "edge",
// Unused implementation
incrementalCache: "dummy",
tagCache: "dummy",
queue: "dummy",
},
},

middleware: {
external: true,
override: {
wrapper: "cloudflare-edge",
converter: "edge",
proxyExternalRequest: "fetch",
},
},
};

export default config;
```

## Known issues

- `▲ [WARNING] Suspicious assignment to defined constant "process.env.NODE_ENV" [assign-to-define]` can safely be ignored
- Maybe more, still experimental...
To get started with the adapter visit the [official get started documentation](https://opennext.js.org/cloudflare/get-started).

## Local development

Expand Down
Loading

0 comments on commit 8de2c04

Please sign in to comment.