BloodyCoTech không cần một server Node chạy suốt ngày. Mỗi lần build, Next.js tạo HTML, CSS và JavaScript trong out; Cloudflare Pages chỉ việc phân phối các file đó. Cách này rẻ và dễ hiểu, đổi lại mình phải bỏ những tính năng cần xử lý request tại server.

Mình ghi lại cấu hình đã dùng và ranh giới của static export. Phần dashboard, DNS và quota có thể đổi theo thời gian, nên cuối bài luôn dẫn tài liệu Cloudflare thay vì đóng đinh một ảnh chụp màn hình.

Ba dòng làm Next.js thành site tĩnh

ts
import type { NextConfig } from "next";
 
const nextConfig: NextConfig = {
  output: "export",
  trailingSlash: true,
  images: {
    unoptimized: true,
  },
};
 
export default nextConfig;

output: "export" bảo next build ghi một file HTML cho mỗi route vào out. trailingSlash: true tạo blog/bai/index.html thay vì chỉ blog/bai.html. Host tĩnh tìm index.html trong thư mục dễ hơn là phải viết rule rewrite cho đuôi .html.

images.unoptimized tắt loader tối ưu ảnh của Next.js. Loader đó cần server. Trên Pages, ảnh trong public/ được phục vụ nguyên trạng. Hãy đặt width và height hoặc tỉ lệ khung để trang không nhảy layout. Đừng bật lại loader mặc định rồi chờ build qua.

File cấu hình thật của một dự án có thể có thêm mục khác, ví dụ loader CSS cho môi trường dev. Ba khóa ở trên là phần quyết định website có xuất tĩnh hay không.

Route động phải biết trước

Với static export, không có server để render /blog/slug-moi lúc có người ghé. generateStaticParams trả về mọi slug đã có lúc build, và dynamicParams = false để slug lạ không bị giả định là sẽ render sau. Trang 404 là file 404.html mà host trả khi không thấy đường dẫn.

Thêm bài là thêm file nội dung rồi build lại. Không có nút xuất bản tức thời nếu bạn không có CMS. Với một blog ít bài, đổi này rõ ràng hơn một pipeline động.

Việc Pages cần khi nối Git

Theo hướng dẫn static export của Cloudflare Pages, dự án Next được import từ Git với preset Next.js (Static HTML Export). Preset đó điền:

MụcGiá trị trong hướng dẫn của Cloudflare
Lệnh buildnpx next build
Thư mục đầu raout
Nhánh productionnhánh bạn chọn, thường là main

Nếu dự án dùng pnpm và có script postbuild, hãy đặt lệnh build là pnpm run build để script sau build vẫn chạy. npx next build một mình không gọi postbuild của npm/pnpm. Thư mục đầu ra vẫn là out.

Đặt Node 20 nếu dashboard không tự nhận. File .node-version hoặc .nvmrc chứa 20 là tín hiệu cho môi trường build. Không commit token. Pages lấy mã từ Git; secret nếu sau này có thì đặt trong mục biến môi trường của project, không đặt trong repo.

@cloudflare/next-on-pages là adapter cũ và không còn là hướng nên đi cho dự án mới. Website chỉ có file tĩnh thì không cần adapter đó. Nếu sản phẩm cần Server Actions hoặc render theo request, đó là mô hình khác, đọc tài liệu Next.js trên Workers hiện tại của Cloudflare thay vì gắn adapter đã ngừng bảo trì.

Những gì không chạy sau khi export

Static export bỏ các tính năng cần process Node lúc có request:

  • Server Actions và route handler phụ thuộc request.
  • Redirect và header khai báo trong next.config, vì chúng chạy trên server Next.
  • Tối ưu ảnh mặc định.
  • Middleware theo từng request.
  • Trang động không có trong generateStaticParams.

Header và redirect của chính Pages thì khác. File _headers và _redirects trong thư mục public được copy vào out, và Pages áp chúng cho response tĩnh. Redirect trong _redirects không chuyển cả tên miền. Hướng dẫn www của Cloudflare dùng Bulk Redirects cộng bản ghi DNS, không dùng một dòng domain trong _redirects. Làm theo bài Redirect www to the apex (mở tab mới) thay vì tự nghĩ một rule.

Tên miền và HTTPS

Trong project Pages, thêm custom domain là tên miền apex, ví dụ bloodycotech.com. Cloudflare cấp chứng chỉ khi domain đã trỏ đúng. Bước này nằm trên tài khoản sở hữu domain, không làm được bằng cách ghi thêm một file trong repo.

Kiểm tra sau khi nối: trang chủ mở bằng HTTPS, /sitemap.xml và /robots.txt trả nội dung, và một URL không có thật trả trang 404 của site chứ không phải một trang trống của host. Redirect từ www sang apex cần kiểm tra bằng một request thật, vì nó không nằm trong _redirects của repo.

Chọn static export từ đầu

Bài React và Next.js nói lúc nào framework này đáng dùng. Nếu bạn đã biết host chỉ nhận file, hãy bật output: "export" trước khi viết form gọi server. Viết Server Action rồi mới phát hiện Pages bản static không chạy nó sẽ buộc bạn xóa tính năng, không phải đổi một dòng cấu hình.

Đừng thêm một Node server chỉ để phục vụ blog. Quota miễn phí của Pages đủ cho một site nội dung nhỏ nếu bạn không vượt hạn mức băng thông và số lần build của gói đang dùng. Hạn mức đổi theo thời điểm; xem trang giá của Cloudflare thay vì chép một con số vào bài.

Việc nên có trong repo

  1. output: "export", trailingSlash, và images.unoptimized.
  2. Mọi route động có generateStaticParams.
  3. Lệnh build tạo được out trên máy sạch.
  4. _headers nếu bạn muốn nosniff và referrer policy, vì headers() trong Next config không chạy lúc export.
  5. Không có secret trong Git.

Năm mục đó là điều kiện để một lần bấm deploy trên Pages có cơ hội xanh. Chúng không bảo đảm tên miền đã trỏ đúng. Phần DNS vẫn là việc của người giữ tài khoản.

Tài liệu