本文 AI 產出,尚未審核
Three.js
單元:開發環境與基本設置
主題:安裝與模組載入(ESM / CDN)
簡介
在使用 Three.js 建立 3D 網頁應用時,第一步往往就是把程式庫正確地載入專案。
無論是透過 npm 安裝後以 ES Module (ESM) 方式匯入,或是直接使用 CDN 提供的 script 標籤,兩者各有優缺點;選擇適合的載入方式能讓開發流程更順暢、除錯更容易,也能避免因版本不一致而產生的怪異錯誤。
本篇文章將從 環境安裝、模組載入、實作範例 三個層面說明,並針對常見的陷阱提供 最佳實踐,讓剛踏入 Three.js 世界的你能快速上手、穩定開發。
核心概念
1. 為什麼要使用 ES Module (ESM)?
ES Module 是 ECMAScript 官方規範的模組系統,具備靜態分析、Tree‑shaking(去除未使用程式碼)等特性。
在現代前端開發工具(如 Vite、Webpack、Rollup)中,使用 ESM 能讓程式碼更模組化、維護性更佳。
1.1 ESM 的基本語法
// 匯入整個 Three.js 套件
import * as THREE from 'three';
// 只匯入需要的子模組,減少 bundle 大小
import { PerspectiveCamera, Scene, WebGLRenderer } from 'three';
import必須放在檔案最上方,且只能在 type="module" 的腳本中使用。- 若要搭配 Three.js 官方的擴充套件(如
OrbitControls),同樣採用 ESM 路徑:
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
2. 使用 npm 安裝 Three.js
2.1 建立專案
# 建立資料夾並初始化 npm
mkdir my-threejs-demo
cd my-threejs-demo
npm init -y
2.2 安裝套件
npm install three
# 若需要額外的範例程式(examples)可安裝
npm install three@latest
Tip:安裝完後,
node_modules/three內即包含完整的 ESM 檔案與範例程式碼,直接引用即可。
2.3 建立開發伺服器(以 Vite 為例)
npm install vite --save-dev
# 在 package.json 加入啟動指令
# "scripts": { "dev": "vite" }
建立 index.html、main.js,然後執行 npm run dev,即可在瀏覽器看到即時重載的 Three.js 場景。
3. 直接使用 CDN(Content Delivery Network)
如果不想安裝 npm,或是要快速驗證想法,CDN 是最省事的方式。
Three.js 官方提供 unpkg、jsDelivr 等多個 CDN,且支援 ESM。
3.1 使用 <script type="module"> 載入
<!DOCTYPE html>
<html lang="zh-Hant">
<head>
<meta charset="UTF-8">
<title>Three.js CDN 範例</title>
<style>body{margin:0;overflow:hidden;}</style>
</head>
<body>
<script type="module">
// 直接從 CDN 匯入 Three.js 主程式
import * as THREE from 'https://cdn.jsdelivr.net/npm/three@0.162.0/build/three.module.js';
// 匯入 OrbitControls(同樣是 ESM)
import { OrbitControls } from 'https://cdn.jsdelivr.net/npm/three@0.162.0/examples/jsm/controls/OrbitControls.js';
// 基本場景設定(同下方範例)
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.MeshStandardMaterial({ color: 0x0077ff });
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);
const light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(5, 10, 7);
scene.add(light);
const controls = new OrbitControls(camera, renderer.domElement);
camera.position.set(2, 2, 5);
controls.update();
function animate() {
requestAnimationFrame(animate);
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
renderer.render(scene, camera);
}
animate();
</script>
</body>
</html>
- 優點:不需安裝任何套件,直接在任何支援 ES Module 的瀏覽器跑。
- 缺點:每次載入都會向 CDN 請求檔案,若網路不穩或 CDN 發生故障,開發體驗會受影響。
4. 完整的「Hello Three.js」範例(ESM 版)
以下示範 npm + ESM 的完整流程,適合想建立可編譯、可部署的專案時使用。
// src/main.js
import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
// ---------- 初始化渲染器 ----------
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// ---------- 建立場景與相機 ----------
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x202020);
const camera = new THREE.PerspectiveCamera(
60, // 視角 (FOV)
window.innerWidth / window.innerHeight,
0.1, // 近剪裁面
1000 // 遠剪裁面
);
camera.position.set(3, 2, 5);
// ---------- 加入光源 ----------
const ambient = new THREE.AmbientLight(0xffffff, 0.4);
scene.add(ambient);
const directional = new THREE.DirectionalLight(0xffffff, 0.8);
directional.position.set(5, 10, 7);
scene.add(directional);
// ---------- 建立簡易幾何 ----------
const geometry = new THREE.SphereGeometry(1, 32, 32);
const material = new THREE.MeshStandardMaterial({
color: 0xff6600,
roughness: 0.5,
metalness: 0.1
});
const sphere = new THREE.Mesh(geometry, material);
scene.add(sphere);
// ---------- 控制器 ----------
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true; // 平滑慣性
// ---------- 窗口尺寸變更 ----------
window.addEventListener('resize', () => {
const { innerWidth, innerHeight } = window;
renderer.setSize(innerWidth, innerHeight);
camera.aspect = innerWidth / innerHeight;
camera.updateProjectionMatrix();
});
// ---------- 動畫迴圈 ----------
function render() {
requestAnimationFrame(render);
controls.update(); // 只在 enableDamping 時需要
renderer.render(scene, camera);
}
render();
說明:
import * as THREE from 'three'會一次匯入所有核心類別。OrbitControls放在examples/jsm/controls目錄下,必須使用 完整的檔案路徑(結尾要.js)。renderer.setSize與camera.aspect需要在視窗大小變更時同步更新,否則畫面會被拉伸。
常見陷阱與最佳實踐
| 陷阱 | 可能的症狀 | 解決方法 | 最佳實踐 |
|---|---|---|---|
忘記在 <script> 加 type="module" |
Uncaught SyntaxError: Cannot use import statement outside a module |
為所有使用 import 的 <script> 標籤加上 type="module" |
使用 Vite/Parcel 時,預設已設定為模組,無需手動加 |
| 引用舊版 CDN URL | 3D 物件不顯示、API 失效 | 直接使用 https://cdn.jsdelivr.net/npm/three@<最新版本>/build/three.module.js |
鎖定版本(如 @0.162.0)避免因新版破壞相容性 |
範例程式檔案路徑錯誤 (OrbitControls、GLTFLoader 等) |
Failed to load module script |
確認路徑以 examples/jsm/ 開頭,且結尾加 .js |
建議在 IDE 中使用 自動補全,減少手寫錯誤 |
未設定 crossOrigin (載入外部資源如貼圖、模型) |
貼圖載入失敗、CORS 錯誤 | 在 loader 上設定 loader.setCrossOrigin('anonymous') 或在伺服器端加上 CORS 頭 |
若使用 Vite,可在 vite.config.js 設定 server.cors:true |
| 過度依賴 CDN,未加離線快取 | 部署後無法在無網路環境使用 | 使用 Service Worker 或 Workbox 快取 CDN 檔案 | 在正式專案中,建議把 Three.js 打包進 dist,減少外部依賴 |
實際應用場景
快速原型驗證
- 使用 CDN 直接在 CodePen、JSFiddle 或本機 HTML 中測試概念,省去建置時間。
企業級 WebGL 專案
- 透過 npm 安裝、ESM 匯入,配合打包工具(Vite、Webpack)產生最小化的 bundle,確保載入效能與版本可控。
多模組協作
- 在大型團隊中,使用 ESM 能讓每個子模組(如
scene-manager.js、ui-controls.js)獨立開發、單元測試,最後再由主入口匯入。
- 在大型團隊中,使用 ESM 能讓每個子模組(如
離線或嵌入式設備
- 把 Three.js 打包成單一檔案(使用 Rollup 的
output.format: 'esm'),搭配本機檔案系統或 Electron,避免依賴外部 CDN。
- 把 Three.js 打包成單一檔案(使用 Rollup 的
總結
- ESM 為現代前端的標準模組系統,提供靜態分析、Tree‑shaking 等優勢;配合 npm 安裝可讓專案更易維護。
- CDN 則是「零安裝」的速成方案,適合快速驗證想法或教學示範。
- 正確的 模組路徑、type="module" 設定、以及 版本鎖定,是避免常見錯誤的關鍵。
- 在實務開發中,建議 先以 CDN 起手,確認概念後再轉移至 npm + ESM 的正式開發流程,這樣既能快速迭代,也能確保最終產品的效能與可維護性。
掌握了安裝與模組載入的基礎後,你就可以把注意力放在 場景構建、動畫控制、資源載入 等更具創意的部分,讓 Three.js 成為你打造互動 3D 網頁體驗的強大工具。祝開發順利,玩得開心! 🎉