[{"data":1,"prerenderedAt":841},["ShallowReactive",2],{"navigation_docs":3,"-web-dev-graphics-threejs-csr":352,"-web-dev-graphics-threejs-csr-surround":836},[4,54,83,116,125,161,179,200],{"title":5,"path":6,"stem":7,"children":8},"Ai","/ai","ai",[9,12,42,46,50],{"title":10,"path":6,"stem":11},"AI 技術探索","ai/index",{"title":13,"path":14,"stem":15,"children":16,"page":41},"Rag","/ai/rag","ai/RAG",[17,21,25,29,33,37],{"title":18,"path":19,"stem":20},"BM25 演算法深入解析：從 TF-IDF 到現代搜尋引擎的核心技術","/ai/rag/bm25-deep-dive-from-tf-idf-to-rag","ai/RAG/bm25-deep-dive-from-tf-idf-to-rag",{"title":22,"path":23,"stem":24},"Dense Retrieval（向量檢索）深入解析","/ai/rag/dense-retrieval-deep-dive","ai/RAG/dense-retrieval-deep-dive",{"title":26,"path":27,"stem":28},"RAG（Retrieval-Augmented Generation）原理與實作入門","/ai/rag/rag-intro-principles-and-implementation","ai/RAG/rag-intro-principles-and-implementation",{"title":30,"path":31,"stem":32},"RAG Retrieval Strategy 深入解析","/ai/rag/rag-retrieval-strategy-deep-dive","ai/RAG/rag-retrieval-strategy-deep-dive",{"title":34,"path":35,"stem":36},"Reciprocal Rank Fusion（RRF）教學：打造更穩定的檢索融合策略","/ai/rag/rrf-reciprocal-rank-fusion-guide","ai/RAG/rrf-reciprocal-rank-fusion-guide",{"title":38,"path":39,"stem":40},"TF-IDF（Term Frequency–Inverse Document Frequency）深入解析","/ai/rag/tf-idf-deep-dive","ai/RAG/tf-idf-deep-dive",false,{"title":43,"path":44,"stem":45},"Docus AI 功能完整實作指南","/ai/docus-ai-implementation","ai/docus-ai-implementation",{"title":47,"path":48,"stem":49},"llms.txt 是什麼？在 Nuxt 中控制 AI 與搜尋引擎爬蟲的新方式","/ai/llms-txt","ai/llms-txt",{"title":51,"path":52,"stem":53},"MCP（Model Context Protocol）是什麼？用「AI 的 USB-C」理解模型如何安全連接工具與資料","/ai/mcp_concept","ai/mcp_concept",{"title":55,"path":56,"stem":57,"children":58,"page":41},"Data Analysis","/data-analysis","data-analysis",[59,63,67,71,75,79],{"title":60,"path":61,"stem":62},"Exploratory Data Analysis（EDA）資料探索分析入門","/data-analysis/exploratory-data-analysis-eda","data-analysis/exploratory-data-analysis-eda",{"title":64,"path":65,"stem":66},"PR-AUC 深入解析：不平衡分類問題的重要評估指標","/data-analysis/pr-auc-for-imbalanced-classification","data-analysis/pr-auc-for-imbalanced-classification",{"title":68,"path":69,"stem":70},"ROC-AUC 深入解析：理解分類模型的判斷能力","/data-analysis/roc-auc-complete-guide","data-analysis/roc-auc-complete-guide",{"title":72,"path":73,"stem":74},"SHAP（SHapley Additive exPlanations）模型解釋方法深入解析","/data-analysis/shap-model-interpretation-complete-guide","data-analysis/shap-model-interpretation-complete-guide",{"title":76,"path":77,"stem":78},"Social Network Analysis（SNA）深入解析","/data-analysis/social-network-analysis-sna","data-analysis/social-network-analysis-sna",{"title":80,"path":81,"stem":82},"Time-based Split：為什麼時間序列資料不能使用 Random Split？","/data-analysis/time-based-split-vs-random-split","data-analysis/time-based-split-vs-random-split",{"title":84,"path":85,"stem":86,"children":87,"page":41},"MachineLearning","/machine_learning","machine_learning",[88,92,96,100,104,108,112],{"title":89,"path":90,"stem":91},"Confusion Matrix（混淆矩陣）完整解析","/machine_learning/confusion-matrix","machine_learning/confusion-matrix",{"title":93,"path":94,"stem":95},"Decision Tree 模型完整教學：從原理到 Python 實作","/machine_learning/decision-tree-complete-guide","machine_learning/decision-tree-complete-guide",{"title":97,"path":98,"stem":99},"為什麼 Decision Tree 在 Tabular Data 上常常勝過 Deep Learning？","/machine_learning/decision-tree-vs-deep-learning-on-tabular-data","machine_learning/decision-tree-vs-deep-learning-on-tabular-data",{"title":101,"path":102,"stem":103},"LightGBM 模型入門：理解高效能的 Gradient Boosting 演算法","/machine_learning/lightgbm-intro-for-tabular-data","machine_learning/lightgbm-intro-for-tabular-data",{"title":105,"path":106,"stem":107},"Logistic Regression（Logit 回歸）完整教學","/machine_learning/logistic-regression-complete-guide","machine_learning/logistic-regression-complete-guide",{"title":109,"path":110,"stem":111},"為什麼模型訓練需要 Train / Validation / Test Dataset？","/machine_learning/train-validation-test-dataset","machine_learning/train-validation-test-dataset",{"title":113,"path":114,"stem":115},"XGBoost 原理與實務教學","/machine_learning/xgboost-complete-guide","machine_learning/xgboost-complete-guide",{"title":117,"path":118,"stem":119,"children":120,"page":41},"Network","/network","network",[121],{"title":122,"path":123,"stem":124},"DNS 設定入門：CNAME vs A Record 完整解析","/network/dns-cname-vs-a-record-guide","network/dns-cname-vs-a-record-guide",{"title":126,"path":127,"stem":128,"children":129},"Nuxt","/nuxt","nuxt",[130,133,137,141,145,149,153,157],{"title":131,"path":127,"stem":132},"Nuxt 實戰指南","nuxt/index",{"title":134,"path":135,"stem":136},"Abstraction Layer 與 Adapter 的差別，一次搞懂設計角色","/nuxt/adapter_abstraction_layer","nuxt/adapter_abstraction_layer",{"title":138,"path":139,"stem":140},"Nuxt 4 全面理解 — 專案檔案結構解析","/nuxt/directory_structure","nuxt/directory_structure",{"title":142,"path":143,"stem":144},"Nuxt 前端 build 流程完整解析","/nuxt/frontend_build","nuxt/frontend_build",{"title":146,"path":147,"stem":148},"Nitro 是什麼？從 Nuxt 專案到 Server 與 Edge 的關鍵引擎","/nuxt/nitro","nuxt/nitro",{"title":150,"path":151,"stem":152},"深入理解 Nuxt 的 .nuxt 與 .output：為什麼部署時一定要分清楚？","/nuxt/nuxt_and_output","nuxt/nuxt_and_output",{"title":154,"path":155,"stem":156},"Nuxt 中 dev、build、preview 的差異一次搞懂","/nuxt/nuxt_dev_build_preview","nuxt/nuxt_dev_build_preview",{"title":158,"path":159,"stem":160},"Nuxt Image vs \u003Cimg>：為什麼 Nuxt 3 專案幾乎都該用 \u003CNuxtImg>？","/nuxt/nuxt_image","nuxt/nuxt_image",{"title":162,"path":163,"stem":164,"children":165},"Python 程式開發","/python","python/index",[166,167,171,175],{"title":162,"path":163,"stem":164},{"title":168,"path":169,"stem":170},"如何在 FastAPI 中調用記憶體 Buffer 回傳圖片 (附實例)","/python/memory_buffer","python/memory_buffer",{"title":172,"path":173,"stem":174},"Python 單元測試教學：如何為你的程式撰寫 Test","/python/python-unit-testing-unittest-pytest","python/python-unit-testing-unittest-pytest",{"title":176,"path":177,"stem":178},"如何使用 uv 取代 pip：改善 Python 專案的開發流程","/python/uv","python/uv",{"title":180,"path":181,"stem":182,"children":183,"page":41},"Statistic","/statistic","statistic",[184,188,192,196],{"title":185,"path":186,"stem":187},"卡方檢定（Chi-Square Test）入門教學","/statistic/chi-square-test-intro","statistic/chi-square-test-intro",{"title":189,"path":190,"stem":191},"常見抽樣方法（Sampling Methods）教學：Stratified、Quota、Convenience、Systematic、Simple Random","/statistic/common-sampling-methods-guide","statistic/common-sampling-methods-guide",{"title":193,"path":194,"stem":195},"Cramér’s V 指標介紹：如何衡量兩個類別變數之間的關聯","/statistic/cramers-v-for-categorical-association","statistic/cramers-v-for-categorical-association",{"title":197,"path":198,"stem":199},"Mann–Whitney U 與 Kolmogorov–Smirnov（KS）檢定：非參數統計檢定的入門指南","/statistic/mann-whitney-u-and-ks-test-intro","statistic/mann-whitney-u-and-ks-test-intro",{"title":201,"path":202,"stem":203,"children":204},"WebDev","/web_dev","web_dev",[205,208,234,248,282,312,334],{"title":206,"path":202,"stem":207},"Web 前端開發","web_dev/index",{"title":209,"path":210,"stem":211,"children":212},"瀏覽器與渲染","/web_dev/browser","web_dev/browser/index",[213,214,218,222,226,230],{"title":209,"path":210,"stem":211},{"title":215,"path":216,"stem":217},"瀏覽器儲存空間完整解析：Cookie、localStorage、IndexedDB 到 Cache Storage","/web_dev/browser/browser-storage-comprehensive-guide","web_dev/browser/browser-storage-comprehensive-guide",{"title":219,"path":220,"stem":221},"DOM (Document Object Model) 深入解析","/web_dev/browser/dom","web_dev/browser/dom",{"title":223,"path":224,"stem":225},"Service Worker Request Flow 深入解析","/web_dev/browser/service-worker-request-flow","web_dev/browser/service-worker-request-flow",{"title":227,"path":228,"stem":229},"CSR、SSR 與 SSG 是什麼？前端渲染策略完整比較","/web_dev/browser/ssr_csr_ssg","web_dev/browser/ssr_csr_ssg",{"title":231,"path":232,"stem":233},"Virtual DOM 深入解析：為什麼它能優化前端效能？","/web_dev/browser/virtual_dom","web_dev/browser/virtual_dom",{"title":235,"path":236,"stem":237,"children":238},"圖形技術","/web_dev/graphics","web_dev/graphics/index",[239,240,244],{"title":235,"path":236,"stem":237},{"title":241,"path":242,"stem":243},"為什麼 Three.js 專案幾乎都選擇 CSR？從 SSR 問題談起","/web_dev/graphics/threejs_csr","web_dev/graphics/threejs_csr",{"title":245,"path":246,"stem":247},"WebGL 是什麼？為什麼前端 3D 幾乎都靠它？","/web_dev/graphics/webgl","web_dev/graphics/webGL",{"title":249,"path":250,"stem":251,"children":252},"架構與配置","/web_dev/infrastructure","web_dev/infrastructure/index",[253,254,258,262,266,270,274,278],{"title":249,"path":250,"stem":251},{"title":255,"path":256,"stem":257},"Zeabur + K3s + Nuxt 部署架構完整解析","/web_dev/infrastructure/k3s-zeabur","web_dev/infrastructure/K3s-zeabur",{"title":259,"path":260,"stem":261},"ECS vs Docker vs Kubernetes：從部署堆疊理解三層架構","/web_dev/infrastructure/ecs-docker-kubernetes-stack","web_dev/infrastructure/ecs-docker-kubernetes-stack",{"title":263,"path":264,"stem":265},"ECS vs VPS 是什麼？從部署網站的角度一次搞懂差別","/web_dev/infrastructure/ecs-vs-vps","web_dev/infrastructure/ecs-vs-vps",{"title":267,"path":268,"stem":269},"Zeabur 內網服務連線完整入門指南","/web_dev/infrastructure/k3s-internal-networking","web_dev/infrastructure/k3s-internal-networking",{"title":271,"path":272,"stem":273},"使用 Microservices 架構設計系統的優勢解析","/web_dev/infrastructure/microservices-architecture-advantages","web_dev/infrastructure/microservices-architecture-advantages",{"title":275,"path":276,"stem":277},"Nginx 入門教學：從反向代理到與 Kubernetes 的架構比較","/web_dev/infrastructure/nginx-intro","web_dev/infrastructure/nginx-intro",{"title":279,"path":280,"stem":281},"YAML 配置是什麼？為什麼現代開發都在用它","/web_dev/infrastructure/yaml-configuration","web_dev/infrastructure/yaml-configuration",{"title":283,"path":284,"stem":285,"children":286},"網絡與通訊","/web_dev/network","web_dev/network/index",[287,288,292,296,300,304,308],{"title":283,"path":284,"stem":285},{"title":289,"path":290,"stem":291},"HTTP Request 結構完整解析：從 Request Line 到 Header 一次看懂","/web_dev/network/http-request-structure","web_dev/network/http-request-structure",{"title":293,"path":294,"stem":295},"OSI 模型（Open Systems Interconnection Model）完整解析","/web_dev/network/osi-model","web_dev/network/osi-model",{"title":297,"path":298,"stem":299},"RESTful API 設計原則與實務解析","/web_dev/network/restful-api","web_dev/network/restful-api",{"title":301,"path":302,"stem":303},"RESTful API 五大設計原則深入解析","/web_dev/network/restful-api-principles","web_dev/network/restful-api-principles",{"title":305,"path":306,"stem":307},"Server-Sent Events (SSE) 深入解析與實作教學","/web_dev/network/sse-introduction","web_dev/network/sse-introduction",{"title":309,"path":310,"stem":311},"WebSocket 入門教學：從概念到 Node.js 實作","/web_dev/network/websocket-introduction","web_dev/network/websocket-introduction",{"title":313,"path":314,"stem":315,"children":316},"認證與安全","/web_dev/security","web_dev/security/index",[317,318,322,326,330],{"title":313,"path":314,"stem":315},{"title":319,"path":320,"stem":321},"使用 Cookie 與 Session 建立使用者驗證（完整新手教學）","/web_dev/security/cookie-session-authentication","web_dev/security/cookie-session-authentication",{"title":323,"path":324,"stem":325},"JWT 驗證機制完整解析：從登入流程到實務應用","/web_dev/security/jwt-authentication","web_dev/security/jwt-authentication",{"title":327,"path":328,"stem":329},"Secret Key 簽名是什麼？從零理解資料簽名的本質","/web_dev/security/secret-key-signing","web_dev/security/secret-key-signing",{"title":331,"path":332,"stem":333},"SSH（Secure Shell）是什麼？從遠端登入到安全通道的核心概念","/web_dev/security/ssh","web_dev/security/ssh",{"title":335,"path":336,"stem":337,"children":338},"SEO 與規範","/web_dev/seo","web_dev/seo/index",[339,340,344,348],{"title":335,"path":336,"stem":337},{"title":341,"path":342,"stem":343},"Canonical URL 是什麼？用生活化方式搞懂前端 SEO 的基本保命符","/web_dev/seo/canonical_link","web_dev/seo/canonical_link",{"title":345,"path":346,"stem":347},"robots.txt 是什麼？SEO 的第一道守門員","/web_dev/seo/robot_txt","web_dev/seo/robot_txt",{"title":349,"path":350,"stem":351},"Nuxt SEO 中的 Meta 與 SEO 工具是如何運作的？","/web_dev/seo/seo","web_dev/seo/seo",{"id":353,"title":241,"body":354,"description":822,"extension":823,"links":824,"meta":825,"navigation":833,"path":242,"seo":834,"stem":243,"__hash__":835},"docs/web_dev/graphics/threejs_csr.md",{"type":355,"value":356,"toc":813},"minimark",[357,375,382,385,390,396,399,421,428,430,434,437,451,454,462,465,467,471,474,477,520,523,552,567,570,578,584,587,604,606,610,613,639,642,649,652,663,666,677,680,682,686,689,703,709,712,727,730,737,739,743,746,751,754,770,773,776,784,786,789,796,799,806,809],[358,359,360,361,365,366,370,371,374],"p",{},"在學習 Three.js 或將它整合進 Nuxt、Vue 專案時，很多人都會遇到同一個問題：",[362,363,364],"strong",{},"為什麼一開啟 SSR，專案就開始報錯？","\n錯誤訊息可能是 ",[367,368,369],"code",{},"window is not defined","、",[367,372,373],{},"document is not defined","，或是在 hydration 階段直接整個畫面炸掉。",[358,376,377,378,381],{},"這並不是你寫錯程式，而是 ",[362,379,380],{},"Three.js 的性質，天生就與 SSR 不相容","。這篇文章會一步步說明原因，並解釋為什麼大多數 Three.js 專案最後都選擇純 CSR 或 client-only 的架構。",[383,384],"hr",{},[386,387,389],"h2",{"id":388},"先釐清一件事ssr-並不是在瀏覽器執行","先釐清一件事：SSR 並不是在瀏覽器執行",[358,391,392,393],{},"理解這個問題的第一步，是要先打破一個常見誤解：\n",[362,394,395],{},"SSR（Server-Side Rendering）不是在瀏覽器跑的 JavaScript。",[358,397,398],{},"在 SSR 階段，JavaScript 執行的環境是：",[400,401,402,406,409,412,418],"ul",{},[403,404,405],"li",{},"Node.js（或其他 server runtime）",[403,407,408],{},"沒有視窗",[403,410,411],{},"沒有 DOM",[403,413,414,415],{},"沒有 ",[367,416,417],{},"\u003Ccanvas>",[403,419,420],{},"沒有顯示畫面",[358,422,423,424,427],{},"換句話說，SSR 的世界是一個「純後端環境」，它的任務只有一個：",[362,425,426],{},"產生 HTML 字串，然後回傳給瀏覽器","。",[383,429],{},[386,431,433],{"id":432},"threejs-的核心前提它一定要在瀏覽器","Three.js 的核心前提：它一定要在瀏覽器",[358,435,436],{},"Three.js 是一個用來操作 3D 圖形的函式庫，而它的整個設計基礎，建立在以下幾件事情上：",[400,438,439,445,448],{},[403,440,441,442,444],{},"透過 ",[367,443,417],{}," 作為繪圖容器",[403,446,447],{},"使用 WebGL 進行 GPU 繪製",[403,449,450],{},"依賴瀏覽器提供的 DOM 與視窗環境",[358,452,453],{},"也就是說，Three.js 假設了一件事：",[455,456,457],"blockquote",{},[358,458,459],{},[362,460,461],{},"「現在執行程式的地方，是一個真的有畫面、有瀏覽器的環境。」",[358,463,464],{},"但這個假設，在 SSR 階段並不成立。",[383,466],{},[386,468,470],{"id":469},"為什麼-threejs-在-ssr-階段會直接壞掉","為什麼 Three.js 在 SSR 階段會直接壞掉？",[358,472,473],{},"我們用最直覺的方式來看。",[358,475,476],{},"在 Three.js 中，你幾乎一定會寫到類似下面的程式碼：",[478,479,484],"pre",{"className":480,"code":481,"language":482,"meta":483,"style":483},"language-js shiki shiki-themes github-dark","const canvas = document.querySelector(\"canvas\");\n","js","",[367,485,486],{"__ignoreMap":483},[487,488,491,495,499,502,506,510,513,517],"span",{"class":489,"line":490},"line",1,[487,492,494],{"class":493},"snl16","const",[487,496,498],{"class":497},"sDLfK"," canvas",[487,500,501],{"class":493}," =",[487,503,505],{"class":504},"s95oV"," document.",[487,507,509],{"class":508},"svObZ","querySelector",[487,511,512],{"class":504},"(",[487,514,516],{"class":515},"sU2Wk","\"canvas\"",[487,518,519],{"class":504},");\n",[358,521,522],{},"或是：",[478,524,526],{"className":480,"code":525,"language":482,"meta":483,"style":483},"const renderer = new THREE.WebGLRenderer();\n",[367,527,528],{"__ignoreMap":483},[487,529,530,532,535,537,540,543,546,549],{"class":489,"line":490},[487,531,494],{"class":493},[487,533,534],{"class":497}," renderer",[487,536,501],{"class":493},[487,538,539],{"class":493}," new",[487,541,542],{"class":497}," THREE",[487,544,545],{"class":504},".",[487,547,548],{"class":508},"WebGLRenderer",[487,550,551],{"class":504},"();\n",[358,553,554,555],{},"這些程式碼背後都隱含了一個前提：\n",[362,556,557,370,560,370,563,566],{},[367,558,559],{},"document",[367,561,562],{},"canvas",[367,564,565],{},"WebGLRenderingContext"," 必須存在。",[358,568,569],{},"但在 SSR 階段：",[478,571,576],{"className":572,"code":574,"language":575,"meta":483},[573],"language-text","window ❌\ndocument ❌\ncanvas ❌\nWebGL ❌\n","text",[367,577,574],{"__ignoreMap":483},[358,579,580,581],{},"於是問題就出現了——\n",[362,582,583],{},"不是 Three.js 寫錯，而是執行環境根本不支援它。",[358,585,586],{},"這也是為什麼你會在 SSR 專案中看到這類錯誤：",[400,588,589,594,598,601],{},[403,590,591],{},[367,592,593],{},"ReferenceError: window is not defined",[403,595,596],{},[367,597,373],{},[403,599,600],{},"hydration mismatch",[403,602,603],{},"dev server 直接 crash",[383,605],{},[386,607,609],{"id":608},"即使不報錯ssr-對-threejs-也沒有實際意義","即使「不報錯」，SSR 對 Three.js 也沒有實際意義",[358,611,612],{},"假設你花了很多力氣，用條件判斷避免 SSR 報錯，例如：",[478,614,616],{"className":480,"code":615,"language":482,"meta":483,"style":483},"if (process.client) {\n  // Three.js code\n}\n",[367,617,618,626,633],{"__ignoreMap":483},[487,619,620,623],{"class":489,"line":490},[487,621,622],{"class":493},"if",[487,624,625],{"class":504}," (process.client) {\n",[487,627,629],{"class":489,"line":628},2,[487,630,632],{"class":631},"sAwPA","  // Three.js code\n",[487,634,636],{"class":489,"line":635},3,[487,637,638],{"class":504},"}\n",[358,640,641],{},"這樣確實可以讓程式「不炸掉」，但問題來了：",[455,643,644],{},[358,645,646],{},[362,647,648],{},"就算 SSR 階段沒執行 Three.js，它也「什麼都沒做」。",[358,650,651],{},"因為 SSR 的目的，是產生「可顯示內容的 HTML」。\n但 Three.js 的畫面：",[400,653,654,657,660],{},[403,655,656],{},"不是文字",[403,658,659],{},"不是靜態結構",[403,661,662],{},"而是即時渲染的圖形結果",[358,664,665],{},"也就是說，在 SSR 階段：",[400,667,668,671,674],{},[403,669,670],{},"無法預先產生 Three.js 的畫面",[403,672,673],{},"無法輸出有意義的 HTML",[403,675,676],{},"最終還是得等瀏覽器載入後才開始渲染",[358,678,679],{},"既然如此，SSR 在這裡就只剩下「增加複雜度」，而沒有實質好處。",[383,681],{},[386,683,685],{"id":684},"為什麼純-csr-client-only-反而是合理選擇","為什麼純 CSR / client-only 反而是合理選擇？",[358,687,688],{},"對於 Three.js 專案來說，核心價值通常是：",[400,690,691,694,697,700],{},[403,692,693],{},"3D 即時渲染",[403,695,696],{},"動畫與互動",[403,698,699],{},"滑鼠、鍵盤、觸控操作",[403,701,702],{},"requestAnimationFrame 的高頻更新",[358,704,705,706],{},"這些行為有一個共同點：\n",[362,707,708],{},"它們只在瀏覽器中才有意義。",[358,710,711],{},"選擇純 CSR 或 client-only，可以帶來幾個非常實際的好處：",[713,714,715,718,721,724],"ol",{},[403,716,717],{},"不需要處理 SSR 與 client 環境差異",[403,719,720],{},"不會遇到 hydration 問題",[403,722,723],{},"可以放心使用瀏覽器 API",[403,725,726],{},"架構更單純、除錯成本更低",[358,728,729],{},"因此在實務上，你會發現：",[455,731,732],{},[358,733,734],{},[362,735,736],{},"展示型、互動型、模擬型的 Three.js 專案，幾乎清一色是 CSR。",[383,738],{},[386,740,742],{"id":741},"在-nuxt-中這不是缺點而是正確使用方式","在 Nuxt 中，這不是缺點，而是正確使用方式",[358,744,745],{},"很多初學者會以為：",[455,747,748],{},[358,749,750],{},"「關掉 SSR，是不是代表專案比較不專業？」",[358,752,753],{},"但實際上剛好相反。",[358,755,756,757,370,760,370,763,766,767,427],{},"Nuxt 提供 ",[367,758,759],{},"ssr: false",[367,761,762],{},"\u003CClientOnly>",[367,764,765],{},"process.client"," 這些工具，",[362,768,769],{},"本來就是為了處理「只適合在瀏覽器執行的應用」",[358,771,772],{},"Three.js 正是這類應用的典型代表。",[358,774,775],{},"只要你的專案核心是 3D 互動，而不是 SEO 導向的內容頁面，那麼選擇 CSR：",[400,777,778,781],{},[403,779,780],{},"不是妥協",[403,782,783],{},"而是符合技術本質的設計決策",[383,785],{},[386,787,788],{"id":788},"結語",[358,790,791,792,795],{},"Three.js 不適合 SSR，並不是因為它「不夠好」，而是因為 ",[362,793,794],{},"SSR 的世界裡，根本不存在它所需要的環境","。\n當一個應用的核心價值來自即時互動與視覺渲染，與其勉強套用 SSR，不如誠實地選擇純 CSR 或 client-only。",[358,797,798],{},"記住這個判斷原則會很有幫助：",[455,800,801],{},[358,802,803],{},[362,804,805],{},"內容導向 → SSR / SSG\n互動導向 → CSR / client-only",[358,807,808],{},"理解這一點，你在 Nuxt 中使用 Three.js，反而會變得非常順。",[810,811,812],"style",{},"html pre.shiki code .snl16, html code.shiki .snl16{--shiki-default:#F97583}html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}html pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}html pre.shiki code .svObZ, html code.shiki .svObZ{--shiki-default:#B392F0}html pre.shiki code .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}",{"title":483,"searchDepth":628,"depth":628,"links":814},[815,816,817,818,819,820,821],{"id":388,"depth":628,"text":389},{"id":432,"depth":628,"text":433},{"id":469,"depth":628,"text":470},{"id":608,"depth":628,"text":609},{"id":684,"depth":628,"text":685},{"id":741,"depth":628,"text":742},{"id":788,"depth":628,"text":788},"從 Three.js 的運作原理出發，說明為什麼高度互動、基於 Canvas/WebGL 的應用不適合 SSR，以及為何純 CSR 或 client-only 會是更合理的選擇。","md",null,{"tags":826,"category":203,"date":832},[827,828,829,128,830,831],"threejs","csr","ssr","frontend","webgl","2026-02-03",true,{"title":241,"description":822},"YMrMPgMghs8eRFvQf1hE8s6MuGZzG8-8deDhCFK4iuU",[837,839],{"title":235,"path":236,"stem":237,"description":838,"children":-1},"探索 WebGL、Three.js 等 3D 與圖形渲染技術。",{"title":245,"path":246,"stem":247,"description":840,"children":-1},"從新手角度理解 WebGL 的角色，以及 Three.js 如何站在 WebGL 之上，讓前端也能輕鬆開發 3D 圖形與互動場景。",1776690845968]