1.01 项目结构

非常好的选择!您提出的技术栈非常现代和轻量级。我完全理解您对 React 的看法,使用 HTMX 和 UnoCSS 确实可以创建一个更轻量、更高效的前端。让我为您重新设计一个基于这些技术的 Todo 项目。

项目名称:LightweightTodo

技术栈: - 运行时:Bun - 后端框架:Elysia - 数据库:Turso - ORM:Drizzle ORM - 前端:HTMX + UnoCSS - 模板引擎:eta - 认证:JWT - 测试:Bun test

项目结构:

lightweight-todo/
├── src/
│   ├── controllers/    # 控制器
│   ├── models/         # 数据模型
│   ├── services/       # 业务逻辑
│   ├── views/          # eta模板
│   ├── public/         # 静态文件
│   │   ├── styles/     # UnoCSS样式
│   │   └── js/         # 客户端JavaScript
│   ├── utils/          # 工具函数
│   ├── middleware/     # 中间件
│   ├── routes/         # 路由定义
│   └── app.ts          # 主应用文件
├── drizzle/            # Drizzle ORM配置和迁移
├── tests/              # 测试文件
├── tsconfig.json       # TypeScript配置
├── package.json
└── README.md

详细实现计划:

  1. 项目初始化和基础设置 (1 天)
  2. 初始化 Bun 项目
  3. 安装必要的依赖(Elysia, Drizzle ORM, HTMX, UnoCSS 等)
  4. 设置 TypeScript 配置
  5. 创建基本的项目结构

  6. 数据库设计和 ORM 设置 (1天)

  7. 使用 Drizzle ORM 定义数据模型(User, Todo)
  8. 设置 Turso 数据库连接
  9. 创建数据库迁移脚本

  10. 后端 API 开发 (2天)

  11. 实现用户认证(使用 JWT)
  12. 开发 Todo CRUD API
  13. 添加中间件(错误处理、日志记录等)
  14. 实现数据验证

  15. 前端基础结构 (1 天)

  16. 设置 eta 模板引擎
  17. 配置 UnoCSS
  18. 创建基本布局模板

  19. 用户认证 UI (1 天)

  20. 创建登录和注册页面
  21. 实现客户端表单验证
  22. 使用 HTMX 处理表单提交

  23. Todo 管理功能 (2 天)

  24. 实现 Todo 列表视图
  25. 创建 Todo 添加、编辑和删除功能
  26. 使用 HTMX 实现无刷新更新

  27. 高级 Todo 功能 (1天)

  28. 添加标签和优先级
  29. 实现过滤和排序功能
  30. 添加截止日期功能

  31. 性能优化 (1 天)

  32. 实现部分页面更新
  33. 优化数据库查询
  34. 添加缓存策略

  35. 测试 (1 天)

  36. 编写单元测试
  37. 实现集成测试
  38. 使用 Bun test 运行测试

  39. 部署准备 (1 天)

    • 编写部署脚本
    • 配置环境变量
    • 准备生产环境设置

总计:12 天

下面是一些关键文件的示例代码:

  1. src/app.ts:
import { Elysia } from 'elysia';
import { html } from '@elysiajs/html';
import { staticPlugin } from '@elysiajs/static';
import { jwt } from '@elysiajs/jwt';
import { cookie } from '@elysiajs/cookie';
import todoRoutes from './routes/todoRoutes';
import authRoutes from './routes/authRoutes';

const app = new Elysia()
  .use(html())
  .use(staticPlugin())
  .use(jwt({ secret: process.env.JWT_SECRET! }))
  .use(cookie())
  .use(todoRoutes)
  .use(authRoutes)
  .listen(3000);

console.log(`🦊 Elysia is running at ${app.server?.hostname}:${app.server?.port}`);
  1. src/models/todo.ts:
import { InferModel } from 'drizzle-orm';
import { sqliteTable, text, integer } from 'drizzle-orm/sqlite-core';

export const todos = sqliteTable('todos', {
  id: text('id').primaryKey(),
  title: text('title').notNull(),
  completed: integer('completed', { mode: 'boolean' }).notNull().default(false),
  userId: text('user_id').notNull(),
});

export type Todo = InferModel<typeof todos>;
export type NewTodo = InferModel<typeof todos, 'insert'>;
  1. src/controllers/todoController.ts:
import { Elysia, t } from 'elysia';
import { db } from '../db';
import { todos } from '../models/todo';
import { eq } from 'drizzle-orm';

export const todoController = new Elysia()
  .get('/todos', async ({ jwt, cookie, set }) => {
    const token = cookie.auth;
    if (!token) {
      set.status = 401;
      return 'Unauthorized';
    }

    const payload = await jwt.verify(token);
    if (!payload) {
      set.status = 401;
      return 'Invalid token';
    }

    const userTodos = await db.select().from(todos).where(eq(todos.userId, payload.sub));
    return userTodos;
  })
  .post('/todos', async ({ body, jwt, cookie, set }) => {
    // Similar authentication logic as above
    // Then create new todo
    const newTodo = await db.insert(todos).values({
      title: body.title,
      userId: payload.sub,
    }).returning();
    return newTodo[0];
  }, {
    body: t.Object({
      title: t.String(),
    })
  });

// Add more routes for update, delete, etc.
  1. src/views/todos.eta:
<% layout('./layout') %>

<div class="container mx-auto p-4">
  <h1 class="text-2xl font-bold mb-4">Todo List</h1>

  <form hx-post="/todos" hx-swap="afterend" class="mb-4">
    <input type="text" name="title" placeholder="New todo" class="border p-2">
    <button type="submit" class="bg-blue-500 text-white p-2">Add</button>
  </form>

  <ul id="todo-list">
    <% it.todos.forEach(function(todo) { %>
      <li class="flex items-center mb-2">
        <input type="checkbox" <%= todo.completed ? 'checked' : '' %>
               hx-put="/todos/<%= todo.id %>/toggle"
               hx-swap="outerHTML"
               class="mr-2">
        <span><%= todo.title %></span>
        <button hx-delete="/todos/<%= todo.id %>"
                hx-target="closest li"
                hx-swap="outerHTML"
                class="ml-2 text-red-500">Delete</button>
      </li>
    <% }) %>
  </ul>
</div>
  1. src/public/styles/main.css:
@import 'uno.css';

/* 添加任何自定义样式 */

这个项目使用了您指定的技术栈,创建了一个轻量级但功能强大的 Todo 应用。它利用了 Bun 的高性能运行时,Elysia 的快速后端框架,Turso 的分布式 SQLite 数据库,以及 HTMX 和 UnoCSS 来创建一个响应迅速的前端,无需大型 JavaScript 框架。

这个设计允许您快速开发和部署,同时保持了出色的性能和开发体验。您可以根据需要进一步扩展功能,例如添加更多的数据可视化、协作功能或高级过滤选项。