📋 核心原则
遵循 Vite 官方标准 + 零配置启动 + 最小开发量
🎯 约定规则
1. 项目结构约定
project/
├── src/ # Rust 后端代码
├── app/ # 前端代码目录(固定约定)
│ ├── index.html # Vite 入口 HTML(必需)
│ ├── main.tsx # JS 入口文件(约定)
│ └── style.css # CSS 样式文件(可选)
└── Cargo.toml
2. 入口文件约定
单入口模式(推荐,最简单)
JS/TS 入口文件按以下优先级查找:
1. main.ts / main.tsx / main.jsx / main.js
2. index.ts / index.tsx / index.jsx / index.js
CSS 入口文件(可选):
1. 如果 JS 中已 import,则自动加载(Vite HMR 处理)
2. 如果需要独立 <link>,查找:style.css
多入口模式(可选支持)
如果项目根目录存在 vite.config.js/ts,且配置了多入口:
// vite.config.js
export default {
build: {
rollupOptions: {
input: {
main: './app/main.js',
admin: './app/admin.js'
}
}
}
}
则 Debug 模式忽略多入口,只使用第一个入口(简化开发)。
理由:
- Debug 模式开发时,通常只关注一个入口
- 多入口在 Release 模式从 manifest 自动处理
- 如果真需要多入口开发,运行多个 dev server
3. 路径约定
| 模式 | JS 路径 | CSS 路径 |
|---|---|---|
| Debug |
/main.js 或 /index.js
|
/style.css (可选) |
| Release | 从 manifest.json 读取 |
从 manifest.json 读取 |
💻 实现逻辑(最小开发量)
Debug 模式策略
1. 固定查找 /main.js 作为入口(Vite 官方默认)
2. CSS 不显式加载(让 JS 中的 import 处理)
3. 回退:如果没有 main.js,查找 /index.js
核心代码:
impl AssetPaths {
pub fn new() -> Self {
#[cfg(debug_assertions)]
{
// Debug 模式:按 Vite 官方约定
// Vite dev server 会自动处理模块解析
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 会处理 .ts/.tsx 转换
} else {
"/index.js" // 回退
};
Self {
js_paths: vec![js_path.to_string()],
css_paths: vec![], // CSS 通过 JS import 加载,不需要单独 <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 模式策略
保持现有逻辑:从 manifest.json 读取所有入口和依赖。
📖 使用指南
最简单的开始方式
- 创建标准 Vite 项目结构:
mkdir app
cd app
npm create vite@latest . -- --template react-ts
- 确保入口文件符合约定:
app/
├── index.html # ✅ Vite 自动生成
├── main.tsx # ✅ Vite 自动生成(已符合约定)
└── vite.config.ts
- 启动即可,无需任何配置:
cargo run
CSS 处理方式
推荐方式(零配置):
// app/main.tsx
import './style.css' // ✅ Vite 自动处理,支持 HMR
function App() {
return <div>Hello</div>
}
传统方式(如需要):
<!-- templates/index.html -->
<link rel="stylesheet" href="{{ assets.css_path() }}">
但 Debug 模式下 css_paths 为空,CSS 必须通过 JS import。
🔧 特殊场景处理
场景 1:使用其他入口文件名
如果项目使用 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:多入口项目
Debug 模式: 只开发一个入口,手动指定
// 环境变量指定入口(可选功能)
let js_path = std::env::var("VITE_ENTRY")
.unwrap_or_else(|_| "/main.js".to_string());
Release 模式: manifest 自动处理所有入口
场景 3:非标准项目结构
如果前端代码不在 app/ 目录:
// 支持自定义前端目录(编译时确定)
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()
}
✅ 最终推荐方案(最小开发量)
代码实现
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 }
}
}
}
文档说明
# 约定规则
**Debug 模式:**
- JS 入口固定为 `/main.js`(Vite 官方默认)
- CSS 通过 `import './style.css'` 在 JS 中加载
**Release 模式:**
- 自动从 manifest.json 读取所有资源
**项目结构要求:**
app/
├── index.html
├── main.tsx ← 必须是这个文件名
└── style.css ← 在 main.tsx 中 import
🎁 优势总结
| 特性 | 说明 |
|---|---|
| 零配置 | 使用 Vite 官方模板即可,无需额外配置 |
| 零学习成本 | 遵循 Vite 标准,前端开发者无需学习新约定 |
| 最小代码量 | Rust 端只需 3 行代码 |
| 支持 HMR | CSS 通过 import 加载,完整支持热更新 |
| 多入口友好 | Release 模式自动处理,Debug 模式简化开发 |
总结:推荐使用固定约定 /main.js + CSS 通过 import 加载,这是开发量最小、最符合 Vite 标准的方案。