04 / WORK / CASE STUDY
Naily 電商前台與 Canvas 客製化設計工具
穿戴甲品牌的消費端電商前台:購物流程、金流發票、四種社群登入,以及瀏覽器內 Canvas 客製化設計編輯器;涵蓋 CRA 商城的模組開發與重構,及 Next.js 15 版的設計債清償。
- TYPE
- FRONTEND
- SCOPE
- 營運中 · 參與 → 重構主力
- STACK
- REACT · NEXTJS · CANVAS · ANTD · STYLED-COMPONENTS · PLAYWRIGHT
- LINKS
- 公司內部專案(不公開)
01 / PROBLEM
Naily 賣的是客製化穿戴甲,消費者要的不是填表單,而是「上傳自己的指甲照片 → 編修設計 → 即時預覽成品」——這需要一個在瀏覽器內即時渲染、支援十指獨立設計的 Canvas 編輯工具。同時它又是一個功能持續疊加的完整電商 SPA:購物車、結帳、台灣電子發票、綠界金流、四種社群登入與行銷追蹤全在同一個 codebase,CSS 與元件層長出重複造輪子與命名衝突。2026 年初的重構把 5 步驟的客製化流程重做為 3 步並統一全站視覺;其後前台遷移到 Next.js 15 App Router 以取得 SSR 與 SEO,遷移完成後緊接著一輪系統性的設計 token 債務清償。
02 / CONSTRAINTS
- 品牌商業專案,程式碼不公開;CRA 商城為 5 人協作,本篇如實區分我負責與不負責的部分。
- 效能與技術債要在「不增加後端資源」的前提下用純前端手段處理:bundle 精簡、CSS 變數整併、圖片壓縮。
- Next.js 版的登入狀態存 localStorage,而 middleware 跑在讀不到 localStorage 的 Edge Runtime——集中式登入導轉做不了,保護邏輯必須下放到每個頁面的 Client Component。
- Next.js repo 僅 3 個測試檔、沒有 CI:大規模刪除死碼只能靠全庫 grep 二次驗證加乾淨 build 把關,而非測試套件。
03 / ARCHITECTURE
CRA 商城:React 18 SPA,react-router v7 管 72 條路由、其中 56 個元件走 React.lazy 分割;狀態刻意只用 4 個 Context 加 37 個 service 檔、不引入 Redux——多數狀態是單一使用者的購物流程,不是跨模組共享。單一 Axios 入口統一 JWT 刷新、json-bigint 精度與訪客容錯;GA4/GTM/Pixel 埋點以近 2,500 行的事件 schema 集中定義與驗證;測試為 572 個 Jest 案例加 33 個 Playwright E2E,GitHub Actions 每日排程執行。
Next.js 15 版:自 CRA 遷移到 App Router 以導入 SSR/SSG——53 個路由頁、55 個功能模組、352 個元件檔,部署為 standalone build 加 PM2。遷移後的全站盤點揭開債務的實際規模:design token 檔案引用率僅 5%、Ant Design / react-bootstrap / styled-components / CSS Modules 四套樣式方案並存、純 CSS 硬編碼色碼 3,463 處——這是設計債清償階段的起點,目前進行中。
04 / RESPONSIBILITIES
兩個時期、兩種角色,如實區分。CRA 商城為 5 人協作,我佔 136/629 個 commit(21.6%):2025/05–07 開發內部後台管理模組(方案、使用者、商品庫存、訂單、金流與發票),2026/02–03 為全站重構期的主要開發者(Canvas 編輯器與三步驟客製流程、首頁效能、CSS 債務治理、無痕模式稽核)。Next.js 版的設計債清償為獨立完成:141 個 commit 全數出自我(2026/07、5 天集中執行),其中 8 個標註與 Claude 結對。
05 / CHALLENGES → SOLUTIONS
CHALLENGE
舊版客製化流程有 5 個步驟,過長的流程本身就是轉換率風險;舊架構也沒有草稿保存、上傳記錄複用與 API 重試,使用者一旦中斷就得從頭開始。
SOLUTION
重新設計為 3 步驟(規格 → 設計 → 預覽),一次交付 9 大模塊:30 秒間隔草稿自動保存、上傳記錄複用、API 重試、6 種甲型 SVG 渲染、十指獨立設計狀態、圖片編修、雙視圖預覽與分享面板。開發方式是把 9 個模塊拆給 8 個並行 AI coding agent 同步產出(單一 commit 77 檔、25,804 行),再由我整合驗收——之後仍需兩輪精修 commit 才達可上線品質。
CHALLENGE
Next.js 版有三份 token 檔各自宣告同名 CSS 變數、給不同的值,實際生效值完全取決於 webpack chunk 載入順序——症狀之一是 --font-size-lg 到 5xl 全被攤平成 1rem,全站標題字級跑掉而沒人注意。
SOLUTION
不做表面對齊,先追出「現在實際生效的是哪組值」再統一:z-index 保留已被 15+ 個元件以自洽順序依賴的 unified 系統,讓另外兩檔改為轉發引用;字級/圓角/陰影則轉發 consolidated 的 token——變數名不變、值收斂。修復後在 build 產物逐一確認每個 token 在所有 chunk 組合下都是同一個值;硬編碼色碼從 3,463 處降到 2,131(-38%),分支仍在進行中。
CHALLENGE
專案累積大量重複與無引用的 CSS/資源檔(Cart.module.css 與 Cart2025.module.css 並存這類),但整個 repo 只有 3 個測試檔——沒有任何測試能保證「刪這個檔不會弄壞某個頁面」。
SOLUTION
把刪除門檻定為「全庫 grep 二次驗證確無任何 import/@import,且乾淨跑過一次 build」:第一輪刪除 80 個確認無引用的檔案,後續分支再刪 111 檔、淨減約 4.4 萬行(進行中)。這個方法有效但明確不可規模化、也蓋不到動態 import——列管中的限制,不是被掩蓋的風險。
CHALLENGE
Safari 等瀏覽器的無痕模式會限制甚至停用 localStorage,而商城多處(裝置識別、訪客訂單追蹤、資料同步)直接裸呼原生 API——一拋 DOMException,訪客訂單查詢這類核心功能就整個失效。
SOLUTION
全站稽核標出 19 個問題點,確立 safeStorage(帶記憶體 fallback 的安全封裝)為修復標準;截至盤點,50 個檔案已遷移、36 個檔案(含稽核點名的核心等級檔案)仍未遷移——稽核完成、修復進行中,如實記錄。
06 / SYSTEM FACTS
72
路由(56 個懶加載)
25,804
行,單一 commit 交付 9 模塊
605
測試(572 Jest + 33 E2E)
-38%
硬編碼色碼(3,463→2,131)
07 / LESSONS
大量並行生成拿得到功能骨架,拿不到一致性:8 個 agent 一次產出 2.5 萬行後,仍需兩輪精修與後續的 token/圖示庫收斂才成為單一風格。重來會在拆任務給並行 agent 之前先鎖定共用的 design token 與元件慣例,而不是事後合併。
CSS 載入順序本身是一種隱性契約:三個檔案宣告同名 token 不同值,生效者由 chunk 順序決定,不是任何人的設計意圖。重來會從第一天強制單一 token 來源,並用 lint 擋掉 raw hex 與重複宣告,而不是等累積 3,463 處才回頭清。
稽核出的問題若不接著排優先序執行,就只是一份文件:無痕模式稽核早就列出 19 個問題點與修復計畫,半年後仍有 36 個檔案未遷移。要嘛當場排進衝刺,要嘛承認它就是「已知未修」——別讓文件本身變成完成的假象。
NEXT
高科大智慧商務系系友會平台