Pages 與 Static Assets 總覽:全端託管選型 | Cloudflare 完整教學
這一篇要幫你把 Cloudflare 的「前端與全端託管」講清楚。你可能聽過 Cloudflare Pages,也聽過比較新的 Workers Static Assets——它們都能把你的網站放上 Cloudflare 全球網路,但定位不同、官方態度也不同。這篇不鑽細節,而是先建立一張「地圖」:兩者各是什麼、差在哪、官方為何主推 Workers、Pages Functions 與一般 Worker 的分別,以及你該怎麼選、既有專案怎麼遷移。這是 CF-6 全端與周邊系列的開場總覽,細節留給接下來的文章。
前言
上一篇《Agents SDK:即時 WebSocket 與 React》,我們讓 Agent「活了起來」——做出一個逐字浮現的即時聊天前端,還把 React 打包後的靜態資源用 assets 綁定放上線。那時我們其實已經偷偷用到了本篇的主角:Workers Static Assets。這一篇,就把「靜態託管」這件事攤開來好好講。
先說一個很多人會踩到的困惑:我要把一個 React、Vue、Astro 或純 HTML 的網站放上 Cloudflare,到底該用什麼?搜尋一下你會看到兩個名字——Cloudflare Pages 和 Workers Static Assets。它們看起來都在做同一件事(託管前端),但你如果隨便選一個,可能會走進一條「官方已經不再積極維護」的路,或是把簡單的事搞複雜。所以在動手之前,先弄懂這張地圖非常值得。
先給一句話定義:
Cloudflare Pages 是較早推出的 JAMstack 靜態網站託管平台,主打 Git 自動部署與預覽環境;Workers Static Assets 則是後來讓 Cloudflare Worker「同時托管靜態資源與動態邏輯」的能力。2025 年後 Cloudflare 官方明確表態:Pages 進入維護模式(持續支援但不再積極開發新功能),所有新的投資都放在 Workers,新專案一律建議使用 Workers Static Assets。
這裡有幾個關鍵詞先埋下伏筆。JAMstack——JavaScript、API、Markup 的縮寫,指的是「前端建置成靜態檔案 + 透過 API 取得動態資料」的架構風格,這是 Pages 誕生時的定位。Static Assets——就是你的網站建置後產出的那一堆靜態檔案(HTML、CSS、JS、圖片)。維護模式——不是「淘汰下線」,而是「還會養、但不再長新功能」。
打個比方會更好懂。你可以把 Cloudflare Pages 想成一台「專門烤吐司的烤麵包機」:插電、放吐司、按下去,簡單好用,做靜態網站這件事它做得很順。而 Workers Static Assets 則像一台「多功能烤箱」:它一樣能烤吐司(純靜態託管),但你需要的時候還能烤雞、燉菜、做甜點(動態 API、WebSocket、排程、資料庫)。過去 Cloudflare 賣兩台機器,現在他們決定:未來只認真升級那台多功能烤箱,烤麵包機還能用,但不會再出新型號了。所以新廚房該買哪一台,答案很清楚。
讀完這篇你會掌握:
- Cloudflare Pages 是什麼——它的核心特色(Git 部署、預覽環境、Pages Functions)與適用場景。
- Workers Static Assets 是什麼——它怎麼用一個 Worker 同時扛靜態與動態,以及
assets綁定的角色。 - 官方方向與選型——為什麼 Pages 進入維護模式、新專案該選什麼、既有專案要不要遷移。
- Pages Functions vs 一般 Worker——兩者的路由模型與能力差異,別再搞混。
核心概念
一、Cloudflare Pages:JAMstack 靜態託管平台
Cloudflare Pages 是 Cloudflare 推出較早的前端託管平台,主打「連上 Git、推程式碼就自動部署」的體驗。它最受歡迎的幾個特色是:
- Git 整合(Git Integration)——連接 GitHub 或 GitLab,每次 push 自動觸發建置與部署,不用手動上傳。
- 預覽部署(Preview Deployments)——每個 branch 或 Pull Request 自動產生唯一的預覽 URL(格式
<branch>.<project>.pages.dev),讓你在合併前先看效果。 - Pages Functions——在 Workers 執行環境上跑的 serverless 函式,讓靜態網站也能有後端 API,支援 KV、D1、R2 等綁定(bindings)。
- 即時回滾(Instant Rollback)——一鍵還原到任意歷史版本。
- 全球 CDN——靜態資源自動分發到 Cloudflare 全球 300 多個資料中心。
這些能力讓 Pages 一度是 Cloudflare 上做前端的首選。它把「靜態網站 + 少量後端」這條路走得很順。
二、Workers Static Assets:一個 Worker 扛全部
Workers Static Assets 是後來 Cloudflare 幫 Worker 加上的能力:讓一個 Worker 同時托管靜態資源與動態邏輯。過去你需要 Pages 才能做到的「靜態網站託管」,現在直接寫在 Worker 的設定裡就有了。
它的運作原理是這樣的:
- 你把建置好的靜態資源(HTML、CSS、JS、圖片)透過
wrangler.jsonc裡的assets.directory指定目錄,部署時一起上傳到 Cloudflare 的資源儲存系統。 - Cloudflare 自動快取這些資源,並在全球邊緣節點提供(自動壓縮、附 ETag)。
- 你的 Worker 程式碼可以透過
env.ASSETS這個綁定去存取這些資源。 - 透過
run_worker_first設定,你可以決定哪些路由「先進 Worker 處理」、哪些「直接回靜態檔案」。
一張圖看懂請求怎麼走:
Request 進入
↓
是否符合 run_worker_first 設定?
├─ 是 → 執行 Worker → Worker 可呼叫 env.ASSETS.fetch() 取得靜態資源
└─ 否 → 直接查找靜態資源
├─ 找到 → 回傳靜態資源(自動壓縮、快取)
└─ 找不到 → 依 not_found_handling 設定處理(SPA 回 index.html / 404 頁 / 直接 404)
關鍵是:如果你不需要後端,連 Worker 程式碼都不用寫——只設定 assets.directory 就是一個純靜態網站。而當你需要 API 時,補上一個 Worker 入口就升級成全端應用,不用換平台。
三、Pages vs Workers Static Assets 對照表
這是本篇最該記住的一張表。除了功能差異,最上面兩列「維護狀態」與「建議用途」是官方態度的核心:
| 面向 | Cloudflare Pages | Workers Static Assets |
|---|---|---|
| 維護狀態 | 持續支援,但不再積極開發新功能 | 主要投資方向 |
| 建議用途 | 既有 Pages 專案 | 所有新專案 |
| Git 整合部署 | 原生支援 | Workers Builds |
| 預覽部署 URL | 支援 | Workers Builds |
| 靜態資源托管 | 支援 | 支援 |
| Serverless 函式 | Pages Functions | 原生 Worker |
| Durable Objects | 不支援 | 支援 |
| Cron Triggers | 不支援 | 支援 |
| Queue Consumers | 不支援 | 支援 |
| WebSocket | 僅限 Advanced Mode | 原生支援 |
| Gradual Deployments | 不支援 | 支援 |
| 進階 Observability | 有限 | 完整 |
看出重點了嗎?凡是「綁在 Worker 上的進階能力」(Durable Objects、Cron、Queue、原生 WebSocket),Pages 幾乎都沒有,而 Workers Static Assets 全都有。 這正是官方把資源集中到 Workers 的原因——與其維護兩套,不如讓 Workers 一套通吃。
四、官方方向:為什麼 Pages 進入維護模式
2025 年初,Cloudflare 官方部落格說了一句很關鍵的話:
“Cloudflare Pages will continue to be supported, but, going forward, all of our investment, optimizations, and feature work will be dedicated to improving Workers.”
翻成白話:Pages 會繼續支援,但往後所有的投資、優化與新功能開發,都會投注在改進 Workers 上。 這句話拆開來理解:
- Pages 不會下線,現有專案不受影響,照常運作、照常部署。
- 新功能、效能優化、框架整合的重心已全部轉移到 Workers Static Assets。
- 過去 Pages 獨有的優勢(靜態託管、SSR、Git 部署、預覽環境)Workers 現在都有了——差異化消失,自然收斂到一套。
- 官方明確建議:新專案一律優先考慮 Workers,而非 Pages。
五、Pages Functions vs 一般 Worker:別再搞混
這是最多人混淆的一點。兩者都跑在 Workers 執行環境上,但寫法與能力不同:
| 面向 | Pages Functions | 一般 Worker(Workers Static Assets) |
|---|---|---|
| 路由模型 | 基於檔案(functions/ 目錄對應 URL) | 單一入口(export default { fetch }),路由自己分派 |
| Handler 寫法 | onRequestGet / onRequestPost 等 | 一個 fetch(request, env, ctx) 統包 |
| 中介層 | _middleware.ts | 自己在 fetch 內組合 |
| 進階能力 | 受限(WebSocket 需 Advanced Mode) | 完整(DO、Cron、Queue、WebSocket 原生) |
| 靜態資源存取 | 自動回退 | 透過 env.ASSETS 綁定 |
一句話總結:Pages Functions 是「Pages 平台幫你包裝好的 Worker」,用檔案路由、方便但受限;一般 Worker 是「完整體」,單一入口、自己掌控路由、能力最全。 官方主推的 Workers Static Assets 用的就是後者。
實作範例
光看表格不夠實感,我們用「同一個目標:把一個 React SPA + 一個 /api 後端放上線」來對照兩種做法的最小設定。你會直接感受到差別。
1. 純靜態:Workers Static Assets 最簡設定
先看最單純的:一個沒有後端的純靜態網站。這是新專案最該優先掌握的起手式——連 Worker 程式碼都不用寫:
// wrangler.jsonc — 純靜態,零 Worker 程式碼
{
"name": "my-static-site",
"compatibility_date": "2026-01-01",
"assets": {
"directory": "./dist" // 指向建置輸出目錄即可
}
}
# 建置你的前端(以 Vite 為例),然後部署
npm run build
npx wrangler deploy
# ↑ 上線後所有請求直接由邊緣節點提供靜態檔案,不計入 Worker 調用次數
就這樣。沒有 main 入口、沒有 Worker 程式碼,Cloudflare 自動幫你壓縮、快取、附 ETag。
2. 全端:Workers Static Assets + Worker 後端
現在加上一個 /api 後端。只要補上 main 入口與 run_worker_first,同一個專案就升級成全端應用:
// wrangler.jsonc — SPA + API 全端設定
{
"name": "my-app",
"main": "src/index.ts", // 補上 Worker 入口
"compatibility_date": "2026-01-01",
"assets": {
"directory": "./dist",
"not_found_handling": "single-page-application", // 找不到就回 index.html(SPA)
"run_worker_first": ["/api/*"] // 只有 /api/* 先進 Worker,其餘直接回靜態
},
"d1_databases": [
{ "binding": "DB", "database_id": "your-db-id" }
]
}
// src/index.ts — Worker 入口:API 自己處理,其餘交給 ASSETS
interface Env {
ASSETS: Fetcher;
DB: D1Database;
}
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const url = new URL(request.url);
// API 路由由 Worker 處理
if (url.pathname.startsWith("/api/")) {
const { results } = await env.DB.prepare("SELECT * FROM users").all();
return Response.json(results);
}
// 其餘路由交給靜態資源(SPA 模式下找不到會回 index.html)
return env.ASSETS.fetch(request);
},
};
注意 run_worker_first: ["/api/*"] 這個設定的巧妙:只有 /api/* 的請求會先進 Worker(產生調用計費),其他所有靜態檔案的請求直接由邊緣提供、不進 Worker——這對成本控制很重要。
3. 對照:Pages 的做法(既有專案的樣子)
同樣的目標,如果是在 Pages 上,設定與程式碼組織會長這樣——放這裡是為了讓你認得既有 Pages 專案的樣貌:
// wrangler.jsonc — Pages 專用:注意 pages_build_output_dir
{
"name": "my-pages-project",
"pages_build_output_dir": "./dist", // Pages 專屬欄位(不是 assets)
"compatibility_date": "2026-01-01"
}
// functions/api/users.ts — Pages Functions:檔名即路由,對應 /api/users
import type { PagesFunction } from "@cloudflare/workers-types";
interface Env {
DB: D1Database;
}
// 檔案路由 + onRequestGet handler,這是 Pages Functions 的招牌寫法
export const onRequestGet: PagesFunction<Env> = async ({ env }) => {
const { results } = await env.DB.prepare("SELECT * FROM users").all();
return Response.json(results);
};
對照著看差別就很清楚:Pages 用 pages_build_output_dir 而非 assets、用 functions/ 檔案路由而非單一 fetch 入口。這也是遷移的核心:把 pages_build_output_dir 換成 assets.directory、把 functions/ 目錄的邏輯改寫進 Worker 的 fetch。 遷移的完整步驟,我們留到後面幾篇細講。
4. not_found_handling:三種模式一次看
上面用到的 not_found_handling 決定「找不到靜態資源時怎麼辦」,這是靜態託管最常用的設定:
| 模式 | 行為 | 適用場景 |
|---|---|---|
"single-page-application" | 所有非資源路徑回 /index.html(HTTP 200) | React / Vue / Angular SPA |
"404-page" | 若有 /404.html 就回它,否則 404 | 靜態網站(SSG,有自訂錯誤頁) |
"none" | 直接回 404 | API 優先、完全自訂路由 |
SPA 一定要用 single-page-application,不然重新整理子路由(例如 /dashboard)就會 404;純靜態部落格(Hugo、Astro SSG)則用 404-page。
常見錯誤與最佳實踐
託管選型的坑,大多不在「部署失敗」,而在「一開始選錯路」或「把兩個概念搞混」。以下是最高頻的幾個。
坑一:新專案還在預設選 Pages。
很多教學、範本還停在「用 Pages 做前端」的舊思維,於是新專案一開就選了進入維護模式的平台。正確做法:2025 年後的所有新專案,一律從 Workers Static Assets 起手。 就算你現在只做純靜態網站(用不到 DO、Cron),也該選 Workers——因為它純靜態一樣簡單(三行設定),而且哪天需要長出後端 API 時,補個 main 入口就能無痛升級,不必搬家換平台。一句話:新專案沒有理由選 Pages。
坑二:把 Pages Functions 當成「一般 Worker」,期待它有 Worker 的全部能力。
有人在 Pages Functions 裡想用 Durable Objects、Cron Triggers、原生 WebSocket,結果發現做不到(或得繞 Advanced Mode 的 _worker.js)。正確做法:認清 Pages Functions 是「受平台約束的 Worker」——檔案路由方便,但進階能力受限。 需要那些能力,就直接用 Workers Static Assets 的「一般 Worker」模型。別在 Pages 上硬湊。
坑三:所有請求都設 run_worker_first: true,白白燒 Worker 調用次數。
有人為了省事,把 run_worker_first 設成布林 true,結果連載入圖片、CSS、JS 都先進 Worker,每個靜態請求都算一次 Worker 調用,成本暴增、延遲也上升。正確做法:用陣列模式,只讓真正需要後端的路由先進 Worker(例如 ["/api/*", "/auth/*"]),其餘靜態資源直接由邊緣提供、不計入調用次數。需要排除某些子路徑時,用 ! 前綴(例如 "!/api/docs/*")。
坑四:既有 Pages 專案急著全部遷移。
聽到「Pages 進入維護模式」就恐慌,把運作良好的舊專案全部連夜搬到 Workers——這既沒必要、又容易出錯。正確做法:Pages 不會下線,現有專案照常維護即可,不急於遷移。 真正該遷移的時機是:(1) 你要開新專案;(2) 你的 Pages 專案「撞到能力天花板」(需要 DO、Cron、Queue、原生 WebSocket)。時機到了再遷,而且要按部就班測試。
選型建議小結(一句話決策):
- 開新專案 → 一律 Workers Static Assets(純靜態就只設
assets.directory,要後端再加main)。 - 現有 Pages 專案運作正常 → 留著別動,繼續維護。
- 現有 Pages 撞到能力天花板 → 規劃遷移到 Workers(
pages_build_output_dir→assets.directory,functions/→ Worker)。 - 搞不清 Pages Functions 還是 Worker → 新專案直接用一般 Worker,能力最完整、最不綁死。
小結
上一篇《Agents SDK:即時 WebSocket 與 React》,我們做出了逐字浮現的即時聊天前端,並用 assets 綁定把 React 前端放上線——那其實已經在用本篇的主角。這一篇《Pages 與 Static Assets 總覽》,我們把 Cloudflare 的前端與全端託管地圖攤開來看:
- Cloudflare Pages——較早的 JAMstack 靜態託管平台,主打 Git 部署、預覽環境、Pages Functions;現已進入維護模式(持續支援但不再積極開發新功能)。
- Workers Static Assets——讓一個 Worker 同時扛靜態與動態;純靜態只需設
assets.directory,要後端補上main與run_worker_first即可無痛升級,是官方主推、所有新專案的預設選擇。 - Pages Functions vs 一般 Worker——前者是「平台包裝好的 Worker」(檔案路由、能力受限),後者是「完整體」(單一入口、能力全);Workers Static Assets 用的是後者。
- 選型與遷移——新專案一律 Workers;既有 Pages 專案不急遷移,撞到能力天花板再搬(
pages_build_output_dir→assets.directory)。
這也是 CF-6 全端與周邊系列的開場——我們把視角從單一功能(AI、儲存、運算)拉高到「怎麼把一個完整的前端與全端應用漂亮地放上 Cloudflare」。下一篇《Workers Static Assets 靜態託管》,我們就把今天總覽帶過的 Workers Static Assets 拆開來實作:assets 的完整選項、html_handling 的 URL 斜線行為、.assetsignore 排除檔、Vite Plugin 整合,一步步把一個靜態網站(以及它未來可能長出的後端)紮實地部署上線。我們下一篇見。
想查閱 Cloudflare 官方對 Pages 與 Workers Static Assets 定位的完整說明與最新設定選項,可以參考 Cloudflare Workers Static Assets 官方文件(設定欄位與官方建議以當下官方文件為準)。