OpenNext Adapter cho Cloudflare¶
OpenNext là gì?¶
OpenNext là adapter cho phép deploy Next.js lên các platforms khác ngoài Vercel.
┌─────────────────────────────────────────────────────────────┐
│ Next.js Application │
└───────────────────────────┬─────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ OpenNext Adapter │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Server │ │ Image │ │ Cache │ │
│ │ Handler │ │ Handler │ │ Handler │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└───────────────────────────┬─────────────────────────────────┘
│
┌─────────────────┼─────────────────┐
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ AWS │ │Cloudflare│ │ Netlify │
│ Lambda │ │ Workers │ │Functions │
└──────────┘ └──────────┘ └──────────┘
Cài đặt @opennextjs/cloudflare¶
Step 1: Install package¶
Step 2: Tạo file cấu hình¶
// open-next.config.ts
import type { OpenNextConfig } from '@opennextjs/cloudflare';
const config: OpenNextConfig = {
default: {
override: {
wrapper: 'cloudflare-node',
converter: 'edge',
incrementalCache: 'dummy',
tagCache: 'dummy',
queue: 'dummy',
},
},
middleware: {
external: true,
override: {
wrapper: 'cloudflare-edge',
converter: 'edge',
proxyExternalRequest: 'fetch',
},
},
};
export default config;
Cấu hình Wrangler¶
wrangler.toml¶
#:schema node_modules/wrangler/config-schema.json
name = "my-nextjs-app"
main = ".open-next/worker.js"
compatibility_date = "2024-09-23"
compatibility_flags = ["nodejs_compat"]
# Assets (static files)
[assets]
directory = ".open-next/assets"
binding = "ASSETS"
# KV Namespace (optional - for caching)
[[kv_namespaces]]
binding = "NEXT_CACHE_WORKERS_KV"
id = "your-kv-namespace-id"
# Environment variables
[vars]
NEXT_PUBLIC_API_URL = "https://api.example.com"
# Secrets (set via CLI)
# wrangler secret put SUPABASE_SERVICE_KEY
Cấu hình next.config.js¶
// next.config.js
import { setupDevPlatform } from '@cloudflare/next-on-pages/next-dev';
/** @type {import('next').NextConfig} */
const nextConfig = {
// Bắt buộc cho Cloudflare
output: 'standalone',
// Experimental features for edge
experimental: {
// Enable if needed
},
// Image optimization
images: {
loader: 'custom',
loaderFile: './lib/image-loader.ts',
},
};
// Enable Cloudflare bindings in development
if (process.env.NODE_ENV === 'development') {
await setupDevPlatform();
}
export default nextConfig;
Build Process¶
Package.json scripts¶
{
"scripts": {
"dev": "next dev",
"build": "next build",
"build:worker": "opennextjs-cloudflare",
"preview": "wrangler dev",
"deploy": "wrangler deploy",
"deploy:staging": "wrangler deploy --env staging",
"deploy:production": "wrangler deploy --env production"
}
}
Build steps¶
# 1. Build Next.js
npm run build
# 2. Build OpenNext (creates .open-next folder)
npm run build:worker
# 3. Preview locally
npm run preview
# 4. Deploy to Cloudflare
npm run deploy
Thư mục .open-next¶
Sau khi build, OpenNext tạo:
.open-next/
├── worker.js # Main worker entry
├── assets/ # Static files (CSS, JS, images)
│ ├── _next/
│ │ ├── static/
│ │ └── ...
│ └── ...
├── cache/ # Build cache
└── server-functions/ # Server handlers
└── default/
└── index.mjs
Cloudflare Bindings trong Next.js¶
Truy cập bindings¶
// app/api/example/route.ts
import { getRequestContext } from '@cloudflare/next-on-pages';
export const runtime = 'edge';
export async function GET() {
// Lấy Cloudflare context
const { env, ctx } = getRequestContext();
// Sử dụng KV
const cached = await env.MY_KV.get('key');
// Sử dụng Queue
await env.MY_QUEUE.send({ data: 'test' });
// Sử dụng R2
const object = await env.MY_R2.get('file.txt');
return Response.json({ cached });
}
Type definitions¶
// env.d.ts
interface CloudflareEnv {
MY_KV: KVNamespace;
MY_QUEUE: Queue<QueueMessage>;
MY_R2: R2Bucket;
SUPABASE_URL: string;
SUPABASE_ANON_KEY: string;
}
declare module '@cloudflare/next-on-pages' {
export function getRequestContext(): {
env: CloudflareEnv;
ctx: ExecutionContext;
};
}
Local Development¶
Option 1: wrangler dev (recommended)¶
Option 2: next dev với mock bindings¶
// lib/get-env.ts
import { getRequestContext } from '@cloudflare/next-on-pages';
export function getCloudflareEnv() {
if (process.env.NODE_ENV === 'development') {
// Mock bindings for development
return {
MY_KV: createMockKV(),
MY_QUEUE: createMockQueue(),
};
}
return getRequestContext().env;
}
Troubleshooting¶
Lỗi thường gặp¶
1. Module not found
→ Package không compatible với Edge. Tìm alternative.
2. Memory exceeded
→ Giảm payload size, dùng streaming.
3. Timeout
→ Offload to Queue hoặc Supabase Edge Function.
4. Build fails
# Clear cache và rebuild
rm -rf .next .open-next node_modules/.cache
npm run build && npm run build:worker
Hands-on Exercise¶
Setup dự án mới¶
# 1. Create Next.js app
npx create-next-app@latest my-app --typescript --tailwind --app
# 2. Install dependencies
cd my-app
npm install @opennextjs/cloudflare
# 3. Create config files
# (copy các file config từ slides)
# 4. Build và test
npm run build
npm run build:worker
npm run preview
# 5. Visit http://localhost:8787
Tổng kết¶
Setup Checklist¶
- [ ] Install
@opennextjs/cloudflare - [ ] Create
open-next.config.ts - [ ] Configure
wrangler.toml - [ ] Update
next.config.jsvớioutput: 'standalone' - [ ] Add build scripts to
package.json - [ ] Create type definitions for bindings
Key Files¶
project/
├── open-next.config.ts # OpenNext config
├── wrangler.toml # Cloudflare config
├── next.config.js # Next.js config
├── env.d.ts # Type definitions
└── .open-next/ # Build output
Q&A¶
- Có vấn đề gì khi setup không?
- Package nào cần thay thế trong dự án của bạn?
- Cần bindings nào (KV, Queue, R2)?