diff --git a/template/frontend/index.html.jinja b/template/frontend/index.html.jinja
new file mode 100644
index 0000000..ea7e088
--- /dev/null
+++ b/template/frontend/index.html.jinja
@@ -0,0 +1,12 @@
+
+
+
+
+
+ {{ project_name }}
+
+
+
+
+
+
diff --git a/template/frontend/package.json.jinja b/template/frontend/package.json.jinja
index 33944b0..3597d43 100644
--- a/template/frontend/package.json.jinja
+++ b/template/frontend/package.json.jinja
@@ -2,6 +2,7 @@
"name": "{{ project_slug }}-frontend",
"version": "0.1.0",
"private": true,
+ "type": "module",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
@@ -27,8 +28,9 @@
"vite": "^5.4.0",
"typescript": "^5.5.0",
"eslint": "^9.11.0",
- "@typescript-eslint/eslint-plugin": "^8.7.0",
- "@typescript-eslint/parser": "^8.7.0",
+ "@eslint/js": "^9.11.0",
+ "globals": "^15.9.0",
+ "typescript-eslint": "^8.7.0",
"eslint-plugin-react-hooks": "^5.1.0",
"eslint-plugin-react-refresh": "^0.4.0",
"prettier": "^3.3.0",
diff --git a/template/frontend/src/App.tsx.jinja b/template/frontend/src/App.tsx.jinja
new file mode 100644
index 0000000..fde86f4
--- /dev/null
+++ b/template/frontend/src/App.tsx.jinja
@@ -0,0 +1,8 @@
+export default function App() {
+ return (
+
+ {{ project_name }}
+ 脚手架已就绪。按 .claude/rules 在 src/ 下分层实现业务。
+
+ );
+}
diff --git a/template/frontend/src/index.css b/template/frontend/src/index.css
new file mode 100644
index 0000000..fea9d9c
--- /dev/null
+++ b/template/frontend/src/index.css
@@ -0,0 +1,17 @@
+:root {
+ font-family: system-ui, -apple-system, sans-serif;
+ line-height: 1.5;
+ color: #1a1a1a;
+}
+
+body {
+ margin: 0;
+ padding: 2rem;
+}
+
+code {
+ font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
+ background: #f0f0f0;
+ padding: 0.1em 0.3em;
+ border-radius: 3px;
+}
diff --git a/template/frontend/src/main.tsx b/template/frontend/src/main.tsx
new file mode 100644
index 0000000..e6f7a53
--- /dev/null
+++ b/template/frontend/src/main.tsx
@@ -0,0 +1,14 @@
+import { StrictMode } from "react";
+import { createRoot } from "react-dom/client";
+
+import App from "./App";
+import "./index.css";
+
+const root = document.getElementById("root");
+if (!root) throw new Error("root element not found");
+
+createRoot(root).render(
+
+
+ ,
+);
diff --git a/template/frontend/tsconfig.node.json b/template/frontend/tsconfig.node.json
new file mode 100644
index 0000000..bfb26cb
--- /dev/null
+++ b/template/frontend/tsconfig.node.json
@@ -0,0 +1,12 @@
+{
+ "compilerOptions": {
+ "composite": true,
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
+ "skipLibCheck": true,
+ "module": "ESNext",
+ "moduleResolution": "bundler",
+ "allowSyntheticDefaultImports": true,
+ "strict": true
+ },
+ "include": ["vite.config.ts", "vitest.config.ts"]
+}