Three.js 部署與相容性:使用 CDN 或雲端部署
簡介
在完成 Three.js 應用的開發後,部署 成為讓使用者真正看到 3D 效果的最後一步。
傳統上,我們會將整個專案打包成靜態檔案,放在自己的伺服器或是本機環境測試。但隨著前端資源日益龐大、瀏覽器相容性需求提升,使用 CDN(Content Delivery Network)或雲端平台 成為更常見且高效的部署方式。
本文將帶你了解 為什麼、如何 透過 CDN 或雲端服務部署 Three.js,並說明在相容性、效能與維護上需要注意的要點。適合剛學完 Three.js 基礎的初學者,也適用於想要優化部署流程的中階開發者。
核心概念
1. CDN 與雲端部署的差異
| 項目 | CDN | 雲端平台(如 Vercel、Netlify、Firebase Hosting) |
|---|---|---|
| 目的 | 快速分發靜態資源(JS、CSS、模型檔) | 完整的前端部署環境,支援 CI/CD、伺服器端渲染 |
| 優點 | 全球節點、低延遲、免自行維護伺服器 | 自動化部署、簡易設定環境變數、支援動態 API |
| 缺點 | 只適合靜態檔案,無法直接處理後端邏輯 | 部署成本(免費方案有流量限制) |
| 典型使用情境 | 引入 Three.js 核心庫、載入常用模型或貼圖 | 部署完整的 Three.js 網站、結合後端服務 |
結論:在大多數案例中,把 Three.js 程式庫放在 CDN,網站本身則部署於雲端平台,可同時取得兩者的優勢。
2. 為什麼要使用 CDN 引入 Three.js
- 減少首次載入時間:CDN 會自動根據使用者所在地選擇最近的節點,降低 RTT(Round‑Trip Time)。
- 瀏覽器快取共享:若使用者之前已訪問過其他使用同一 CDN 的網站,瀏覽器會直接使用快取,避免重複下載。
- 自動版本管理:許多 CDN(如
unpkg、jsDelivr)支援語義化版本號,讓你輕鬆升級或回退。
3. 常見 CDN 來源
| CDN | URL 範例 | 說明 |
|---|---|---|
| jsDelivr | https://cdn.jsdelivr.net/npm/three@0.166.0/build/three.min.js |
支援 npm 套件直接引用,支援自動選擇最適合的壓縮檔 |
| unpkg | https://unpkg.com/three@0.166.0/build/three.min.js |
直接從 npm 下載,支援 ?module 取得 ES Module |
| cdnjs | https://cdnjs.cloudflare.com/ajax/libs/three.js/r166/three.min.js |
老牌 CDN,提供多個發佈版(rXXX) |
小技巧:在開發階段使用
?module(如https://unpkg.com/three@0.166.0/build/three.module.js?module)可直接以 ES Module 方式匯入,配合<script type="module">使用。
4. 雲端平台部署流程概覽
以下以 Vercel 為例,說明從 GitHub 到線上網站的完整流程:
- 建立 Git Repository:把 Three.js 專案(HTML、JS、模型檔)推上 GitHub。
- 連結 Vercel 帳號:在 Vercel 網站點選「New Project」→ 選擇剛才的 repo。
- 設定 Build 設定:對於純靜態網站,Vercel 會自動偵測
public/或根目錄的index.html,不需要額外建置指令。 - 部署:點擊「Deploy」後,Vercel 會自動建立 CDN 網路,並提供唯一的 domain(如
your-project.vercel.app)。 - 自訂域名(可選):在 Vercel 控制台設定自己的域名,並透過 DNS 解析指向 Vercel。
其他平台(Netlify、Firebase Hosting)操作類似,只是 UI 與設定檔稍有差異。
5. 程式碼範例
以下示範 三種不同的部署方式,從最簡單的 CDN 引入到完整的雲端部署流程。每段程式碼均附上說明註解,方便直接複製使用。
範例 1:使用 CDN 引入 Three.js(最小化 HTML)
<!DOCTYPE html>
<html lang="zh-Hant">
<head>
<meta charset="UTF-8">
<title>Three.js CDN 範例</title>
<style>
body { margin:0; overflow:hidden; }
canvas { display:block; }
</style>
</head>
<body>
<!-- 直接從 jsDelivr 取得壓縮版 -->
<script src="https://cdn.jsdelivr.net/npm/three@0.166.0/build/three.min.js"></script>
<script>
// 基本場景、相機、渲染器
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, innerWidth / innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(innerWidth, innerHeight);
document.body.appendChild(renderer.domElement);
// 簡單立方體
const geometry = new THREE.BoxGeometry();
const material = new THREE.MeshBasicMaterial({ color: 0x0077ff });
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);
camera.position.z = 3;
function animate() {
requestAnimationFrame(animate);
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
renderer.render(scene, camera);
}
animate();
</script>
</body>
</html>
重點:只要把
script src換成其他 CDN(如unpkg),即可測試不同來源的效能差異。
範例 2:使用 ES Module(type="module")從 CDN 載入 Three.js
<!DOCTYPE html>
<html lang="zh-Hant">
<head>
<meta charset="UTF-8">
<title>Three.js ES Module CDN 範例</title>
<style>body{margin:0;overflow:hidden}</style>
</head>
<body>
<script type="module">
// 從 unpkg 直接取得 ES Module 版本
import * as THREE from 'https://unpkg.com/three@0.166.0/build/three.module.js?module';
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(60, innerWidth / innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(innerWidth, innerHeight);
document.body.appendChild(renderer.domElement);
const geometry = new THREE.SphereGeometry(1, 32, 32);
const material = new THREE.MeshStandardMaterial({ color: '#ff6600', metalness: 0.5, roughness: 0.2 });
const sphere = new THREE.Mesh(geometry, material);
scene.add(sphere);
// 加入簡易光源
const light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(5, 5, 5);
scene.add(light);
camera.position.set(0, 0, 3);
function render() {
requestAnimationFrame(render);
sphere.rotation.y += 0.005;
renderer.render(scene, camera);
}
render();
</script>
</body>
</html>
說明:使用 ES Module 可以直接在瀏覽器端使用
import,讓程式碼結構更清晰,且支援 tree‑shaking(如果未使用的功能會被瀏覽器自動忽略)。
範例 3:在 Vercel 部署的完整 Three.js 靜態網站
下面的檔案結構示意(檔案放在專案根目錄):
my-threejs-project/
│─ public/
│ │─ index.html
│ │─ assets/
│ │ └─ model.glb
│ └─ styles.css
│─ package.json (可不需要,但放在此方便未來加入 build 工具)
└─ .vercelignore (可選,排除不必要檔案)
public/index.html(使用 CDN + GLTFLoader)
<!DOCTYPE html>
<html lang="zh-Hant">
<head>
<meta charset="UTF-8">
<title>Three.js + Vercel 部署範例</title>
<link rel="stylesheet" href="/styles.css">
</head>
<body>
<script src="https://cdn.jsdelivr.net/npm/three@0.166.0/build/three.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.166.0/examples/js/loaders/GLTFLoader.js"></script>
<script>
// 基本設定
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(70, innerWidth / innerHeight, 0.1, 100);
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(innerWidth, innerHeight);
document.body.appendChild(renderer.domElement);
// 環境光 + 方向光
scene.add(new THREE.AmbientLight(0xffffff, 0.6));
const dirLight = new THREE.DirectionalLight(0xffffff, 0.8);
dirLight.position.set(5, 10, 7);
scene.add(dirLight);
// 載入 GLTF 模型
const loader = new THREE.GLTFLoader();
loader.load('/assets/model.glb',
gltf => {
const model = gltf.scene;
model.scale.set(0.5, 0.5, 0.5);
scene.add(model);
},
xhr => console.log(`模型載入進度: ${(xhr.loaded / xhr.total * 100).toFixed(1)}%`),
err => console.error('模型載入失敗', err)
);
camera.position.set(0, 1, 3);
const controls = new THREE.OrbitControls(camera, renderer.domElement); // 若使用 OrbitControls,請自行加入 CDN
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
animate();
</script>
</body>
</html>
public/styles.css(簡單全螢幕樣式)
html, body, #app {
width: 100%;
height: 100%;
margin: 0;
overflow: hidden;
background: #111;
}
部署步驟(簡化版):
# 1. 初始化 Git
git init
git add .
git commit -m "Initial commit - Three.js with CDN"
# 2. 推送至 GitHub
git remote add origin https://github.com/yourname/my-threejs-project.git
git push -u origin master
# 3. 前往 Vercel
# - 登入後點選 "New Project"
# - 選擇剛剛的 repo
# - Vercel 會自動偵測為靜態網站,直接 Deploy
部署完成後,你會得到
https://my-threejs-project.vercel.app,全球 CDN 會自動快取three.min.js、模型檔與 CSS,使用者即時取得最佳效能。
範例 4:使用 Netlify 搭配自動化 CI/CD
# netlify.toml
[build]
publish = "public" # 指定要發佈的資料夾
command = "echo 'No build step needed'" # 靜態網站不需要編譯
[[redirects]]
from = "/*"
to = "/index.html"
status = 200
把
netlify.toml放在專案根目錄,接著在 Netlify 網站「New site from Git」選擇 repo,完成後 Netlify 會自動部署,且每次 push 都會觸發重新部署。
常見陷阱與最佳實踐
| 陷阱 | 可能的症狀 | 解決方案 / 最佳實踐 |
|---|---|---|
| CDN 版本不一致 | 產生 THREE.Object3D 無法正確繼承或 GLTFLoader 报错 |
固定版本號(如 @0.166.0),不要直接使用 latest;在 package.json 中鎖定相同版本,確保本地與線上環境一致。 |
| 跨域(CORS)問題 | 無法載入模型、貼圖或 HDR 環境圖 | 確保模型檔案放在同一域名或使用支援 CORS 的 CDN;若自行上傳到 Cloud Storage,必須在設定中開啟 Access-Control-Allow-Origin: *。 |
| Cache 失效 | 更新模型後使用者仍看到舊檔 | 為資源加上 版本化 query string(例如 model.glb?v=20251101),或在雲端平台設定 Cache‑Control 為 no-cache(開發階段)。 |
| 載入順序錯誤 | GLTFLoader 找不到 THREE 物件 |
先載入 three.min.js,再載入 GLTFLoader.js;或改用 ES Module 方式一次匯入(import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js')。 |
| 過大的模型檔 | 首次載入時間超過 5 秒,使用者離開 | 使用 glTF Draco 壓縮、GLB 二進位格式,或在 CDN 上啟用 gzip / brotli 壓縮。 |
最佳實踐清單
- 固定 CDN 版本:在
script src中寫完整的語義化版本(例:@0.166.0),避免因新版破壞相容性。 - 使用
async/defer:若使用多個外部腳本,加入defer讓瀏覽器在解析完 HTML 後才執行,提升首次渲染速度。<script src="https://cdn.jsdelivr.net/npm/three@0.166.0/build/three.min.js" defer></script> - 啟用 HTTP/2:大多數雲端平台自動支援 HTTP/2,能同時傳送多個小檔案(如貼圖)而不產生阻塞。
- 使用
preconnect與dns-prefetch:提前與 CDN 建立連線,降低延遲。<link rel="preconnect" href="https://cdn.jsdelivr.net"> <link rel="dns-prefetch" href="https://cdn.jsdelivr.net"> - 監控效能:在 Chrome DevTools 的「Network」面板觀察資源大小、快取命中率;使用 Lighthouse 量化「First Contentful Paint」與「Time to Interactive」。
實際應用場景
| 場景 | 為何選擇 CDN + 雲端部署 | 範例作品 |
|---|---|---|
| 產品展示網站 | 大量模型與高解析度貼圖需要快速下載,且全球客戶可能同時訪問 | 3D 商品展覽、家具 AR 預覽 |
| 教育與互動教學平台 | 常常需要即時更新教材(模型、影片),使用 CDN 可免除每次重新部署的等待 | WebGL 互動課程、科學模擬 |
| 藝術與視覺化專案 | 藝術家希望作品能在任何裝置上流暢播放,使用雲端平台的自動縮放與 CDN 能確保一致體驗 | 交互式裝置藝術、資料視覺化儀表板 |
| 行銷活動與微網站 | 活動期間流量激增,CDN 能自動擴展,雲端平台提供即時部署與回滾功能 | 節日優惠 3D 微站、品牌互動體驗 |
案例分享:某家具品牌使用 Vercel + jsDelivr,把所有 GLB 模型放在 Cloudflare R2,配合 Cache‑Control 設定 30 天快取,首頁載入時間從 4.2 秒降至 1.3 秒,轉換率提升 12%。
總結
- CDN 為 Three.js 程式庫與大型資源(模型、貼圖)提供全球快速分發,降低首次載入延遲。
- 雲端平台(Vercel、Netlify、Firebase Hosting)則負責整個靜態網站的部署、CI/CD、以及自動快取機制,讓開發者可以專注在 3D 內容本身。
- 在實務上,固定版本、處理 CORS、妥善設定快取 是避免相容性問題的關鍵;同時加入
preconnect、async/defer等最佳實踐,可讓使用者得到更流暢的體驗。
只要掌握上述概念與步驟,即可把你在本機開發的 Three.js 作品,快速、安全且具備全球相容性的上線給全世界的使用者欣賞。祝你部署順利,創造出更多令人驚豔的 Web 3D 體驗!