Skip to content
Merged
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
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@

All notable changes to Wallpect are recorded in this file. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the project uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## Unreleased

### Changed

- Migrated the deployment configuration from Cloudflare Pages to assets-only Workers Static Assets with explicit SPA fallback and preview deployments.
- Pinned Wrangler and added local validation, preview, and deployment commands.
- Added immutable caching for fingerprinted JavaScript and CSS while keeping the service worker revalidated.

## 0.1.0 - 2026-07-16

### Added
Expand Down
110 changes: 93 additions & 17 deletions docs/DEPLOYMENT.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Cloudflare Pages 部署指南 / Deployment Guide
# Cloudflare Workers Static Assets 部署指南 / Deployment Guide

## 中文

Expand All @@ -8,34 +8,70 @@
Project: wallpect
Production branch: main
Build command: npm run build
Output directory: dist
Deploy command: npx wrangler deploy
Non-production branch deploy command: npx wrangler versions upload
Node.js: 22 或以上版本
```

Repository 亦包含 `wrangler.toml`、`public/_headers` 與正式版本的 service worker。Vite 會為 JS/CSS 資源加入 hash;Cloudflare 應長期快取這些不可變資源,同時讓 `index.html` 保持較短的快取時間。
Wallpect 使用 Workers Static Assets 的純靜態模式。`wrangler.toml` 不包含 `main` 或 `ASSETS` binding,因此請求不會執行 Worker script;圖片仍然只會在瀏覽器內解碼、預覽及匯出。`assets.not_found_handling` 明確設定為 `single-page-application`,讓非檔案導覽路徑回傳 `index.html`。

Repository 亦包含鎖定版本的 Wrangler、`public/_headers` 與正式版本的 service worker。Vite 會為 JS/CSS 資源加入 hash;`_headers` 會長期快取這些不可變資源,同時讓 `index.html` 保持重新驗證,並避免長期快取 `sw.js`。

本機驗證 Workers 靜態資源設定:

```bash
npm run build
npm run worker:check
```

在 Workers runtime 本機預覽:

```bash
npm run build
npm run worker:dev
```

### 網域

建議對應:

- `main` → `wallpect.k-y.cc`
- 預覽部署 → Cloudflare Pages 預覽 URL
- 可選的 `develop` branch → `dev.wallpect.k-y.cc`
- `main` → `wallpect.k-y.cc/*` Workers route
- 非 production branch → Workers Preview URL
- 可選的 `develop` branch → 獨立 preview 或 staging Worker

Pages 專案建立後,必須在 Cloudflare dashboard 加入自訂網域。DNS 與正式部署屬於外部操作,不會由本機建置執行。
`wrangler.toml` 以 zone route 將 `wallpect.k-y.cc/*` 導向 Worker。現有 Pages custom domain 與 DNS 會保留作 origin 及 rollback;如要回復 Pages,可先在 Cloudflare dashboard 移除該 Worker route。確認 Workers 正式流量及 rollback 流程穩定之前,不要刪除原有 Pages project。

如日後要完全移除 Pages,可先解除 Pages custom domain 及其 CNAME,再將 route 改成 Workers Custom Domain。Custom Domain 不能與現有 CNAME 同時建立,因此唔應在同一次未驗證操作內完成。

Workers Builds 設定:

1. 連接 GitHub repository;
2. Production branch 設為 `main`;
3. Build command 設為 `npm run build`;
4. Deploy command 使用 Workers Builds 預設的 `npx wrangler deploy`;
5. 開啟 non-production branch builds,並使用預設的 `npx wrangler versions upload` 建立不影響正式流量的 preview version。

Cloudflare 會使用 `package.json` 鎖定的 Wrangler 版本;本機仍可使用 `npm run worker:deploy` 與 `npm run worker:preview` 作為相同命令的簡寫。

### 安全 header

`public/_headers` 會設定 CSP、`nosniff`、referrer policy、permissions policysame-origin opener policy。CSP 刻意只允許同源 scripts/styles,以及本機圖片處理與下載所需的 `blob:` 圖片/worker。收緊設定後,必須重新測試 Canvas 匯出與 service worker。
Workers Static Assets 會直接讀取 `public/_headers` 建置後的 `dist/_headers`。它會設定 CSP、`nosniff`、referrer policy、permissions policysame-origin opener policy 與快取規則。CSP 刻意只允許同源 scripts/styles,以及本機圖片處理與下載所需的 `blob:` 圖片/worker。收緊設定後,必須重新測試 Canvas 匯出與 service worker。

### 發佈檢查

```bash
npm ci
npm run check
npm run worker:check
npm run test:e2e
```

針對已部署的 preview 或正式 URL 執行瀏覽器矩陣:

```bash
PLAYWRIGHT_BASE_URL=https://<preview-url> npm run test:e2e
```

然後在已部署 URL 驗證:

1. 首次開啟預設顯示繁體中文,並可切換簡體中文與英文;
Expand All @@ -44,7 +80,9 @@ npm run test:e2e
4. iPhone、iPad 與 Mac 設定檔可正確切換;
5. PNG/JPEG/WebP 下載具有設定檔指定的精確尺寸;
6. 桌面與流動版版面沒有水平溢出;
7. 安全 header 已正確提供。
7. 非檔案導覽路徑會回傳 SPA shell;
8. 安全與快取 header 已正確提供;
9. hashed JS/CSS 使用 immutable cache,而 `sw.js` 仍會重新驗證。

## English

Expand All @@ -54,34 +92,70 @@ npm run test:e2e
Project: wallpect
Production branch: main
Build command: npm run build
Output directory: dist
Deploy command: npx wrangler deploy
Non-production branch deploy command: npx wrangler versions upload
Node.js: 22 or newer
```

The repository also includes `wrangler.toml`, `public/_headers`, and a production service worker. Vite hashes JS/CSS assets; Cloudflare should cache those immutable assets while keeping `index.html` short-lived.
Wallpect uses the assets-only Workers Static Assets mode. `wrangler.toml` has no `main` entry or `ASSETS` binding, so requests do not invoke a Worker script; images remain decoded, previewed, and exported only in the browser. `assets.not_found_handling` is explicitly set to `single-page-application`, so navigation paths that do not match files receive `index.html`.

The repository also includes a pinned Wrangler version, `public/_headers`, and a production service worker. Vite hashes JS/CSS assets; `_headers` caches those immutable assets for the long term while leaving `index.html` revalidated and preventing long-lived caching of `sw.js`.

Validate the Workers static assets configuration locally:

```bash
npm run build
npm run worker:check
```

Preview with the Workers runtime locally:

```bash
npm run build
npm run worker:dev
```

### Domains

Suggested mappings:

- `main` → `wallpect.k-y.cc`
- preview deploymentsCloudflare Pages preview URLs
- optional `develop` branch → `dev.wallpect.k-y.cc`
- `main` → the `wallpect.k-y.cc/*` Workers route
- non-production branchesWorkers Preview URLs
- optional `develop` branch → a dedicated preview or staging Worker

Custom domains must be added in the Cloudflare dashboard after the Pages project exists. DNS and production deployment are external operations and are not performed by the local build.
`wrangler.toml` maps the `wallpect.k-y.cc/*` zone route to the Worker. The existing Pages custom domain and DNS remain in place as the origin and rollback path; to restore Pages, first remove this Worker route in the Cloudflare dashboard. Do not delete the Pages project until Workers production traffic and rollback have been confirmed stable.

To remove Pages completely later, detach its custom domain and CNAME before replacing the route with a Workers Custom Domain. A Custom Domain cannot be created while that CNAME exists, so these changes should not be combined into the initial, unverified cutover.

Workers Builds settings:

1. Connect the GitHub repository.
2. Set the production branch to `main`.
3. Set the build command to `npm run build`.
4. Keep the Workers Builds default deploy command, `npx wrangler deploy`.
5. Enable non-production branch builds and keep the default `npx wrangler versions upload` command to create preview versions without affecting production traffic.

Cloudflare uses the Wrangler version pinned in `package.json`; `npm run worker:deploy` and `npm run worker:preview` remain available as equivalent local aliases.

### Security headers

`public/_headers` sets CSP, `nosniff`, referrer policy, permissions policy, and same-origin opener policy. The CSP intentionally allows same-origin scripts/styles plus `blob:` images/workers for local image handling and download. Re-test Canvas export and the service worker after tightening it.
Workers Static Assets reads `public/_headers` from the built `dist/_headers`. It sets CSP, `nosniff`, referrer policy, permissions policy, same-origin opener policy, and cache rules. The CSP intentionally allows same-origin scripts/styles plus `blob:` images/workers for local image handling and download. Re-test Canvas export and the service worker after tightening it.

### Release check

```bash
npm ci
npm run check
npm run worker:check
npm run test:e2e
```

Run the browser matrix against a deployed preview or production URL:

```bash
PLAYWRIGHT_BASE_URL=https://<preview-url> npm run test:e2e
```

Then verify on the deployed URL:

1. the first visit defaults to Traditional Chinese and can switch to Simplified Chinese or English;
Expand All @@ -90,4 +164,6 @@ Then verify on the deployed URL:
4. iPhone, iPad, and Mac profiles switch correctly;
5. PNG/JPEG/WebP downloads have exact profile dimensions;
6. desktop and mobile layouts have no horizontal overflow;
7. security headers are present.
7. non-file navigation paths return the SPA shell;
8. security and cache headers are present;
9. hashed JS/CSS uses immutable caching while `sw.js` remains revalidated.
Loading
Loading