?? 核心原則
遵循 Vite 官方標(biāo)準(zhǔn) + 零配置啟動(dòng) + 最小開發(fā)量
?? 約定規(guī)則
1. 項(xiàng)目結(jié)構(gòu)約定
project/
├── src/ # Rust 后端代碼
├── app/ # 前端代碼目錄(固定約定)
│ ├── index.html # Vite 入口 HTML(必需)
│ ├── main.tsx # JS 入口文件(約定)
│ └── style.css # CSS 樣式文件(可選)
└── Cargo.toml
2. 入口文件約定
單入口模式(推薦,最簡單)
JS/TS 入口文件按以下優(yōu)先級查找:
1. main.ts / main.tsx / main.jsx / main.js
2. index.ts / index.tsx / index.jsx / index.js
CSS 入口文件(可選):
1. 如果 JS 中已 import,則自動(dòng)加載(Vite HMR 處理)
2. 如果需要獨(dú)立 <link>,查找:style.css
多入口模式(可選支持)
如果項(xiàng)目根目錄存在 vite.config.js/ts,且配置了多入口:
// vite.config.js
export default {
build: {
rollupOptions: {
input: {
main: './app/main.js',
admin: './app/admin.js'
}
}
}
}
則 Debug 模式忽略多入口,只使用第一個(gè)入口(簡化開發(fā))。
理由:
- Debug 模式開發(fā)時(shí),通常只關(guān)注一個(gè)入口
- 多入口在 Release 模式從 manifest 自動(dòng)處理
- 如果真需要多入口開發(fā),運(yùn)行多個(gè) dev server
3. 路徑約定
| 模式 | JS 路徑 | CSS 路徑 |
|---|---|---|
| Debug |
/main.js 或 /index.js
|
/style.css (可選) |
| Release | 從 manifest.json 讀取 |
從 manifest.json 讀取 |
?? 實(shí)現(xiàn)邏輯(最小開發(fā)量)
Debug 模式策略
1. 固定查找 /main.js 作為入口(Vite 官方默認(rèn))
2. CSS 不顯式加載(讓 JS 中的 import 處理)
3. 回退:如果沒有 main.js,查找 /index.js
核心代碼:
impl AssetPaths {
pub fn new() -> Self {
#[cfg(debug_assertions)]
{
// Debug 模式:按 Vite 官方約定
// Vite dev server 會(huì)自動(dòng)處理模塊解析
let js_path = if Self::file_exists("app/main.js")
|| Self::file_exists("app/main.ts")
|| Self::file_exists("app/main.tsx") {
"/main.js" // Vite 會(huì)處理 .ts/.tsx 轉(zhuǎn)換
} else {
"/index.js" // 回退
};
Self {
js_paths: vec![js_path.to_string()],
css_paths: vec![], // CSS 通過 JS import 加載,不需要單獨(dú) <link>
}
}
#[cfg(not(debug_assertions))]
{
let (js_paths, css_paths) = Self::get_paths_from_manifest();
Self { js_paths, css_paths }
}
}
#[cfg(debug_assertions)]
fn file_exists(path: &str) -> bool {
std::path::Path::new(path).exists()
}
}
Release 模式策略
保持現(xiàn)有邏輯:從 manifest.json 讀取所有入口和依賴。
?? 使用指南
最簡單的開始方式
- 創(chuàng)建標(biāo)準(zhǔn) Vite 項(xiàng)目結(jié)構(gòu):
mkdir app
cd app
npm create vite@latest . -- --template react-ts
- 確保入口文件符合約定:
app/
├── index.html # ? Vite 自動(dòng)生成
├── main.tsx # ? Vite 自動(dòng)生成(已符合約定)
└── vite.config.ts
- 啟動(dòng)即可,無需任何配置:
cargo run
CSS 處理方式
推薦方式(零配置):
// app/main.tsx
import './style.css' // ? Vite 自動(dòng)處理,支持 HMR
function App() {
return <div>Hello</div>
}
傳統(tǒng)方式(如需要):
<!-- templates/index.html -->
<link rel="stylesheet" href="{{ assets.css_path() }}">
但 Debug 模式下 css_paths 為空,CSS 必須通過 JS import。
?? 特殊場景處理
場景 1:使用其他入口文件名
如果項(xiàng)目使用 app.js 而不是 main.js:
// 修改約定順序(可選)
let js_path = if Self::file_exists("app/app.js") {
"/app.js"
} else if Self::file_exists("app/main.js") {
"/main.js"
} else {
"/index.js"
};
場景 2:多入口項(xiàng)目
Debug 模式: 只開發(fā)一個(gè)入口,手動(dòng)指定
// 環(huán)境變量指定入口(可選功能)
let js_path = std::env::var("VITE_ENTRY")
.unwrap_or_else(|_| "/main.js".to_string());
Release 模式: manifest 自動(dòng)處理所有入口
場景 3:非標(biāo)準(zhǔn)項(xiàng)目結(jié)構(gòu)
如果前端代碼不在 app/ 目錄:
// 支持自定義前端目錄(編譯時(shí)確定)
const FRONTEND_DIR: &str = option_env!("FRONTEND_DIR").unwrap_or("app");
fn file_exists(path: &str) -> bool {
std::path::Path::new(&format!("{}/{}", FRONTEND_DIR, path)).exists()
}
? 最終推薦方案(最小開發(fā)量)
代碼實(shí)現(xiàn)
impl AssetPaths {
pub fn new() -> Self {
#[cfg(debug_assertions)]
{
Self {
js_paths: vec!["/main.js".to_string()], // 固定約定
css_paths: vec![], // CSS 通過 import 加載
}
}
#[cfg(not(debug_assertions))]
{
let (js_paths, css_paths) = Self::get_paths_from_manifest();
Self { js_paths, css_paths }
}
}
}
文檔說明
# 約定規(guī)則
**Debug 模式:**
- JS 入口固定為 `/main.js`(Vite 官方默認(rèn))
- CSS 通過 `import './style.css'` 在 JS 中加載
**Release 模式:**
- 自動(dòng)從 manifest.json 讀取所有資源
**項(xiàng)目結(jié)構(gòu)要求:**
app/
├── index.html
├── main.tsx ← 必須是這個(gè)文件名
└── style.css ← 在 main.tsx 中 import
?? 優(yōu)勢總結(jié)
| 特性 | 說明 |
|---|---|
| 零配置 | 使用 Vite 官方模板即可,無需額外配置 |
| 零學(xué)習(xí)成本 | 遵循 Vite 標(biāo)準(zhǔn),前端開發(fā)者無需學(xué)習(xí)新約定 |
| 最小代碼量 | Rust 端只需 3 行代碼 |
| 支持 HMR | CSS 通過 import 加載,完整支持熱更新 |
| 多入口友好 | Release 模式自動(dòng)處理,Debug 模式簡化開發(fā) |
總結(jié):推薦使用固定約定 /main.js + CSS 通過 import 加載,這是開發(fā)量最小、最符合 Vite 標(biāo)準(zhǔn)的方案。