## 一、Apple App Store 專案的核心架構特徵 ### 1.1 單一業務邏輯門面(Jet Facade) ``` browser.ts → bootstrap → Jet.load → runtime + objectGraph ↓ UI 層僅透過 jet.dispatch(intent) / jet.perform(action) 溝通 ``` - **Jet** 封裝所有業務邏輯:路由、資料取得、動作分發、metrics。 - UI 層**不直接**呼叫 API、不直接操作 storage、不直接操作 history。 - 所有外部依賴(fetch、storage、locale、user)統一注入 `Dependencies`,再組裝成 `ObjectGraph`。 ### 1.2 Intent / Action 分離(查詢與命令) | 類型 | 職責 | 回傳值 | 例子 | |------|------|--------|------| | **Intent** | 取得頁面資料(Query) | `Promise` | `RouteUrlIntent` → 回傳 `ProductPage` | | **Action** | 執行副作用(Command) | `'performed' \| 'unsupported'` | `FlowAction` → 導航到新頁面 | - `FlowAction` 是主要導航機制:內含 `destination Intent` + `pageUrl` + `presentationContext`。 - Action handler 註冊採用**型別註冊制**:`jet.onAction('flowAction', handler)`。 ### 1.3 Page Model 驅動 UI(資料驅動) ```ts // App.svelte 的介面極簡 export let page: Promise | Page ``` - 整個應用由單一 `page` prop 驅動。 - `PageResolver` 處理 `Promise` 的 loading / error 狀態。 - `Page.svelte` 用 type guard 分發到對應的 page component:`isProductPage(page)` → ``。 - **Page 是 union type**,不是 route-based 的硬編碼映射。 ### 1.4 Shelf / Item 分層(容器與內容分離) ``` Page (TodayPage / ProductPage / ...) └── Shelf[] (水平捲軸 / 網格) └── ShelfItemLayout (佈局抽象:HorizontalShelf or Grid) └── Item (BrickItem / LargeLockupItem / ...) ``` - **Shelf** = 容器邏輯:決定是水平捲軸還是網格、rowsPerColumn、邊框。 - **ShelfItemLayout** = 佈局中介:根據 `isHorizontal` 選擇 `HorizontalShelf` 或 `Grid`。 - **Item** = 純粹內容渲染:只關心單一資料單位的呈現,不知道自己是水平還是網格。 - **FallbackShelf** = 優雅的降級策略:遇到未實作的 shelf 類型顯示 placeholder,不 crash。 ### 1.5 Svelte Context 作為跨層依賴注入 ```ts // bootstrap.ts context.set('jet', jet) context.set('i18n', i18nStore) // 深層元件 const jet = getJet() // 從 Svelte Context 取得 const i18n = getI18n() // 從 Svelte Context 取得 ``` - 避免 props drilling:Jet、i18n、accessibility layout、today-card layout 都透過 context 傳遞。 - Context 在啟動時注入,生命周期與應用一致,不是用來傳遞 UI 狀態的。 ### 1.6 命令式外殼 + 聲明式 UI ```ts // browser.ts(命令式啟動層) const app = new App({ target: container, context, hydrate: true }) registerActionHandlers({ jet, updateApp: (props) => app.$set(props), // 橋接命令式 → 聲明式 }) ``` - 導航、歷史管理、scroll 復原由命令式的 action handler 處理。 - UI 渲染完全聲明式,只接收 `page` 與 `isFirstPage` 兩個 prop。 ---