[{"data":1,"prerenderedAt":1302},["ShallowReactive",2],{"search-dialog-posts":3,"post-\u002Fposts\u002Fnuxt-route-rules-redirect":316,"post-surround-\u002Fposts\u002Fnuxt-route-rules-redirect":1295},[4,12,21,29,37,47,57,67,77,85,96,104,112,121,129,137,147,155,164,173,181,188,195,207,215,224,236,241,247,254,260,266,272,279,286,291,298,304,310],{"path":5,"title":6,"description":7,"category":8,"tags":9},"\u002Fposts\u002Fgit-commands-cheatsheet","Git 常用指令與終端機筆記","2018 年整理的 Git 學習筆記，包含基本終端機指令、Git 操作、分支、reset、SourceTree、Vim 與一些常用設定。","notes",[10,11],"Git","版本控制",{"path":13,"title":14,"description":15,"category":16,"tags":17},"\u002Fposts\u002Fjs-prototype-inheritance","JavaScript 物件導向：建構函式、prototype 與繼承三步驟","整理 ES5 時代用建構函式加 prototype 手刻物件導向的完整流程——封裝屬性與方法、共用函式為什麼要掛在 prototype 上、以及繼承的三個步驟（call 借用母類別建構子、Object.create 接上原型鏈、修正 constructor 指向），並附上物件縮寫與計算屬性這兩個順便學到的 ES6 寫法。","frontend",[18,19,20],"JavaScript","物件導向","prototype",{"path":22,"title":23,"description":24,"category":16,"tags":25},"\u002Fposts\u002Fflexbox-notes","Flexbox 對齊與彈性尺寸筆記","記錄 Flexbox 的主軸與交錯軸對齊、flex-direction、flex-wrap，以及 flex-grow、flex-shrink、flex-basis 等常用屬性。",[26,27,28],"CSS","Flexbox","版面",{"path":30,"title":31,"description":32,"category":16,"tags":33},"\u002Fposts\u002Fscreen-orientation-api","screen.orientation：現在判斷與鎖定螢幕方向的做法","整理現在 JavaScript 判斷螢幕方向的方式，包括 screen.orientation、change 事件與 lock()，並說明 RWD 使用 matchMedia 或 CSS orientation 會更適合。",[18,34,35,36],"RWD","螢幕方向","PWA",{"path":38,"title":39,"description":40,"category":16,"tags":41},"\u002Fposts\u002Fpinia-vuex-state-management","Pinia \u002F Vuex 狀態管理及差異","紀錄 Vuex、Pinia 的狀態管理概念、差異與用法。",[42,43,44,45,46],"Pinia","Vuex","Vue3","狀態管理","Nuxt",{"path":48,"title":49,"description":50,"category":8,"tags":51},"\u002Fposts\u002Fpyenv-python-version-management","Python 多版本管理 pyenv","紀錄 macOS 與 Windows 使用 pyenv 管理 Python 版本的方式。",[52,53,54,55,56],"Python","pyenv","macOS","Windows","版本管理",{"path":58,"title":59,"description":60,"category":8,"tags":61},"\u002Fposts\u002Fnpm-publish-vue2-component","npm 發布流程","紀錄 Vue 2 元件的 npm 發布、dist-tag 與打包流程。",[62,63,64,65,66],"npm","Vue2","Vue CLI","套件發布","MIT",{"path":68,"title":69,"description":70,"category":8,"tags":71},"\u002Fposts\u002Fmobile-debugging-today","現在怎麼 debug 手機網頁：從裝一堆工具到幾乎不用裝","對照 2022 年那套 scoop、iTunes、remotedebug-ios-webkit-adapter 的繁瑣設定，整理現在偵錯手機網頁的做法：Android 無線偵錯、iOS 的實際選項、on-device console、Playwright 裝置模擬，以及本機 HTTPS 的處理。",[72,73,74,75,76],"debug","iOS","Android","Chrome DevTools","Playwright",{"path":78,"title":79,"description":80,"category":16,"tags":81},"\u002Fposts\u002Fplaywright-vs-cypress","E2E 測試現在選什麼：Playwright 與 Cypress 的實際差異","對照幾年前用 Cypress 的做法，說明 Playwright 為什麼變成多數新專案的預設選擇：真正的多瀏覽器支援、免費的平行執行、trace viewer 除錯，以及兩者在架構上的根本差異與各自仍然適合的場景。",[76,82,83,84],"Cypress","E2E","測試",{"path":86,"title":87,"description":88,"category":89,"tags":90},"\u002Fposts\u002Fjs-encoding-today","現在處理編碼：TextEncoder、Uint8Array 的 Base64 方法與 URLSearchParams","整理 JavaScript 現代編碼方式，使用 TextEncoder、TextDecoder 與 Uint8Array 處理 UTF-8 與 Base64，並說明 Base64URL、URLSearchParams 與 encodeURIComponent 的差異。","research",[91,92,93,94,95,18],"編碼","TextEncoder","Base64","URLSearchParams","Uint8Array",{"path":97,"title":98,"description":99,"category":16,"tags":100},"\u002Fposts\u002Fdart-sass-migration","Dart Sass 遷移筆記：node-sass 之後怎麼裝 Sass","node-sass 與 LibSass 已停止維護，現在改用 Dart Sass。整理 webpack 與 Vite 的安裝方式，以及為什麼不再像 node-sass 一樣容易遇到 Node.js 版本與原生編譯問題。",[101,102,103],"Sass","Webpack","Vite",{"path":105,"title":106,"description":107,"category":16,"tags":108},"\u002Fposts\u002Fdayjs-vue3-computed","day.js 搭配 Vue 3 的日期格式化","整理 Vue 3 日期格式化的常見做法，使用 day.js 取代舊專案常見的 moment.js，並以 method 或 computed 取代 Vue 2 filter，也補充原生 Intl.DateTimeFormat 的使用方式。",[44,109,110,111],"day.js","日期","Intl",{"path":113,"title":114,"description":115,"category":16,"tags":116},"\u002Fposts\u002Fes-modules-today","ES Module 現在的樣子：Node ESM、exports 與 import maps","整理現代 JavaScript ES Module 的常見用法，包括 Node.js 原生 ESM、package.json exports、瀏覽器 import maps、JSON import attributes，以及 Vite 動態載入的注意事項。",[117,118,119,120,103,18],"ES Module","Node.js","import maps","exports",{"path":122,"title":123,"description":124,"category":89,"tags":125},"\u002Fposts\u002Fstructured-clone","structuredClone()：終於有內建的深層拷貝","整理 JavaScript structuredClone() 的深層拷貝用法，說明 Date、Map、Set、循環參考的處理方式，以及 Function、class 與 Vue reactive Proxy 的注意事項。",[18,126,127,128],"structuredClone","深拷貝","Vue",{"path":130,"title":131,"description":132,"category":16,"tags":133},"\u002Fposts\u002Fdynamic-import","JavaScript 動態載入：import() 與 Vue 非同步元件","整理靜態 import、動態 import() 與 Vue defineAsyncComponent 的使用方式，並簡單補充 Vite import.meta.glob 的用途。",[18,134,135,103,136],"ES Modules","Vue 3","Code Splitting",{"path":138,"title":139,"description":140,"category":16,"tags":141},"\u002Fposts\u002Fscreen-wake-lock-api","Screen Wake Lock API：不用套件也能讓頁面保持亮著","整理 Screen Wake Lock API 的基本用法，說明 HTTPS、頁面可見性、切換分頁後重新取得 wake lock，以及 Vue／Nuxt 計時器使用時的注意事項。",[142,128,143,144,145,146],"Wake Lock","Nuxt4","行動裝置","計時器","Web API",{"path":148,"title":149,"description":150,"category":16,"tags":151},"\u002Fposts\u002Fhtml-meta-boilerplate-today","現在的 HTML meta 標籤怎麼寫","整理現在一個新頁面該有的 meta 標籤骨架——viewport 補上 viewport-fit=cover 因應瀏海與圓角螢幕、color-scheme 讓表單控制項跟著深色模式換色、theme-color 決定行動瀏覽器工具列顏色，以及基本的 SEO 與 Open Graph 標籤。",[152,153,154],"HTML","meta","SEO",{"path":156,"title":157,"description":158,"category":8,"tags":159},"\u002Fposts\u002Fdocker-node-postgres","把 Node + PostgreSQL 的 backend 裝進 Docker：Dockerfile、.dockerignore 與 compose","從「本機裝了就跑」到打包成容器的通用做法——Dockerfile 每一行的理由與 layer cache 為什麼決定了指令順序、.dockerignore 漏掉 node_modules 對原生模組是災難級的問題、容器之間為什麼不能用 localhost 互相找到對方，以及怎麼驗證資料真的寫進了 volume。",[160,161,118,162,163],"Docker","Docker Compose","PostgreSQL","Express",{"path":165,"title":166,"description":167,"category":16,"tags":168},"\u002Fposts\u002Fnuxt-server-proxy","Nuxt 3 \u002F 4 用 Server API 做代理與轉發","整理 Nuxt 3 與 Nuxt 4 使用 server\u002Fapi 轉發第三方 API 的方式，可以避免瀏覽器 CORS 問題、隱藏 API Key，也能在伺服器端加入快取。",[169,143,170,171,172],"Nuxt3","CORS","Nitro","API",{"path":174,"title":175,"description":176,"category":16,"tags":177},"\u002Fposts\u002Fnuxt4-project-setup","Nuxt 4 建立專案：和 Nuxt 3 有哪些不同","整理 Nuxt 4 建立專案的基本流程與目錄結構，並對照 Nuxt 3 的差異，包括 app\u002F 目錄、路徑別名、TypeScript，以及目前常用的 ESLint 與 Tailwind CSS 4 設定。",[143,44,178,179,180],"TypeScript","ESLint","Tailwind CSS 4",{"path":182,"title":183,"description":184,"category":16,"tags":185},"\u002Fposts\u002Fnuxt3-route-middleware","Nuxt 3 \u002F 4 的 Route Middleware：進頁面前先做判斷","整理 Nuxt 3 與 Nuxt 4 的 Route Middleware，用 defineNuxtRouteMiddleware 在進入頁面前檢查登入狀態，搭配 navigateTo 重新導向，並說明一般 middleware、global middleware 與 definePageMeta 的用法。",[169,143,186,187],"Middleware","驗證",{"path":189,"title":190,"description":191,"category":16,"tags":192},"\u002Fposts\u002Fnuxt-route-rules-redirect","Nuxt 3 \u002F 4 的 routeRules：重新導向與頁面設定","整理 Nuxt 3 與 Nuxt 4 的 routeRules 用法，可以依照不同網址設定重新導向、預渲染、SSR 與快取，並簡單對照 Nuxt 2 的舊做法。",[169,143,193,194],"routeRules","重新導向",{"path":196,"title":197,"description":198,"category":16,"tags":199},"\u002Fposts\u002Fios-iframe-google-login-blank-page","iOS iframe 串接 Google 登入出現空白頁：Popup 與頁面回收問題排查紀錄","記錄 iframe 內串接 Google 第三方登入時，部分 iOS 裝置因背景頁面遭到回收並重新載入，導致 Popup 登入流程中斷，以及最後透過 Redirect 分流與登入狀態接回機制處理的過程。",[73,200,201,202,203,204,205,206],"Safari","iframe","Google Login","GIS","OAuth","Popup","Redirect",{"path":208,"title":209,"description":210,"category":16,"tags":211},"\u002Fposts\u002Fios-login-tab-return-behavior","iOS 第三方登入後回不到原頁？分頁開啟關係與回頁行為實測","記錄 iOS Safari 與 Chrome 在多分頁第三方登入流程中，登入頁關閉後不一定回到原頁的實測，以及分頁開啟關係、window.close 與 window.focus 的限制。",[73,200,212,202,204,201,213,214],"Chrome","window.close","window.focus",{"path":216,"title":217,"description":218,"category":16,"tags":219},"\u002Fposts\u002Fgoogle-app-about-blank-placeholder","Google App 內建瀏覽器：about:blank 佔位頁被關閉的排查紀錄","記錄 iOS Google App 內建瀏覽器在非同步開啟外部頁面時，about:blank 佔位分頁被自動關閉，導致第三方登入或外部導轉失敗的排查與解法。",[73,220,221,222,204,223],"Google App","window.open","about:blank","WebView",{"path":225,"title":226,"description":227,"category":228,"tags":229},"\u002Fposts\u002Fclaude-code-codex-cli-init-basics","AI 相關紀錄 v1｜Claude Code \u002F Codex CLI 初始化與基本概念","從 Claude Code 與 Codex CLI 開始，整理 CLI、Coding Agent、Context、\u002Finit 與 CLAUDE.md／AGENTS.md 這幾個一開始最容易搞混的概念，以及在既有專案中的安裝與啟動方式。","ai",[230,231,232,233,234,235],"AI","Claude Code","Codex CLI","Coding Agent","CLAUDE.md","AGENTS.md",{"path":237,"title":238,"description":239,"category":228,"tags":240},"\u002Fposts\u002Fclaude-agents-md-project-guidelines","AI 相關紀錄 v2｜CLAUDE.md \u002F AGENTS.md 怎麼寫？專案規範與實際範例","整理 CLAUDE.md 與 AGENTS.md 的用途、適合記錄的專案規範，以及可直接參考的設定範例。",[230,231,232,234,235],{"path":242,"title":243,"description":244,"category":228,"tags":245},"\u002Fposts\u002Fclaude-codex-config-locations","AI 相關紀錄 v3｜Claude Code `.claude\u002F` \u002F Codex CLI 設定位置：全域與專案設定基本概要介紹","整理 Claude Code 與 Codex CLI 的使用者層級、專案層級設定位置，以及 rules、skills、agents 等目錄的用途。",[230,231,232,246],"設定檔",{"path":248,"title":249,"description":250,"category":228,"tags":251},"\u002Fposts\u002Fclaude-settings-codex-config","AI 相關紀錄 v4｜Claude Code settings \u002F Codex config 基本設定","整理 Claude Code settings.json 與 Codex config.toml 的設定層級、權限控制和常見基本設定。",[230,231,232,252,253],"settings.json","config.toml",{"path":255,"title":256,"description":257,"category":228,"tags":258},"\u002Fposts\u002Fclaude-codex-rules-structure","AI 相關紀錄 v5｜Rules：專案規則多了之後怎麼拆？","整理 Claude Code Rules 與 Codex AGENTS.md 的拆分方式，說明何時該拆、怎麼依目錄管理專案規則。",[230,231,232,259,235],"Rules",{"path":261,"title":262,"description":263,"category":228,"tags":264},"\u002Fposts\u002Fclaude-codex-slash-commands","AI 相關紀錄 v6｜Commands \u002F Slash Commands：CLI 裡的 `\u002F` 指令是什麼？","介紹 Claude Code 與 Codex CLI 的 Slash Commands，整理常用內建指令、自訂指令與 Skills 的差異。",[230,231,232,265],"Slash Commands",{"path":267,"title":268,"description":269,"category":228,"tags":270},"\u002Fposts\u002Fclaude-codex-skills","AI 相關紀錄 v7｜Skills：把重複工作流程整理起來","介紹 Claude Code 與 Codex Skills，整理適合保存成 Skill 的重複流程、基本結構與使用方式。",[230,231,232,271],"Skills",{"path":273,"title":274,"description":275,"category":228,"tags":276},"\u002Fposts\u002Fclaude-codex-agents-subagents","AI 相關紀錄 v8｜Agent \u002F Subagent：什麼時候真的需要分工？","整理 Agent、Subagent 與 Custom Agent 的用途，說明何時適合分工，以及它們和 Rules、Skills 的差異。",[230,231,232,277,278],"Agent","Subagent",{"path":280,"title":281,"description":282,"category":228,"tags":283},"\u002Fposts\u002Fmcp-basics","AI 相關紀錄 v9｜MCP：讓 AI 使用其他工具與資料","介紹 MCP 如何讓 AI 使用外部工具與資料，並以 Pencil MCP 說明實際用途、權限風險及與 Skill 的差異。",[230,284,231,232,285],"MCP","Pencil",{"path":287,"title":288,"description":289,"category":228,"tags":290},"\u002Fposts\u002Fai-coding-agent-concepts-summary","AI 相關紀錄 v10｜基本概念小結論","用一篇快速整理 CLAUDE.md、AGENTS.md、設定檔、Rules、Commands、Skills、Agent 與 MCP 的角色和差異。",[230,231,232,284,271,277],{"path":292,"title":293,"description":294,"category":228,"tags":295},"\u002Fposts\u002Fclaude-code-codex-model-selection","Claude Code 與 Codex：不同模型怎麼選？","比較 Claude Code 與 Codex 不同模型的速度、能力與成本取捨，依工作難度整理實用的選擇方向。",[230,231,296,297],"Codex","模型選擇",{"path":299,"title":300,"description":301,"category":228,"tags":302},"\u002Fposts\u002Fclaude-model-selection","Claude 模型簡單怎麼選？","整理 Claude 各模型在速度、能力與使用情境上的差異，提供從輕量工作到複雜任務的選擇方向。",[230,231,303,297],"Claude",{"path":305,"title":306,"description":307,"category":228,"tags":308},"\u002Fposts\u002Fcodex-model-selection","Codex 模型簡單怎麼選？","整理 Codex 各模型在速度、能力與使用情境上的差異，提供從簡單修改到大型端到端任務的選擇方向。",[230,296,309,297],"OpenAI",{"path":311,"title":312,"description":313,"category":228,"tags":314},"\u002Fposts\u002Fclaude-code-codex-cli-command-cheatsheet","Claude Code \u002F Codex CLI 常用指令速查表","整理 Claude Code 與 Codex CLI 的常用斜線指令、快捷操作與進階功能，方便需要時快速查找。",[230,231,232,265,315],"速查表",{"id":317,"title":190,"body":318,"category":16,"description":191,"draft":1285,"extension":1286,"image":1287,"meta":1288,"navigation":721,"path":189,"publishedAt":1289,"relatedExperiments":1290,"seo":1291,"stem":1292,"tags":1293,"updatedAt":1289,"__hash__":1294},"posts\u002Fposts\u002F20260629.nuxt-route-rules-redirect.md",{"type":319,"value":320,"toc":1272},"minimark",[321,329,338,341,351,358,361,364,435,438,444,447,453,456,501,504,511,581,584,590,593,596,601,646,648,654,657,663,668,672,677,679,844,847,853,859,862,869,873,877,901,904,909,912,918,921,925,948,950,955,957,963,966,970,1061,1064,1070,1073,1079,1084,1087,1090,1096,1099,1132,1135,1220,1226,1233,1236,1263,1268],[322,323,324,325,328],"p",{},"Nuxt 2 時期如果要處理重新導向，常會去修改 router。\n到了 Nuxt 3，開始可以使用 ",[326,327,193],"code",{},"；Nuxt 4 也延續相同的做法。\n可以先把它理解成：",[330,331,332],"blockquote",{},[322,333,334],{},[335,336,337],"strong",{},"告訴 Nuxt「某個網址要怎麼處理」。",[322,339,340],{},"例如：",[342,343,349],"pre",{"className":344,"code":346,"language":347,"meta":348},[345],"language-text","\u002Fold-page\n→ 重新導向\n\n\u002Fblog\u002F**\n→ 預先產生 HTML\n\n\u002Fadmin\u002F**\n→ 不做 SSR\n\n\u002Fapi\u002F**\n→ 加上快取\n","text","",[326,350,346],{"__ignoreMap":348},[322,352,353,354,357],{},"這些都可以集中寫在 ",[326,355,356],{},"nuxt.config.ts","。",[359,360,194],"h2",{"id":194},[322,362,363],{},"最基本的例子：",[342,365,369],{"className":366,"code":367,"language":368,"meta":348,"style":348},"language-ts shiki shiki-themes github-light github-dark-default","export default defineNuxtConfig({\n  routeRules: {\n    '\u002Fold-page': {\n      redirect: '\u002Fnew-page'\n    }\n  }\n})\n","ts",[326,370,371,391,398,408,417,423,429],{"__ignoreMap":348},[372,373,376,380,383,387],"span",{"class":374,"line":375},"line",1,[372,377,379],{"class":378},"sDgYj","export",[372,381,382],{"class":378}," default",[372,384,386],{"class":385},"sVjZL"," defineNuxtConfig",[372,388,390],{"class":389},"sfpNf","({\n",[372,392,394],{"class":374,"line":393},2,[372,395,397],{"class":396},"szmH1","  routeRules: {\n",[372,399,401,405],{"class":374,"line":400},3,[372,402,404],{"class":403},"sNbzA","    '\u002Fold-page'",[372,406,407],{"class":396},": {\n",[372,409,411,414],{"class":374,"line":410},4,[372,412,413],{"class":396},"      redirect: ",[372,415,416],{"class":403},"'\u002Fnew-page'\n",[372,418,420],{"class":374,"line":419},5,[372,421,422],{"class":396},"    }\n",[372,424,426],{"class":374,"line":425},6,[372,427,428],{"class":396},"  }\n",[372,430,432],{"class":374,"line":431},7,[372,433,434],{"class":389},"})\n",[322,436,437],{},"使用者進入：",[342,439,442],{"className":440,"code":441,"language":347,"meta":348},[345],"\u002Fold-page\n",[326,443,441],{"__ignoreMap":348},[322,445,446],{},"就會被帶到：",[342,448,451],{"className":449,"code":450,"language":347,"meta":348},[345],"\u002Fnew-page\n",[326,452,450],{"__ignoreMap":348},[322,454,455],{},"例如首頁進入後直接導向登入頁：",[342,457,459],{"className":366,"code":458,"language":368,"meta":348,"style":348},"export default defineNuxtConfig({\n  routeRules: {\n    '\u002F': {\n      redirect: '\u002Flogin'\n    }\n  }\n})\n",[326,460,461,471,475,482,489,493,497],{"__ignoreMap":348},[372,462,463,465,467,469],{"class":374,"line":375},[372,464,379],{"class":378},[372,466,382],{"class":378},[372,468,386],{"class":385},[372,470,390],{"class":389},[372,472,473],{"class":374,"line":393},[372,474,397],{"class":396},[372,476,477,480],{"class":374,"line":400},[372,478,479],{"class":403},"    '\u002F'",[372,481,407],{"class":396},[372,483,484,486],{"class":374,"line":410},[372,485,413],{"class":396},[372,487,488],{"class":403},"'\u002Flogin'\n",[372,490,491],{"class":374,"line":419},[372,492,422],{"class":396},[372,494,495],{"class":374,"line":425},[372,496,428],{"class":396},[372,498,499],{"class":374,"line":431},[372,500,434],{"class":389},[359,502,503],{"id":503},"永久搬家的網址",[322,505,506,507,510],{},"如果舊網址確定不會再使用，可以明確設定 ",[326,508,509],{},"301","：",[342,512,514],{"className":366,"code":513,"language":368,"meta":348,"style":348},"export default defineNuxtConfig({\n  routeRules: {\n    '\u002Fold-page': {\n      redirect: {\n        to: '\u002Fnew-page',\n        statusCode: 301\n      }\n    }\n  }\n})\n",[326,515,516,526,530,536,541,552,561,566,571,576],{"__ignoreMap":348},[372,517,518,520,522,524],{"class":374,"line":375},[372,519,379],{"class":378},[372,521,382],{"class":378},[372,523,386],{"class":385},[372,525,390],{"class":389},[372,527,528],{"class":374,"line":393},[372,529,397],{"class":396},[372,531,532,534],{"class":374,"line":400},[372,533,404],{"class":403},[372,535,407],{"class":396},[372,537,538],{"class":374,"line":410},[372,539,540],{"class":396},"      redirect: {\n",[372,542,543,546,549],{"class":374,"line":419},[372,544,545],{"class":396},"        to: ",[372,547,548],{"class":403},"'\u002Fnew-page'",[372,550,551],{"class":396},",\n",[372,553,554,557],{"class":374,"line":425},[372,555,556],{"class":396},"        statusCode: ",[372,558,560],{"class":559},"sPgVT","301\n",[372,562,563],{"class":374,"line":431},[372,564,565],{"class":396},"      }\n",[372,567,569],{"class":374,"line":568},8,[372,570,422],{"class":396},[372,572,574],{"class":374,"line":573},9,[372,575,428],{"class":396},[372,577,579],{"class":374,"line":578},10,[372,580,434],{"class":389},[322,582,583],{},"這種比較適合：",[342,585,588],{"className":586,"code":587,"language":347,"meta":348},[345],"舊文章網址\n→ 新文章網址\n\n舊分類\n→ 新分類\n",[326,589,587],{"__ignoreMap":348},[322,591,592],{},"尤其網站已經被搜尋引擎收錄時，應該明確處理重新導向。",[359,594,595],{"id":595},"一次設定整個路徑",[322,597,598,600],{},[326,599,193],{}," 也可以使用萬用路徑：",[342,602,604],{"className":366,"code":603,"language":368,"meta":348,"style":348},"export default defineNuxtConfig({\n  routeRules: {\n    '\u002Fold\u002F**': {\n      redirect: '\u002Fnew\u002F**'\n    }\n  }\n})\n",[326,605,606,616,620,627,634,638,642],{"__ignoreMap":348},[372,607,608,610,612,614],{"class":374,"line":375},[372,609,379],{"class":378},[372,611,382],{"class":378},[372,613,386],{"class":385},[372,615,390],{"class":389},[372,617,618],{"class":374,"line":393},[372,619,397],{"class":396},[372,621,622,625],{"class":374,"line":400},[372,623,624],{"class":403},"    '\u002Fold\u002F**'",[372,626,407],{"class":396},[372,628,629,631],{"class":374,"line":410},[372,630,413],{"class":396},[372,632,633],{"class":403},"'\u002Fnew\u002F**'\n",[372,635,636],{"class":374,"line":419},[372,637,422],{"class":396},[372,639,640],{"class":374,"line":425},[372,641,428],{"class":396},[372,643,644],{"class":374,"line":431},[372,645,434],{"class":389},[322,647,340],{},[342,649,652],{"className":650,"code":651,"language":347,"meta":348},[345],"\u002Fold\u002Fabout\n\u002Fold\u002Fposts\u002F123\n\u002Fold\u002Fcategory\u002Ffrontend\n",[326,653,651],{"__ignoreMap":348},[322,655,656],{},"都可以套用同一組規則。",[322,658,659,662],{},[326,660,661],{},"**"," 可以簡單理解成：",[330,664,665],{},[322,666,667],{},"這個路徑底下的所有內容。",[359,669,671],{"id":670},"routerules-不只是重新導向","routeRules 不只是重新導向",[322,673,674,676],{},[326,675,193],{}," 還可以設定不同頁面的渲染方式。",[322,678,340],{},[342,680,682],{"className":366,"code":681,"language":368,"meta":348,"style":348},"export default defineNuxtConfig({\n  routeRules: {\n    '\u002F': {\n      prerender: true\n    },\n\n    '\u002Fblog\u002F**': {\n      prerender: true\n    },\n\n    '\u002Fadmin\u002F**': {\n      ssr: false\n    },\n\n    '\u002Fapi\u002Fdata': {\n      cache: {\n        maxAge: 60 * 10\n      }\n    },\n\n    '\u002Fold-page': {\n      redirect: '\u002Fnew-page'\n    }\n  }\n})\n",[326,683,684,694,698,704,712,717,723,730,736,740,744,752,761,766,771,779,785,800,805,810,815,822,829,834,839],{"__ignoreMap":348},[372,685,686,688,690,692],{"class":374,"line":375},[372,687,379],{"class":378},[372,689,382],{"class":378},[372,691,386],{"class":385},[372,693,390],{"class":389},[372,695,696],{"class":374,"line":393},[372,697,397],{"class":396},[372,699,700,702],{"class":374,"line":400},[372,701,479],{"class":403},[372,703,407],{"class":396},[372,705,706,709],{"class":374,"line":410},[372,707,708],{"class":396},"      prerender: ",[372,710,711],{"class":559},"true\n",[372,713,714],{"class":374,"line":419},[372,715,716],{"class":396},"    },\n",[372,718,719],{"class":374,"line":425},[372,720,722],{"emptyLinePlaceholder":721},true,"\n",[372,724,725,728],{"class":374,"line":431},[372,726,727],{"class":403},"    '\u002Fblog\u002F**'",[372,729,407],{"class":396},[372,731,732,734],{"class":374,"line":568},[372,733,708],{"class":396},[372,735,711],{"class":559},[372,737,738],{"class":374,"line":573},[372,739,716],{"class":396},[372,741,742],{"class":374,"line":578},[372,743,722],{"emptyLinePlaceholder":721},[372,745,747,750],{"class":374,"line":746},11,[372,748,749],{"class":403},"    '\u002Fadmin\u002F**'",[372,751,407],{"class":396},[372,753,755,758],{"class":374,"line":754},12,[372,756,757],{"class":396},"      ssr: ",[372,759,760],{"class":559},"false\n",[372,762,764],{"class":374,"line":763},13,[372,765,716],{"class":396},[372,767,769],{"class":374,"line":768},14,[372,770,722],{"emptyLinePlaceholder":721},[372,772,774,777],{"class":374,"line":773},15,[372,775,776],{"class":403},"    '\u002Fapi\u002Fdata'",[372,778,407],{"class":396},[372,780,782],{"class":374,"line":781},16,[372,783,784],{"class":396},"      cache: {\n",[372,786,788,791,794,797],{"class":374,"line":787},17,[372,789,790],{"class":396},"        maxAge: ",[372,792,793],{"class":559},"60",[372,795,796],{"class":378}," *",[372,798,799],{"class":559}," 10\n",[372,801,803],{"class":374,"line":802},18,[372,804,565],{"class":396},[372,806,808],{"class":374,"line":807},19,[372,809,716],{"class":396},[372,811,813],{"class":374,"line":812},20,[372,814,722],{"emptyLinePlaceholder":721},[372,816,818,820],{"class":374,"line":817},21,[372,819,404],{"class":403},[372,821,407],{"class":396},[372,823,825,827],{"class":374,"line":824},22,[372,826,413],{"class":396},[372,828,416],{"class":403},[372,830,832],{"class":374,"line":831},23,[372,833,422],{"class":396},[372,835,837],{"class":374,"line":836},24,[372,838,428],{"class":396},[372,840,842],{"class":374,"line":841},25,[372,843,434],{"class":389},[322,845,846],{},"可以白話理解成：",[342,848,851],{"className":849,"code":850,"language":347,"meta":348},[345],"\u002F\n→ 建置時先產生 HTML\n\n\u002Fblog\u002F**\n→ 部落格文章也先產生 HTML\n\n\u002Fadmin\u002F**\n→ 只在瀏覽器執行，不做 SSR\n\n\u002Fapi\u002Fdata\n→ 快取 10 分鐘\n\n\u002Fold-page\n→ 導到 \u002Fnew-page\n",[326,852,850],{"__ignoreMap":348},[322,854,855,856,858],{},"所以 ",[326,857,193],{}," 不只是 redirect。",[322,860,861],{},"它比較像是：",[330,863,864],{},[322,865,866],{},[335,867,868],{},"每個網址的處理規則表。",[359,870,872],{"id":871},"prerender-與-ssr-是什麼","prerender 與 ssr 是什麼？",[874,875,876],"h3",{"id":876},"prerender",[342,878,880],{"className":366,"code":879,"language":368,"meta":348,"style":348},"'\u002Fabout': {\n  prerender: true\n}\n",[326,881,882,889,896],{"__ignoreMap":348},[372,883,884,887],{"class":374,"line":375},[372,885,886],{"class":403},"'\u002Fabout'",[372,888,407],{"class":396},[372,890,891,894],{"class":374,"line":393},[372,892,893],{"class":396},"  prerender: ",[372,895,711],{"class":559},[372,897,898],{"class":374,"line":400},[372,899,900],{"class":396},"}\n",[322,902,903],{},"代表：",[330,905,906],{},[322,907,908],{},"build 的時候就先把這個頁面的 HTML 做好。",[322,910,911],{},"比較適合：",[342,913,916],{"className":914,"code":915,"language":347,"meta":348},[345],"首頁\n關於我\n文章\n說明頁面\n",[326,917,915],{"__ignoreMap":348},[322,919,920],{},"這些內容不需要每次有人進來都重新產生。",[874,922,924],{"id":923},"ssr-false","ssr: false",[342,926,928],{"className":366,"code":927,"language":368,"meta":348,"style":348},"'\u002Fadmin\u002F**': {\n  ssr: false\n}\n",[326,929,930,937,944],{"__ignoreMap":348},[372,931,932,935],{"class":374,"line":375},[372,933,934],{"class":403},"'\u002Fadmin\u002F**'",[372,936,407],{"class":396},[372,938,939,942],{"class":374,"line":393},[372,940,941],{"class":396},"  ssr: ",[372,943,760],{"class":559},[372,945,946],{"class":374,"line":400},[372,947,900],{"class":396},[322,949,903],{},[330,951,952],{},[322,953,954],{},"這些頁面不要在伺服器產生 HTML，交給瀏覽器執行。",[322,956,340],{},[342,958,961],{"className":959,"code":960,"language":347,"meta":348},[345],"後台\n管理系統\n不需要 SEO 的工具頁\n",[326,962,960],{"__ignoreMap":348},[322,964,965],{},"可以視需求使用。",[359,967,969],{"id":968},"nuxt-234-差在哪","Nuxt 2、3、4 差在哪？",[971,972,973,991],"table",{},[974,975,976],"thead",{},[977,978,979,982,985,988],"tr",{},[980,981],"th",{},[980,983,984],{},"Nuxt 2",[980,986,987],{},"Nuxt 3",[980,989,990],{},"Nuxt 4",[992,993,994,1010,1029,1045],"tbody",{},[977,995,996,999,1002,1006],{},[997,998,194],"td",{},[997,1000,1001],{},"修改 router \u002F middleware 等方式",[997,1003,1004],{},[326,1005,193],{},[997,1007,1008],{},[326,1009,193],{},[977,1011,1012,1015,1021,1025],{},[997,1013,1014],{},"預渲染設定",[997,1016,1017,1020],{},[326,1018,1019],{},"generate"," 等設定",[997,1022,1023],{},[326,1024,193],{},[997,1026,1027],{},[326,1028,193],{},[977,1030,1031,1034,1037,1041],{},[997,1032,1033],{},"單一路徑關閉 SSR",[997,1035,1036],{},"沒有現在這種統一寫法",[997,1038,1039],{},[326,1040,193],{},[997,1042,1043],{},[326,1044,193],{},[977,1046,1047,1050,1053,1057],{},[997,1048,1049],{},"路由快取",[997,1051,1052],{},"需另外處理",[997,1054,1055],{},[326,1056,193],{},[997,1058,1059],{},[326,1060,193],{},[322,1062,1063],{},"所以如果是從 Nuxt 3 升到 Nuxt 4：",[342,1065,1068],{"className":1066,"code":1067,"language":347,"meta":348},[345],"routeRules 基本上不用重新學。\n",[326,1069,1067],{"__ignoreMap":348},[322,1071,1072],{},"真正變比較大的反而是 Nuxt 4 的：",[342,1074,1077],{"className":1075,"code":1076,"language":347,"meta":348},[345],"app\u002F\nshared\u002F\n目錄結構\n",[326,1078,1076],{"__ignoreMap":348},[322,1080,1081,1083],{},[326,1082,193],{}," 本身則是延續 Nuxt 3 的概念。",[359,1085,1086],{"id":1086},"小結",[322,1088,1089],{},"Nuxt 3 與 Nuxt 4 都可以在：",[342,1091,1094],{"className":1092,"code":1093,"language":347,"meta":348},[345],"nuxt.config.ts\n",[326,1095,1093],{"__ignoreMap":348},[322,1097,1098],{},"使用：",[342,1100,1102],{"className":366,"code":1101,"language":368,"meta":348,"style":348},"routeRules: {\n  '\u002F某個網址': {\n    \u002F\u002F 這個網址要套用的規則\n  }\n}\n",[326,1103,1104,1111,1118,1124,1128],{"__ignoreMap":348},[372,1105,1106,1109],{"class":374,"line":375},[372,1107,193],{"class":1108},"sYRkA",[372,1110,407],{"class":396},[372,1112,1113,1116],{"class":374,"line":393},[372,1114,1115],{"class":403},"  '\u002F某個網址'",[372,1117,407],{"class":396},[372,1119,1120],{"class":374,"line":400},[372,1121,1123],{"class":1122},"sPyeA","    \u002F\u002F 這個網址要套用的規則\n",[372,1125,1126],{"class":374,"line":410},[372,1127,428],{"class":396},[372,1129,1130],{"class":374,"line":419},[372,1131,900],{"class":396},[322,1133,1134],{},"最常見的幾個用途：",[342,1136,1138],{"className":366,"code":1137,"language":368,"meta":348,"style":348},"\u002F\u002F 重新導向\nredirect: '\u002Fnew-page'\n\n\u002F\u002F 預先產生 HTML\nprerender: true\n\n\u002F\u002F 關閉 SSR\nssr: false\n\n\u002F\u002F 快取\ncache: {\n  maxAge: 600\n}\n",[326,1139,1140,1145,1155,1159,1164,1172,1176,1181,1190,1194,1199,1206,1216],{"__ignoreMap":348},[372,1141,1142],{"class":374,"line":375},[372,1143,1144],{"class":1122},"\u002F\u002F 重新導向\n",[372,1146,1147,1150,1153],{"class":374,"line":393},[372,1148,1149],{"class":1108},"redirect",[372,1151,1152],{"class":396},": ",[372,1154,416],{"class":403},[372,1156,1157],{"class":374,"line":400},[372,1158,722],{"emptyLinePlaceholder":721},[372,1160,1161],{"class":374,"line":410},[372,1162,1163],{"class":1122},"\u002F\u002F 預先產生 HTML\n",[372,1165,1166,1168,1170],{"class":374,"line":419},[372,1167,876],{"class":1108},[372,1169,1152],{"class":396},[372,1171,711],{"class":559},[372,1173,1174],{"class":374,"line":425},[372,1175,722],{"emptyLinePlaceholder":721},[372,1177,1178],{"class":374,"line":431},[372,1179,1180],{"class":1122},"\u002F\u002F 關閉 SSR\n",[372,1182,1183,1186,1188],{"class":374,"line":568},[372,1184,1185],{"class":1108},"ssr",[372,1187,1152],{"class":396},[372,1189,760],{"class":559},[372,1191,1192],{"class":374,"line":573},[372,1193,722],{"emptyLinePlaceholder":721},[372,1195,1196],{"class":374,"line":578},[372,1197,1198],{"class":1122},"\u002F\u002F 快取\n",[372,1200,1201,1204],{"class":374,"line":746},[372,1202,1203],{"class":1108},"cache",[372,1205,407],{"class":396},[372,1207,1208,1211,1213],{"class":374,"line":754},[372,1209,1210],{"class":1108},"  maxAge",[372,1212,1152],{"class":396},[372,1214,1215],{"class":559},"600\n",[372,1217,1218],{"class":374,"line":763},[372,1219,900],{"class":396},[322,1221,1222,1223,1225],{},"所以可以直接把 ",[326,1224,193],{}," 記成：",[330,1227,1228],{},[322,1229,1230],{},[335,1231,1232],{},"依照網址，告訴 Nuxt 這個頁面要怎麼處理。",[359,1234,1235],{"id":1235},"參考資料",[1237,1238,1239,1249,1256],"ul",{},[1240,1241,1242],"li",{},[1243,1244,1248],"a",{"href":1245,"rel":1246},"https:\u002F\u002Fnuxt.com\u002Fdocs\u002F4.x\u002Fguide\u002Fconcepts\u002Frendering",[1247],"nofollow","Nuxt 4：Rendering Modes",[1240,1250,1251],{},[1243,1252,1255],{"href":1253,"rel":1254},"https:\u002F\u002Fnuxt.com\u002Fdocs\u002F4.x\u002Fgetting-started\u002Fserver",[1247],"Nuxt 4：Server",[1240,1257,1258],{},[1243,1259,1262],{"href":1260,"rel":1261},"https:\u002F\u002Fnuxt.com\u002Fdocs\u002F3.x\u002Fguide\u002Fconcepts\u002Frendering",[1247],"Nuxt 3：Rendering Modes",[342,1264,1266],{"className":1265,"code":348,"language":347},[345],[326,1267,348],{"__ignoreMap":348},[1269,1270,1271],"style",{},"html pre.shiki code .sDgYj, html code.shiki .sDgYj{--shiki-default:#D73A49;--shiki-dark:#FF7B72}html pre.shiki code .sVjZL, html code.shiki .sVjZL{--shiki-default:#6F42C1;--shiki-dark:#D2A8FF}html pre.shiki code .sfpNf, html code.shiki .sfpNf{--shiki-default:#24292E;--shiki-dark:#FFA657}html pre.shiki code .szmH1, html code.shiki .szmH1{--shiki-default:#24292E;--shiki-dark:#E6EDF3}html pre.shiki code .sNbzA, html code.shiki .sNbzA{--shiki-default:#032F62;--shiki-dark:#A5D6FF}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 .sPgVT, html code.shiki .sPgVT{--shiki-default:#005CC5;--shiki-dark:#79C0FF}html pre.shiki code .sYRkA, html code.shiki .sYRkA{--shiki-default:#6F42C1;--shiki-dark:#FFA657}html pre.shiki code .sPyeA, html code.shiki .sPyeA{--shiki-default:#6A737D;--shiki-dark:#8B949E}",{"title":348,"searchDepth":400,"depth":400,"links":1273},[1274,1275,1276,1277,1278,1282,1283,1284],{"id":194,"depth":393,"text":194},{"id":503,"depth":393,"text":503},{"id":595,"depth":393,"text":595},{"id":670,"depth":393,"text":671},{"id":871,"depth":393,"text":872,"children":1279},[1280,1281],{"id":876,"depth":400,"text":876},{"id":923,"depth":400,"text":924},{"id":968,"depth":393,"text":969},{"id":1086,"depth":393,"text":1086},{"id":1235,"depth":393,"text":1235},false,"md",null,{},"2026-06-29",[],{"title":190,"description":191},"posts\u002F20260629.nuxt-route-rules-redirect",[169,143,193,194],"C6cEjhlOhb55ZshleUrttoMPZEKDcbBiEHzygvK1kLA",[1296,1299],{"title":197,"path":196,"stem":1297,"description":198,"category":16,"publishedAt":1298,"children":-1},"posts\u002F20260724.ios-iframe-google-login-blank-page","2026-07-24",{"title":183,"path":182,"stem":1300,"description":184,"category":16,"publishedAt":1301,"children":-1},"posts\u002F20260625.nuxt3-route-middleware","2026-06-25",1791786900976]