~7 分鐘閱讀 · 教學
我看過許多 MUI 管理後台模板。material-kit-react 來自 minimals 團隊,是我經常回頭使用的模板。它乾淨、具型別,且資料夾結構合理。儲存庫:minimal-ui-kit/material-kit-react。
但每次我只想看看它,或是改一個顏色來確認效果,總是重複同樣的流程。git clone、npm install、等待、npm run dev,再等待,切換到 localhost。幾分鐘就過去了,磁碟上還多出幾百 MB 的 node_modules。這一切只是為了看一眼儀表板。
所以這次我跳過建置。直接在 CrossUI Studio 中開啟資料夾,並直接渲染 src/main.tsx。不需要安裝、不需要 Vite、不需要 localhost。以下是我所做的過程,以及讓我停下來思考的細節。
先說實話。這無法取代你的開發伺服器。你仍然需要真正的開發伺服器來進行測試、正式建置,以及實際的功能開發。它適合「快速查看與微調」的循環:評估模板、重新配色、展示給客戶等,這些情況下啟動整套工具鏈的成本高於任務本身。
小提醒:本機資料夾支援需要 Pro 帳號。若要測試,可使用原文部落格中的代碼免費升級。無需信用卡,名額有限,額滿為止。
你的瀏覽器不支援影片。請至 YouTube 觀看。
1. 複製到本機磁碟(不要直接從 GitHub 開啟)
Studio 可以直接掛載 GitHub 儲存庫。對於小型儲存庫來說,這是最佳途徑。針對這個專案,我先複製到磁碟:
git clone https://github.com/minimal-ui-kit/material-kit-react
進入全螢幕模式 離開全螢幕模式
原因很單純。src/ 約有 130 個檔案,整個專案約 245 個檔案,分散在 sections/、components/、layouts/、theme/、routes/ 等目錄。開啟專案時,工具必須抓取它所碰觸的檔案。透過 GitHub API 按需抓取會產生大量小型請求。雖然可行,但速度不快,若頻繁操作還可能達到速率限制。本機資料夾只透過檔案系統,因此速度更快。對於這種規模的模板,本機複製較佳。
這裡沒有執行 npm install。我只複製了原始碼。重點就是不進行建置。
2. 開啟資料夾 — 並讓它產生專案設定
在 Studio 中:開啟本機資料夾,選擇已複製的 material-kit-react 目錄。它會讀取目錄結構。不會安裝任何東西、不會執行任何程式,檔案仍留在我的磁碟上。最後這點很重要,因為你可能不希望為了查看而將客戶的程式碼上傳到某處。
第一次進入時,Studio 偵測到沒有專案設定檔,會跳出提示:
此專案沒有 CrossUI Studio 設定檔。我們建議先自動掃描專案以產生設定檔,之後再手動編輯。
點擊掃描並產生。它會讀取專案自身的設定檔,並在根目錄寫入設定檔。之後,模板所使用的 import 就能正確解析,而不需要 Vite。我完全不需要手動設定任何內容。
之後你可以手動編輯。專案設定對話框會直接開啟已產生的檔案。但自動產生的設定檔已足以完成以下所有操作。花費幾秒鐘,仍然完全不需要 npm install。
3. 開啟 src/main.tsx 並點擊預覽
關閉專案設定對話框後,Studio 會直接開啟入口檔案。你不需要在檔案樹中搜尋。
以下是你通常無法「直接渲染」的檔案:
// src/main.tsx
const router = createBrowserRouter([
{
Component: () => (
<App>
<Outlet />
</App>
),
errorElement: <ErrorBoundary />,
children: routesSection,
},
]);
createRoot(document.getElementById('root')!).render(
<StrictMode>
<RouterProvider router={router} />
</StrictMode>
);
進入全螢幕模式 離開全螢幕模式
這是 Vite 的入口檔案。createBrowserRouter + RouterProvider,而整個應用程式都包含在 <App>(主題提供者)與 routesSection(路由)之中。若以隔離方式直接渲染此檔案,會發生錯誤。沒有路由器上下文、沒有主題,也沒有應用程式所需的 #root。
但它仍然成功渲染了。我沒有進行任何設定。開啟 main.tsx、點擊預覽,儀表板就出現在畫布上,並帶有 MUI 主題。
現在回到設計模式。據我所知,它會從入口檔案中自動抓取提供者,因此若模板在啟動時有特殊處理,可能需要手動指定正確的提供者。對於 material-kit 來說,它直接就能運作,我猜這是因為 app.tsx 相當簡潔:
// src/app.tsx
export default function App({ children }: AppProps) {
return (
<ThemeProvider>
{children}
{/* github fab */}
</ThemeProvider>
);
}
進入全螢幕模式 離開全螢幕模式
乾淨的入口檔案在這裡非常重要。更多細節請見文末。
4. 深入探索 — 提供者會自動跟隨(這才是真正的重點)
/ 路徑的儀表板不是單一元件。它是由延遲載入的堆疊組成:
main.tsx (RouterProvider 在此定義 + 偵測到的 ThemeProvider)
└─ routesSection (src/routes/sections.tsx)
└─ DashboardPage (src/pages/dashboard.tsx, lazy)
└─ OverviewAnalyticsView (src/sections/overview/view)
└─ AnalyticsWidgetSummary ×4 (src/sections/overview, 統計卡片)
進入全螢幕模式 離開全螢幕模式
在畫布上按 Ctrl+點擊,可逐層向下瀏覽檔案樹。令人驚喜的是:包裝用的提供者會自動跟隨。在任何層級開啟「渲染裝飾」面板,都能看到兩個包裝器:RouterProvider 與 ThemeProvider:
- 在
main.tsx上,兩者皆會列出,但 自動跳過RouterProvider。這很合理,因為該提供者就在此檔案中,若再包裝一次會造成重複。它只會套用主題。 - 在
sections.tsx、dashboard.tsx以及更下層,兩個提供者都會存在(面板顯示「2」)。因此路由器與主題上下文會一路跟隨。我完全不需要手動修復「缺少提供者」的問題。
這通常是在隔離渲染深層檔案時最痛苦的部分,而這裡是自動處理的。在前往目標檔案的過程中,只遇到兩次小型導覽中斷。兩者都不是錯誤,只是真實程式碼的常見情況。
中斷 1 — sections.tsx 開啟在錯誤的 JSX 區塊(renderFallback)。
按 Ctrl+點擊進入路由器檔案時,會停在 renderFallback,也就是 Suspense 的 spinner:
// src/routes/sections.tsx
const renderFallback = () => (
<Box sx={{ display: 'flex', flex: '1 1 auto', alignItems: 'center', justifyContent: 'center' }}>
...
</Box>
);
進入全螢幕模式 離開全螢幕模式
因此畫布幾乎空白。一個檔案可能包含多個 JSX 區塊,而這個 spinner 只是第一個。頂端有區塊導覽器(麵包屑下拉選單),會列出所有區塊。我切換到 routesSection 及其子項目:
export const routesSection: RouteObject[] = [
{
element: ( /* <DashboardLayout><Suspense><Outlet/></Suspense></DashboardLayout> */ ),
children: [
{ index: true, element: <DashboardPage /> },
{ path: 'user', element: <UserPage /> },
{ path: 'products', element: <ProductsPage /> },
{ path: 'blog', element: <BlogPage /> },
],
},
// sign-in, 404 ...
];
進入全螢幕模式 離開全螢幕模式
選擇 { index: true, element: <DashboardPage /> }(也就是 / 路由),整個儀表板就渲染出來了。主題已經從自動包裝器一路跟隨。找到 DashboardPage 與 UserPage / ProductsPage 並排的位置只需一眼。路由看起來就像 URL 對照表。
教訓:當一個檔案包含多個 JSX 區塊時,不要相信它顯示的第一個東西。請使用區塊導覽器來切換到你需要的區塊。
中斷 2 — index.ts 是 barrel 檔案,不是元件。
從 DashboardPage 繼續向下,我遇到這個:
// src/sections/overview/view/index.ts
export * from "./overview-analytics-view.tsx";
進入全螢幕模式 離開全螢幕模式
NO-TARGET-JSX: 檔案中找不到目標 JSX 區塊。這是正確的。它是一個 re-export,沒有 JSX 可以渲染。sections/ 到處使用這種簡短的 barrel,讓 import 保持簡潔(使用 from 'src/sections/overview/view' 而非完整路徑)。在檔案清單中點擊 overview-analytics-view.tsx 即可開啟原始檔案。overview-analytics-view.tsx 會在開啟時渲染,主題已套用,而這正是我實際要編輯的檔案(下一節)。
因此讓我停下來的兩件事都不是錯誤。提供者會自動跟隨。其中一個是包含多個 JSX 區塊的檔案(使用導覽器),另一個是 barrel re-export(直接點擊)。這兩次半秒鐘的中斷,其實透露了更多關於模板結構的資訊,而不是工具的問題。
(編輯器上方的區塊導覽器也可以直接跳到任何層級,若你覺得點擊穿梭很麻煩。)
5. 進行修改
overview-analytics-view.tsx 是四個統計卡片取得 props 的地方,而且讀起來很簡單:
<AnalyticsWidgetSummary
title="Weekly sales"
percent={2.6}
total={714000}
// color 預設為 primary
/>
進入全螢幕模式 離開全螢幕模式
兩處小修改,都是從畫布與檢查器完成的。我將「Weekly sales」卡片的 color 改為 warning,並將 total 提高。接著將「New users」卡片的 color 從 secondary 改為 success。產生的 diff 正是這些修改,沒有其他變更:
<AnalyticsWidgetSummary
title="Weekly sales"
percent={2.6}
- total={714000}
+ total={928000}
+ color="warning"
...
/>
<AnalyticsWidgetSummary
title="New users"
percent={-0.1}
total={1352831}
- color="secondary"
+ color="success"
...
/>
進入全螢幕模式 離開全螢幕模式
沒有重新格式化、沒有碰觸 import,其他卡片完全相同。這是我最在意的部分。我希望它能以我原本會手動輸入的方式寫入修改,而不是從內部模型重新輸出整個檔案。這裡只進行了精準的 prop 修改。
如果你想進行更大的修改,可以從主題著手。src/theme/ 是調色盤建立的地方,在那裡修改 primary 顏色會改變按鈕、導覽列、啟用狀態等所有地方。同樣的流程,但影響範圍更廣。
6. 回到整個應用程式 — 只需按下瀏覽器返回鍵
有件小事我沒想到會這麼喜歡。我不需要從檔案樹重新開啟 main.tsx 來返回。每一次向下鑽取都是真正的導覽,每次進入時 URL 都會改變,因此瀏覽器返回鍵可以直接回到上層。檢視 → 頁面 → 路由 → main.tsx。前進與返回的行為就像一般網頁應用程式。按幾次返回,我就會看到完整的儀表板,並帶有我所做的修改。「Weekly sales」卡片現在在真實佈局中呈現琥珀色,而不只是在我修改它的隔離檢視中。
這種「在檢視深處進行編輯,然後一路返回到整個應用程式查看」的流程,通常需要重新載入並進行心理上的上下文切換。在這裡,它是同一個畫布,而且只要按返回鍵即可。
從 git clone 到「在執行中的儀表板中看到琥珀色卡片」的總時間:只要幾分鐘,大部分時間花在複製上。完全不需要 npm install。
為什麼摩擦點出現在這些地方(給模板作者的建議)
其實並非完全零摩擦。向下鑽取的過程中遇到兩次小型導覽中斷。但兩者都出現在可預測的位置:多區塊的路由器檔案,以及 barrel re-export,而且每次都只需一點擊即可解決。之所以這麼可預測,很大一部分來自模板本身,而不是工具。material-kit-react 的組織方式與工具相當配合:
- 入口檔案(
main.tsx/app.tsx)相當直觀。提供者就在這裡,不會隱藏在三層間接參照之後。這可能就是為什麼RouterProvider與ThemeProvider能被抓取,並在每一層級都持續套用的原因。主題上下文會自動跟隨,完全不需要手動修復提供者。 - 路由使用
lazy()並分組在routesSection中,因此區塊導覽器看起來就像 URL 結構。找到DashboardPage與UserPage/ProductsPage並排的位置只需一眼。 -
sections/會依功能拆分,並放在簡短的 barrelindex.ts檔案後面。這讓真實應用程式中的 import 保持簡潔,而在向下鑽取時,你只需點擊export *那一行。可預測的模式勝過聰明的模式。 - 卡片接受純粹的 props。
AnalyticsWidgetSummary只需要title/total/percent/color/chart,由 view 提供。因此從 view 編輯就是資料變更,而不是後端呼叫,而 diff 只會是一行。
如果模板結構混亂,預覽就會變得困難,無論有沒有工具。若提供者是動態組裝、單一頁面有 2000 行程式碼、section 必須接收真實的 fetched 資料才能運作,那麼好的模板結構就是讓「不建置就能開啟」成為現實的重要因素。為此要向 material-kit-react 致敬,它的結構確實發揮了作用。
實際上,如果你製作或銷售模板。有人評估你的模板時,一大部分的摩擦來自「clone-install-run」的成本。讓模板可以直接從原始碼預覽與微調,能大幅降低這項成本。這值得思考。
我不會用它來做什麼
- 執行測試套件或真正的 Vite 建置。這是預覽 + 編輯,不是 CI。
- 任何需要即時後端資料才能渲染的內容。你可以為向下鑽取模擬資料,但那是不同的工作流程。
- 對執行時期行為的最終判斷。它會從原始碼渲染結構,但不會監視你的應用程式真正從頭到尾執行。
對於「開啟這個模板、修改幾處、在上下文中查看」這種我使用管理後台模板前最常做的事,跳過建置就是少了一道繁瑣的手續。
小提醒:本機資料夾支援需要 Pro 帳號。若要測試,可使用原文部落格中的代碼免費升級。無需信用卡,名額有限,額滿為止。










0 Comments
Log in to join the conversation.No comments yet. Be the first to share your thoughts.