[{"data":1,"prerenderedAt":1101},["ShallowReactive",2],{"blog:\u002Fblog\u002Fnuxt\u002Ffullstack-architecture":3},{"id":4,"title":5,"author":6,"body":7,"category":1085,"date":1086,"description":1087,"draft":1088,"extension":1089,"image":1090,"meta":1091,"navigation":282,"path":1092,"seo":1093,"series":1094,"seriesOrder":214,"seriesTitle":1095,"stem":1096,"tags":1097,"updatedAt":1090,"__hash__":1100},"blog\u002Fblog\u002Fnuxt\u002Ffullstack-architecture\u002Findex.md","Nuxt 4 全棧專案架構設計","charles",{"type":8,"value":9,"toc":1062},"minimark",[10,14,18,34,37,40,44,133,137,164,168,194,196,200,593,597,600,620,627,629,632,640,643,648,668,673,681,683,686,689,692,711,717,721,724,730,737,743,749,751,755,952,956,997,999,1002,1028,1030,1033,1058],[11,12,13],"h2",{"id":13},"這篇要解決什麼問題",[15,16,17],"p",{},"當專案規模成長，架構設計的好壞直接影響開發效率與維護成本。這篇文章將說明：",[19,20,21,25,28,31],"ul",{},[22,23,24],"li",{},"為什麼選擇 Nuxt 4 + Supabase + Cloudflare Workers",[22,26,27],{},"app\u002F vs server\u002F 的分層設計",[22,29,30],{},"選擇 SPA 模式（ssr: false）的場景與權衡",[22,32,33],{},"模組化的目錄結構設計",[35,36],"hr",{},[11,38,39],{"id":39},"技術棧選型",[41,42,43],"h3",{"id":43},"核心技術",[45,46,47,63],"table",{},[48,49,50],"thead",{},[51,52,53,57,60],"tr",{},[54,55,56],"th",{},"層級",[54,58,59],{},"技術",[54,61,62],{},"選擇理由",[64,65,66,81,94,107,120],"tbody",{},[51,67,68,75,78],{},[69,70,71],"td",{},[72,73,74],"strong",{},"框架",[69,76,77],{},"Nuxt 4",[69,79,80],{},"Vue 3 生態系最成熟的全棧框架",[51,82,83,88,91],{},[69,84,85],{},[72,86,87],{},"UI",[69,89,90],{},"Nuxt UI 4",[69,92,93],{},"官方 UI 庫，Dashboard 元件完整",[51,95,96,101,104],{},[69,97,98],{},[72,99,100],{},"資料庫",[69,102,103],{},"Supabase",[69,105,106],{},"PostgreSQL + 即時訂閱 + Auth + Storage",[51,108,109,114,117],{},[69,110,111],{},[72,112,113],{},"部署",[69,115,116],{},"Cloudflare Workers",[69,118,119],{},"Edge Runtime，全球低延遲",[51,121,122,127,130],{},[69,123,124],{},[72,125,126],{},"狀態管理",[69,128,129],{},"Pinia + Pinia Colada",[69,131,132],{},"輕量 + 內建非同步狀態管理",[41,134,136],{"id":135},"為什麼選-nuxt-4","為什麼選 Nuxt 4",[138,139,140,146,152,158],"ol",{},[22,141,142,145],{},[72,143,144],{},"檔案式路由","：pages\u002F 目錄自動產生路由",[22,147,148,151],{},[72,149,150],{},"自動匯入","：composables、components、utils 自動可用",[22,153,154,157],{},[72,155,156],{},"Server API","：server\u002Fapi\u002F 直接寫 API，無需額外設定",[22,159,160,163],{},[72,161,162],{},"TypeScript 優先","：內建類型支援，開發體驗優秀",[41,165,167],{"id":166},"為什麼選-supabase","為什麼選 Supabase",[138,169,170,176,182,188],{},[22,171,172,175],{},[72,173,174],{},"PostgreSQL","：成熟的關聯式資料庫，支援複雜查詢",[22,177,178,181],{},[72,179,180],{},"RLS","：Row Level Security 在資料庫層保護資料",[22,183,184,187],{},[72,185,186],{},"TypeScript 類型","：CLI 自動產生完整類型定義",[22,189,190,193],{},[72,191,192],{},"本地開發","：Docker 一鍵啟動，不依賴雲端",[35,195],{},[11,197,199],{"id":198},"nuxtconfigts-核心設定","nuxt.config.ts 核心設定",[201,202,207],"pre",{"className":203,"code":204,"language":205,"meta":206,"style":206},"language-typescript shiki shiki-themes material-theme-lighter github-light github-dark","export default defineNuxtConfig({\n  compatibilityDate: \"2025-05-15\",\n  ssr: false, \u002F\u002F SPA 模式\n\n  modules: [\n    \"@nuxt\u002Fui\",\n    \"@nuxt\u002Ftest-utils\u002Fmodule\",\n    \"@nuxt\u002Fimage\",\n    \"@nuxtjs\u002Fsupabase\",\n    \"@pinia\u002Fnuxt\",\n    \"@vueuse\u002Fnuxt\",\n    \"@sentry\u002Fnuxt\u002Fmodule\",\n    \"@onmax\u002Fnuxt-better-auth\",\n    \"@pinia\u002Fcolada-nuxt\",\n    \"nuxt-charts\",\n  ],\n\n  \u002F\u002F 元件目錄配置：移除路徑前綴\n  components: [\n    {\n      path: \"~\u002Fcomponents\",\n      pathPrefix: false, \u002F\u002F MachineTable.vue → \u003CMachineTable \u002F>\n    },\n  ],\n\n  \u002F\u002F Nitro 配置：部署到 Cloudflare Workers\n  nitro: {\n    preset: \"cloudflare_module\",\n    cloudflare: {\n      deployConfig: true,\n      nodeCompat: true,\n    },\n  },\n});\n","typescript","",[208,209,210,234,258,277,284,295,308,320,332,344,356,368,380,392,404,416,424,429,435,445,451,468,483,489,496,501,507,518,535,545,558,570,575,581],"code",{"__ignoreMap":206},[211,212,215,219,222,226,230],"span",{"class":213,"line":214},"line",1,[211,216,218],{"class":217},"sVHd0","export",[211,220,221],{"class":217}," default",[211,223,225],{"class":224},"sGLFI"," defineNuxtConfig",[211,227,229],{"class":228},"su5hD","(",[211,231,233],{"class":232},"sP7_E","{\n",[211,235,237,241,244,248,252,255],{"class":213,"line":236},2,[211,238,240],{"class":239},"skxfh","  compatibilityDate",[211,242,243],{"class":232},":",[211,245,247],{"class":246},"sjJ54"," \"",[211,249,251],{"class":250},"s_sjI","2025-05-15",[211,253,254],{"class":246},"\"",[211,256,257],{"class":232},",\n",[211,259,261,264,266,270,273],{"class":213,"line":260},3,[211,262,263],{"class":239},"  ssr",[211,265,243],{"class":232},[211,267,269],{"class":268},"syTEX"," false",[211,271,272],{"class":232},",",[211,274,276],{"class":275},"sutJx"," \u002F\u002F SPA 模式\n",[211,278,280],{"class":213,"line":279},4,[211,281,283],{"emptyLinePlaceholder":282},true,"\n",[211,285,287,290,292],{"class":213,"line":286},5,[211,288,289],{"class":239},"  modules",[211,291,243],{"class":232},[211,293,294],{"class":228}," [\n",[211,296,298,301,304,306],{"class":213,"line":297},6,[211,299,300],{"class":246},"    \"",[211,302,303],{"class":250},"@nuxt\u002Fui",[211,305,254],{"class":246},[211,307,257],{"class":232},[211,309,311,313,316,318],{"class":213,"line":310},7,[211,312,300],{"class":246},[211,314,315],{"class":250},"@nuxt\u002Ftest-utils\u002Fmodule",[211,317,254],{"class":246},[211,319,257],{"class":232},[211,321,323,325,328,330],{"class":213,"line":322},8,[211,324,300],{"class":246},[211,326,327],{"class":250},"@nuxt\u002Fimage",[211,329,254],{"class":246},[211,331,257],{"class":232},[211,333,335,337,340,342],{"class":213,"line":334},9,[211,336,300],{"class":246},[211,338,339],{"class":250},"@nuxtjs\u002Fsupabase",[211,341,254],{"class":246},[211,343,257],{"class":232},[211,345,347,349,352,354],{"class":213,"line":346},10,[211,348,300],{"class":246},[211,350,351],{"class":250},"@pinia\u002Fnuxt",[211,353,254],{"class":246},[211,355,257],{"class":232},[211,357,359,361,364,366],{"class":213,"line":358},11,[211,360,300],{"class":246},[211,362,363],{"class":250},"@vueuse\u002Fnuxt",[211,365,254],{"class":246},[211,367,257],{"class":232},[211,369,371,373,376,378],{"class":213,"line":370},12,[211,372,300],{"class":246},[211,374,375],{"class":250},"@sentry\u002Fnuxt\u002Fmodule",[211,377,254],{"class":246},[211,379,257],{"class":232},[211,381,383,385,388,390],{"class":213,"line":382},13,[211,384,300],{"class":246},[211,386,387],{"class":250},"@onmax\u002Fnuxt-better-auth",[211,389,254],{"class":246},[211,391,257],{"class":232},[211,393,395,397,400,402],{"class":213,"line":394},14,[211,396,300],{"class":246},[211,398,399],{"class":250},"@pinia\u002Fcolada-nuxt",[211,401,254],{"class":246},[211,403,257],{"class":232},[211,405,407,409,412,414],{"class":213,"line":406},15,[211,408,300],{"class":246},[211,410,411],{"class":250},"nuxt-charts",[211,413,254],{"class":246},[211,415,257],{"class":232},[211,417,419,422],{"class":213,"line":418},16,[211,420,421],{"class":228},"  ]",[211,423,257],{"class":232},[211,425,427],{"class":213,"line":426},17,[211,428,283],{"emptyLinePlaceholder":282},[211,430,432],{"class":213,"line":431},18,[211,433,434],{"class":275},"  \u002F\u002F 元件目錄配置：移除路徑前綴\n",[211,436,438,441,443],{"class":213,"line":437},19,[211,439,440],{"class":239},"  components",[211,442,243],{"class":232},[211,444,294],{"class":228},[211,446,448],{"class":213,"line":447},20,[211,449,450],{"class":232},"    {\n",[211,452,454,457,459,461,464,466],{"class":213,"line":453},21,[211,455,456],{"class":239},"      path",[211,458,243],{"class":232},[211,460,247],{"class":246},[211,462,463],{"class":250},"~\u002Fcomponents",[211,465,254],{"class":246},[211,467,257],{"class":232},[211,469,471,474,476,478,480],{"class":213,"line":470},22,[211,472,473],{"class":239},"      pathPrefix",[211,475,243],{"class":232},[211,477,269],{"class":268},[211,479,272],{"class":232},[211,481,482],{"class":275}," \u002F\u002F MachineTable.vue → \u003CMachineTable \u002F>\n",[211,484,486],{"class":213,"line":485},23,[211,487,488],{"class":232},"    },\n",[211,490,492,494],{"class":213,"line":491},24,[211,493,421],{"class":228},[211,495,257],{"class":232},[211,497,499],{"class":213,"line":498},25,[211,500,283],{"emptyLinePlaceholder":282},[211,502,504],{"class":213,"line":503},26,[211,505,506],{"class":275},"  \u002F\u002F Nitro 配置：部署到 Cloudflare Workers\n",[211,508,510,513,515],{"class":213,"line":509},27,[211,511,512],{"class":239},"  nitro",[211,514,243],{"class":232},[211,516,517],{"class":232}," {\n",[211,519,521,524,526,528,531,533],{"class":213,"line":520},28,[211,522,523],{"class":239},"    preset",[211,525,243],{"class":232},[211,527,247],{"class":246},[211,529,530],{"class":250},"cloudflare_module",[211,532,254],{"class":246},[211,534,257],{"class":232},[211,536,538,541,543],{"class":213,"line":537},29,[211,539,540],{"class":239},"    cloudflare",[211,542,243],{"class":232},[211,544,517],{"class":232},[211,546,548,551,553,556],{"class":213,"line":547},30,[211,549,550],{"class":239},"      deployConfig",[211,552,243],{"class":232},[211,554,555],{"class":268}," true",[211,557,257],{"class":232},[211,559,561,564,566,568],{"class":213,"line":560},31,[211,562,563],{"class":239},"      nodeCompat",[211,565,243],{"class":232},[211,567,555],{"class":268},[211,569,257],{"class":232},[211,571,573],{"class":213,"line":572},32,[211,574,488],{"class":232},[211,576,578],{"class":213,"line":577},33,[211,579,580],{"class":232},"  },\n",[211,582,584,587,590],{"class":213,"line":583},34,[211,585,586],{"class":232},"}",[211,588,589],{"class":228},")",[211,591,592],{"class":232},";\n",[41,594,596],{"id":595},"關於-ssr-false","關於 ssr: false",[15,598,599],{},"選擇 SPA 模式的場景：",[19,601,602,608,614],{},[22,603,604,607],{},[72,605,606],{},"Dashboard 應用","：需要登入才能使用，SEO 不重要",[22,609,610,613],{},[72,611,612],{},"企業內部系統","：使用者固定，不需要搜尋引擎索引",[22,615,616,619],{},[72,617,618],{},"降低複雜度","：不需處理 hydration mismatch",[15,621,622,623,626],{},"如果你的應用需要 SEO（如部落格、電商），請保持 ",[208,624,625],{},"ssr: true","。",[35,628],{},[11,630,631],{"id":631},"目錄結構設計",[201,633,638],{"className":634,"code":636,"language":637},[635],"language-text","project\u002F\n├── app\u002F                        # Client-side 程式碼\n│   ├── app.vue                 # 根元件\n│   ├── app.config.ts           # UI 主題設定\n│   ├── layouts\u002F                # 版面配置\n│   │   └── default.vue         # Dashboard 版面\n│   ├── pages\u002F                  # 檔案式路由\n│   ├── components\u002F             # Vue 元件（按功能分類）\n│   │   └── common\u002F             # 共用元件\n│   ├── composables\u002F            # Vue composables\n│   ├── stores\u002F                 # Pinia stores\n│   ├── queries\u002F                # Pinia Colada queries\n│   ├── types\u002F                  # TypeScript 類型\n│   │   └── database.types.ts   # Supabase 自動產生\n│   └── assets\u002F\n│       └── css\u002Fmain.css        # 全域樣式\n│\n├── server\u002F                     # Server-side 程式碼\n│   ├── api\u002F                    # API 端點\n│   │   ├── v1\u002F                 # 版本化業務 API\n│   │   ├── auth\u002F               # 認證相關\n│   │   └── admin\u002F              # 管理員專用\n│   ├── middleware\u002F             # Server middleware\n│   ├── utils\u002F                  # Server 工具函式\n│   │   └── supabase.ts         # Supabase client\n│   └── auth.config.ts          # Better Auth 設定\n│\n├── shared\u002F                     # 前後端共用\n│   └── types\u002F                  # 共用類型定義\n│\n├── test\u002F                       # 測試檔案\n│   ├── unit\u002F                   # 單元測試\n│   └── nuxt\u002F                   # Nuxt 環境測試\n│\n├── supabase\u002F                   # Supabase 設定\n│   └── migrations\u002F             # 資料庫 migration\n│\n├── docs\u002F                       # 專案文件\n│   └── verify\u002F                 # 狀態文件（非歷史紀錄）\n│\n└── .claude\u002F                    # AI 輔助開發\n    └── skills\u002F                 # AI Skills 定義\n","text",[208,639,636],{"__ignoreMap":206},[41,641,642],{"id":642},"為什麼這樣分層",[15,644,645],{},[72,646,647],{},"app\u002F vs server\u002F 分離的好處：",[138,649,650,656,662],{},[22,651,652,655],{},[72,653,654],{},"關注點分離","：前端邏輯與後端邏輯清楚區分",[22,657,658,661],{},[72,659,660],{},"安全性","：敏感邏輯只在 server\u002F 執行",[22,663,664,667],{},[72,665,666],{},"可測試性","：各層可以獨立測試",[15,669,670],{},[72,671,672],{},"shared\u002F 的用途：",[19,674,675,678],{},[22,676,677],{},"放置前後端共用的類型定義",[22,679,680],{},"Zod schema 可以在 client 驗證表單，也在 server 驗證請求",[35,682],{},[11,684,685],{"id":685},"踩坑經驗",[41,687,688],{"id":688},"目錄結構混亂的代價",[15,690,691],{},"早期專案沒有規劃好結構，導致：",[19,693,694,697,708],{},[22,695,696],{},"元件散落各處，難以找到",[22,698,699,700,703,704,707],{},"API 命名不一致（有的 ",[208,701,702],{},"\u002Fapi\u002Fusers","，有的 ",[208,705,706],{},"\u002Fapi\u002Fv1\u002Fuser","）",[22,709,710],{},"類型定義重複，維護困難",[15,712,713,716],{},[72,714,715],{},"解決方案","：建立明確的目錄結構規範，並在 CLAUDE.md 中記錄。",[41,718,720],{"id":719},"pathprefix-false-的影響","pathPrefix: false 的影響",[15,722,723],{},"預設情況下，Nuxt 會根據目錄結構產生元件名稱：",[201,725,728],{"className":726,"code":727,"language":637},[635],"components\u002F\n└── machines\u002F\n    └── MachineTable.vue  → \u003CMachinesMachineTable \u002F>\n",[208,729,727],{"__ignoreMap":206},[15,731,732,733,736],{},"設定 ",[208,734,735],{},"pathPrefix: false"," 後：",[201,738,741],{"className":739,"code":740,"language":637},[635],"components\u002F\n└── machines\u002F\n    └── MachineTable.vue  → \u003CMachineTable \u002F>\n",[208,742,740],{"__ignoreMap":206},[15,744,745,748],{},[72,746,747],{},"注意","：這樣做需要確保元件名稱在整個專案中唯一。",[35,750],{},[11,752,754],{"id":753},"常用-scripts","常用 Scripts",[201,756,760],{"className":757,"code":758,"language":759,"meta":206,"style":206},"language-json shiki shiki-themes material-theme-lighter github-light github-dark","{\n  \"scripts\": {\n    \"dev\": \"nuxt dev --dotenv .env -o\",\n    \"build\": \"nuxt build\",\n    \"check\": \"pnpm format && pnpm lint && pnpm typecheck && pnpm test\",\n    \"typecheck\": \"nuxt typecheck\",\n    \"test\": \"vitest run --coverage\",\n    \"db:reset\": \"supabase db reset\",\n    \"db:lint\": \"supabase db lint --level warning\",\n    \"db:types\": \"supabase gen types --lang=typescript --local | tee app\u002Ftypes\u002Fdatabase.types.ts > \u002Fdev\u002Fnull\"\n  }\n}\n","json",[208,761,762,766,782,803,823,843,863,883,903,923,942,947],{"__ignoreMap":206},[211,763,764],{"class":213,"line":214},[211,765,233],{"class":232},[211,767,768,772,776,778,780],{"class":213,"line":236},[211,769,771],{"class":770},"s39Yj","  \"",[211,773,775],{"class":774},"sseR_","scripts",[211,777,254],{"class":770},[211,779,243],{"class":232},[211,781,517],{"class":232},[211,783,784,786,790,792,794,796,799,801],{"class":213,"line":260},[211,785,300],{"class":770},[211,787,789],{"class":788},"sZMiF","dev",[211,791,254],{"class":770},[211,793,243],{"class":232},[211,795,247],{"class":246},[211,797,798],{"class":250},"nuxt dev --dotenv .env -o",[211,800,254],{"class":246},[211,802,257],{"class":232},[211,804,805,807,810,812,814,816,819,821],{"class":213,"line":279},[211,806,300],{"class":770},[211,808,809],{"class":788},"build",[211,811,254],{"class":770},[211,813,243],{"class":232},[211,815,247],{"class":246},[211,817,818],{"class":250},"nuxt build",[211,820,254],{"class":246},[211,822,257],{"class":232},[211,824,825,827,830,832,834,836,839,841],{"class":213,"line":286},[211,826,300],{"class":770},[211,828,829],{"class":788},"check",[211,831,254],{"class":770},[211,833,243],{"class":232},[211,835,247],{"class":246},[211,837,838],{"class":250},"pnpm format && pnpm lint && pnpm typecheck && pnpm test",[211,840,254],{"class":246},[211,842,257],{"class":232},[211,844,845,847,850,852,854,856,859,861],{"class":213,"line":297},[211,846,300],{"class":770},[211,848,849],{"class":788},"typecheck",[211,851,254],{"class":770},[211,853,243],{"class":232},[211,855,247],{"class":246},[211,857,858],{"class":250},"nuxt typecheck",[211,860,254],{"class":246},[211,862,257],{"class":232},[211,864,865,867,870,872,874,876,879,881],{"class":213,"line":310},[211,866,300],{"class":770},[211,868,869],{"class":788},"test",[211,871,254],{"class":770},[211,873,243],{"class":232},[211,875,247],{"class":246},[211,877,878],{"class":250},"vitest run --coverage",[211,880,254],{"class":246},[211,882,257],{"class":232},[211,884,885,887,890,892,894,896,899,901],{"class":213,"line":322},[211,886,300],{"class":770},[211,888,889],{"class":788},"db:reset",[211,891,254],{"class":770},[211,893,243],{"class":232},[211,895,247],{"class":246},[211,897,898],{"class":250},"supabase db reset",[211,900,254],{"class":246},[211,902,257],{"class":232},[211,904,905,907,910,912,914,916,919,921],{"class":213,"line":334},[211,906,300],{"class":770},[211,908,909],{"class":788},"db:lint",[211,911,254],{"class":770},[211,913,243],{"class":232},[211,915,247],{"class":246},[211,917,918],{"class":250},"supabase db lint --level warning",[211,920,254],{"class":246},[211,922,257],{"class":232},[211,924,925,927,930,932,934,936,939],{"class":213,"line":346},[211,926,300],{"class":770},[211,928,929],{"class":788},"db:types",[211,931,254],{"class":770},[211,933,243],{"class":232},[211,935,247],{"class":246},[211,937,938],{"class":250},"supabase gen types --lang=typescript --local | tee app\u002Ftypes\u002Fdatabase.types.ts > \u002Fdev\u002Fnull",[211,940,941],{"class":246},"\"\n",[211,943,944],{"class":213,"line":358},[211,945,946],{"class":232},"  }\n",[211,948,949],{"class":213,"line":370},[211,950,951],{"class":232},"}\n",[41,953,955],{"id":954},"pnpm-check-一條龍","pnpm check 一條龍",[201,957,961],{"className":958,"code":959,"language":960,"meta":206,"style":206},"language-bash shiki shiki-themes material-theme-lighter github-light github-dark","pnpm check\n# 等同於執行：\n# 1. pnpm format    - 程式碼格式化\n# 2. pnpm lint      - 程式碼檢查\n# 3. pnpm typecheck - 類型檢查\n# 4. pnpm test      - 執行測試\n","bash",[208,962,963,972,977,982,987,992],{"__ignoreMap":206},[211,964,965,969],{"class":213,"line":214},[211,966,968],{"class":967},"sbgvK","pnpm",[211,970,971],{"class":250}," check\n",[211,973,974],{"class":213,"line":236},[211,975,976],{"class":275},"# 等同於執行：\n",[211,978,979],{"class":213,"line":260},[211,980,981],{"class":275},"# 1. pnpm format    - 程式碼格式化\n",[211,983,984],{"class":213,"line":279},[211,985,986],{"class":275},"# 2. pnpm lint      - 程式碼檢查\n",[211,988,989],{"class":213,"line":286},[211,990,991],{"class":275},"# 3. pnpm typecheck - 類型檢查\n",[211,993,994],{"class":213,"line":297},[211,995,996],{"class":275},"# 4. pnpm test      - 執行測試\n",[35,998],{},[11,1000,1001],{"id":1001},"最佳實踐總結",[138,1003,1004,1010,1016,1022],{},[22,1005,1006,1009],{},[72,1007,1008],{},"技術選型要配合需求","：Dashboard 選 SPA，公開網站選 SSR",[22,1011,1012,1015],{},[72,1013,1014],{},"目錄結構要提前規劃","：app\u002F 放 client，server\u002F 放 API",[22,1017,1018,1021],{},[72,1019,1020],{},"共用邏輯放 shared\u002F","：類型、Zod schema 前後端共用",[22,1023,1024,1027],{},[72,1025,1026],{},"文件即規範","：在 CLAUDE.md 或 docs\u002F 記錄架構決策",[35,1029],{},[11,1031,1032],{"id":1032},"延伸閱讀",[19,1034,1035,1044,1051],{},[22,1036,1037],{},[1038,1039,1043],"a",{"href":1040,"rel":1041},"https:\u002F\u002Fnuxt.com\u002Fdocs",[1042],"nofollow","Nuxt 4 官方文件",[22,1045,1046],{},[1038,1047,1050],{"href":1048,"rel":1049},"https:\u002F\u002Fsupabase.com\u002Fdocs",[1042],"Supabase 文件",[22,1052,1053,1054],{},"下一篇：",[1038,1055,1057],{"href":1056},"\u002Fblog\u002Fnuxt\u002Fnuxt-ui-dashboard","Nuxt UI Dashboard 實戰",[1059,1060,1061],"style",{},"html pre.shiki code .sVHd0, html code.shiki .sVHd0{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#D73A49;--shiki-default-font-style:inherit;--shiki-dark:#F97583;--shiki-dark-font-style:inherit}html pre.shiki code .sGLFI, html code.shiki .sGLFI{--shiki-light:#6182B8;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .su5hD, html code.shiki .su5hD{--shiki-light:#90A4AE;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sP7_E, html code.shiki .sP7_E{--shiki-light:#39ADB5;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .skxfh, html code.shiki .skxfh{--shiki-light:#E53935;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sjJ54, html code.shiki .sjJ54{--shiki-light:#39ADB5;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .s_sjI, html code.shiki .s_sjI{--shiki-light:#91B859;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .syTEX, html code.shiki .syTEX{--shiki-light:#FF5370;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sutJx, html code.shiki .sutJx{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#6A737D;--shiki-default-font-style:inherit;--shiki-dark:#6A737D;--shiki-dark-font-style:inherit}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}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 .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s39Yj, html code.shiki .s39Yj{--shiki-light:#39ADB5;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sseR_, html code.shiki .sseR_{--shiki-light:#9C3EDA;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZMiF, html code.shiki .sZMiF{--shiki-light:#E2931D;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sbgvK, html code.shiki .sbgvK{--shiki-light:#E2931D;--shiki-default:#6F42C1;--shiki-dark:#B392F0}",{"title":206,"searchDepth":260,"depth":260,"links":1063},[1064,1065,1070,1073,1076,1080,1083,1084],{"id":13,"depth":236,"text":13},{"id":39,"depth":236,"text":39,"children":1066},[1067,1068,1069],{"id":43,"depth":260,"text":43},{"id":135,"depth":260,"text":136},{"id":166,"depth":260,"text":167},{"id":198,"depth":236,"text":199,"children":1071},[1072],{"id":595,"depth":260,"text":596},{"id":631,"depth":236,"text":631,"children":1074},[1075],{"id":642,"depth":260,"text":642},{"id":685,"depth":236,"text":685,"children":1077},[1078,1079],{"id":688,"depth":260,"text":688},{"id":719,"depth":260,"text":720},{"id":753,"depth":236,"text":754,"children":1081},[1082],{"id":954,"depth":260,"text":955},{"id":1001,"depth":236,"text":1001},{"id":1032,"depth":236,"text":1032},"Nuxt","2026-01-22","從技術選型到目錄結構，打造可維護的 Nuxt 4 + Supabase + Cloudflare Workers 全棧應用。",false,"md",null,{},"\u002Fblog\u002Fnuxt\u002Ffullstack-architecture",{"title":5,"description":1087},"nuxt-fullstack","Nuxt 4 全棧實戰筆記","blog\u002Fnuxt\u002Ffullstack-architecture\u002Findex",[1085,1098,1099],"TypeScript","Architecture","Tz5GTnR7_wV2nFtugKaUe5nwi89XhLI0Nde0I4g2UVc",1780512499430]