diff --git a/src-tauri/src/commands/templates.rs b/src-tauri/src/commands/templates.rs
index 28a38ac..c558c5b 100644
--- a/src-tauri/src/commands/templates.rs
+++ b/src-tauri/src/commands/templates.rs
@@ -344,17 +344,8 @@ pub fn seed_builtin_templates() {
Err(_) => return,
};
- // 已有内置模板则跳过
- let count: i64 = conn
- .query_row(
- "SELECT COUNT(*) FROM project_templates WHERE is_builtin = 1",
- [],
- |row| row.get(0),
- )
- .unwrap_or(0);
- if count > 0 {
- return;
- }
+ // 不做全局跳过,直接用 INSERT OR IGNORE 保证幂等
+ // 这样新增内置模板时,已有用户也能自动获得
struct Tpl {
id: &'static str,
@@ -450,6 +441,192 @@ edition = "2021"
init_commands: "",
files: vec![],
},
+ Tpl {
+ id: "builtin-tauri-react",
+ name: "Tauri + React",
+ description: "桌面应用,Tauri v2 + React 19 + TypeScript + Vite",
+ platform: "both",
+ tech_stack: "Rust,Node,pnpm,React,TypeScript,Tauri",
+ init_commands: "pnpm install",
+ files: vec![
+ ("package.json", r#"{
+ "name": "{{project_name_kebab}}",
+ "private": true,
+ "version": "0.1.0",
+ "type": "module",
+ "scripts": {
+ "dev": "tauri dev",
+ "build": "tauri build",
+ "preview": "vite preview"
+ },
+ "dependencies": {
+ "@tauri-apps/api": "^2",
+ "react": "^19",
+ "react-dom": "^19"
+ },
+ "devDependencies": {
+ "@tauri-apps/cli": "^2",
+ "@types/react": "^19",
+ "@types/react-dom": "^19",
+ "@vitejs/plugin-react": "^4",
+ "typescript": "^5",
+ "vite": "^6"
+ }
+}
+"#),
+ ("vite.config.ts", r#"import { defineConfig } from "vite";
+import react from "@vitejs/plugin-react";
+
+export default defineConfig(async () => ({
+ plugins: [react()],
+ clearScreen: false,
+ server: {
+ port: 1420,
+ strictPort: true,
+ watch: {
+ ignored: ["**/src-tauri/**"],
+ },
+ },
+}));
+"#),
+ ("tsconfig.json", r#"{
+ "compilerOptions": {
+ "target": "ES2020",
+ "useDefineForClassFields": true,
+ "lib": ["ES2020", "DOM", "DOM.Iterable"],
+ "module": "ESNext",
+ "skipLibCheck": true,
+ "moduleResolution": "bundler",
+ "allowImportingTsExtensions": true,
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "noEmit": true,
+ "jsx": "react-jsx",
+ "strict": true
+ },
+ "include": ["src"]
+}
+"#),
+ ("index.html", r#"
+
+
+
+
+ {{project_name}}
+
+
+
+
+
+
+"#),
+ ("src/main.tsx", r#"import React from "react";
+import ReactDOM from "react-dom/client";
+import App from "./App";
+
+ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
+
+
+
+);
+"#),
+ ("src/App.tsx", r#"import { useState } from "react";
+
+function App() {
+ const [count, setCount] = useState(0);
+
+ return (
+
+
{{project_name}}
+
Tauri v2 + React + TypeScript
+
+
+ );
+}
+
+export default App;
+"#),
+ ("src-tauri/tauri.conf.json", r#"{
+ "$schema": "https://schema.tauri.app/config/2",
+ "productName": "{{project_name_kebab}}",
+ "version": "0.1.0",
+ "identifier": "com.example.{{project_name_snake}}",
+ "build": {
+ "beforeDevCommand": "pnpm vite",
+ "devUrl": "http://localhost:1420",
+ "beforeBuildCommand": "pnpm vite build",
+ "frontendDist": "../dist"
+ },
+ "app": {
+ "windows": [
+ {
+ "title": "{{project_name}}",
+ "width": 1200,
+ "height": 800
+ }
+ ],
+ "security": {
+ "csp": null
+ }
+ },
+ "bundle": {
+ "active": true,
+ "targets": "all",
+ "icon": []
+ }
+}
+"#),
+ ("src-tauri/Cargo.toml", r#"[package]
+name = "{{project_name_snake}}"
+version = "0.1.0"
+description = "A Tauri App"
+authors = []
+edition = "2021"
+
+[lib]
+name = "{{project_name_snake}}_lib"
+crate-type = ["staticlib", "cdylib", "rlib"]
+
+[build-dependencies]
+tauri-build = { version = "2", features = [] }
+
+[dependencies]
+tauri = { version = "2", features = [] }
+tauri-plugin-opener = "2"
+serde = { version = "1", features = ["derive"] }
+serde_json = "1"
+"#),
+ ("src-tauri/build.rs", "fn main() {\n tauri_build::build()\n}\n"),
+ ("src-tauri/src/main.rs", r#"// Prevents additional console window on Windows in release, DO NOT REMOVE!!
+#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
+
+fn main() {
+ {{project_name_snake}}_lib::run()
+}
+"#),
+ ("src-tauri/src/lib.rs", r#"#[cfg_attr(mobile, tauri::mobile_entry_point)]
+pub fn run() {
+ tauri::Builder::default()
+ .plugin(tauri_plugin_opener::init())
+ .invoke_handler(tauri::generate_handler![])
+ .run(tauri::generate_context!())
+ .expect("error while running tauri application");
+}
+"#),
+ ("src-tauri/capabilities/default.json", r#"{
+ "$schema": "../gen/schemas/desktop-schema.json",
+ "identifier": "default",
+ "description": "Capability for the main window",
+ "windows": ["main"],
+ "permissions": [
+ "core:default",
+ "opener:default"
+ ]
+}
+"#),
+ (".gitignore", "node_modules/\ndist/\n.env\n.env.*\n!.env.example\nsrc-tauri/target/\nsrc-tauri/gen/\n"),
+ ],
+ },
];
for t in &templates {