Skip to content
sj817Public
forked from expressjs/express

About

Fast, unopinionated, minimalist web framework for node.

Resources

Security policy

Stars

0 stars

Watchers

0 watching

Forks

 
 

Latest commit

 

History

6,124 Commits

Folders and files

Repository files navigation

@karinjs/express

NPM Version License Node Version

基于 TypeScript 重写的 Express 5.x 框架

快速、极简、无约束的 Web 框架

English | 简体中文

📖 项目简介

这是一个完全使用 TypeScript 重写的 Express 5.x 框架,旨在提供更好的类型安全性和开发体验,同时保持与原版 Express 的 API 兼容性。

🎯 项目初衷

本项目专为 github.com/karinjs/karin 优化而开发,针对其特定使用场景进行了深度定制和性能优化。

⚠️ 特别声明

Warning

本项目未经生产环境充分验证,不建议非专业用户使用。

  • 🔴 本项目仍在积极开发中
  • 🔴 未经过大规模生产环境的长期验证
  • 🔴 建议仅在开发和测试环境中使用
  • 🔴 生产环境使用需自行承担风险

📋 免责声明

  • 本项目按 "原样" 提供,不提供任何明示或暗示的保证
  • 使用本项目所产生的任何直接或间接损失,开发者不承担责任
  • 本项目基于 Express 5.x 进行重写,但与官方 Express 项目无关
  • 在生产环境使用前,请进行充分的测试和评估
  • 对于关键业务系统,建议使用经过验证的稳定版本(如官方 Express)

✨ 主要特性

  • 🎯 完整的 TypeScript 重写:核心代码全部使用 TypeScript 编写
  • 🔒 类型安全:提供完整的类型定义,享受更好的 IDE 智能提示
  • 📦 Monorepo 架构:使用 pnpm workspace 管理多个相关包
  • 🚀 现代化构建:使用 tsdown 进行高效打包
  • ⚡ ESM 优先:原生支持 ES Modules
  • 🔄 API 兼容:保持与 Express 5.x 的 API 兼容性
  • 🧪 完整测试:包含大量单元测试和集成测试

🏗️ 项目架构

Monorepo 结构

本项目采用 pnpm workspace 管理,包含以下子包:

packages:
  - "packages/path-to-regexp"   # 路径匹配和参数提取
  - "packages/send"              # 文件发送类型定义
  - "packages/connect"           # Connect 中间件类型定义
  - "packages/serve-static"      # 静态文件服务

核心模块

src/
├── application.ts          # Application 类 - 核心应用逻辑
├── express.ts             # Express 工厂函数和导出
├── request.ts             # Request 类 - 扩展的请求对象
├── response.ts            # Response 类 - 扩展的响应对象
├── view.ts                # 视图渲染系统
├── utils.ts               # 工具函数
├── router/                # 路由系统
│   ├── index.ts          # Router 类
│   ├── layer.ts          # 路由层
│   └── route.ts          # Route 类
├── body-parser/           # 请求体解析器
│   └── src/
└── serve-static/          # 静态文件服务实现
    └── index.ts

🔄 与原版 Express 的主要区别

1. 完全的 TypeScript 实现

  • 原版:JavaScript 实现,通过 @types/express 提供类型
  • 本项目:TypeScript 原生实现,类型定义即源码
// 更好的类型推导
const app = express()
app.get('/user/:id', (req, res) => {
  // req.params 自动推导类型
  const id = req.params.id // string
  res.json({ id })
})

2. 模块化架构

  • 原版:依赖外部 npm 包(如 path-to-regexp、send 等)
  • 本项目:将核心依赖纳入 monorepo,便于维护和定制

3. 现代化的构建系统

  • 原版:传统的 CommonJS 模块
  • 本项目:
    • 使用 tsdown 构建,生成 ESM 格式
    • 支持 Tree-shaking
    • 更小的包体积
// tsdown.config.ts
export default defineConfig({
  entry: ['./src/index.ts'],
  format: ['esm'],
  dts: { resolve: true, build: true },
  target: 'node18',
  platform: 'node',
})

4. 增强的类型系统

  • Application 类:完整的类型定义,包括所有 HTTP 方法
  • Request/Response:泛型支持,更精确的类型推导
  • 路由系统:路径参数、查询参数的类型安全
// 泛型支持示例
class Request<
  P = ParamsDictionary,      // 路径参数类型
  ResBody = any,             // 响应体类型
  ReqBody = any,             // 请求体类型
  ReqQuery = ParsedQs,       // 查询参数类型
  LocalsObj = Record<string, any>  // 本地变量类型
> extends IncomingMessage

5. 内置模块重写

Router 模块

  • 完全 TypeScript 重写
  • 更好的路由匹配性能
  • 类型安全的中间件链

Body Parser

  • 集成到核心,无需单独安装
  • TypeScript 原生实现
  • 支持 JSON、URL-encoded、Raw、Text 等格式

Serve Static

  • 静态文件服务的 TypeScript 实现
  • 更好的错误处理
  • 内置安全特性

6. 改进的错误处理

// Application.status() - 更严格的状态码验证
status(code: StatusCode): this {
  if (!Number.isInteger(code)) {
    throw new TypeError(`Invalid status code: ${JSON.stringify(code)}`)
  }
  if (code < 100 || code > 999) {
    throw new RangeError(`Invalid status code: ${JSON.stringify(code)}`)
  }
  this.statusCode = code
  return this
}

7. 优化的开发体验

  • 路径别名配置:
{
  "paths": {
    "router": ["./src/router/index.ts"],
    "body-parser": ["./src/body-parser/src/index.ts"],
    "serve-static": ["./src/serve-static/index.ts"]
  }
}
  • 统一的测试框架:所有模块使用 Mocha + TypeScript
  • 现代化的工具链:ESLint、TypeScript 5.x

📦 安装

npm install @karinjs/express
# 或
pnpm add @karinjs/express
# 或
yarn add @karinjs/express

🚀 快速开始

import express from '@karinjs/express'

const app = express()

app.get('/', (req, res) => {
  res.send('Hello World!')
})

app.listen(3000, () => {
  console.log('Server is running on http://localhost:3000')
})

💡 核心改进点

1. 类型安全的中间件

import { RequestHandler } from '@karinjs/express'

const authMiddleware: RequestHandler = (req, res, next) => {
  // 完整的类型提示
  const token = req.get('Authorization')
  if (!token) {
    return res.status(401).json({ error: 'Unauthorized' })
  }
  next()
}

2. 泛型路由处理

interface UserParams {
  id: string
}

interface UserBody {
  name: string
  email: string
}

app.post<UserParams, any, UserBody>('/user/:id', (req, res) => {
  const { id } = req.params  // 类型: { id: string }
  const { name, email } = req.body  // 类型: { name: string, email: string }
  res.json({ id, name, email })
})

3. 内置 Body Parser

// 无需额外安装 body-parser
app.use(express.json())
app.use(express.urlencoded({ extended: true }))

app.post('/api/data', (req, res) => {
  console.log(req.body)  // 自动解析
  res.json({ received: true })
})

4. 静态文件服务

// 使用内置的 serve-static
app.use(express.static('public'))
app.use('/static', express.static('assets'))

📚 API 文档

本项目保持与 Express 5.x 的 API 兼容性。主要的 API 包括:

Application

  • app.get(path, ...handlers)
  • app.post(path, ...handlers)
  • app.put(path, ...handlers)
  • app.delete(path, ...handlers)
  • app.use([path], ...middleware)
  • app.listen(port, [callback])
  • app.set(setting, value)
  • app.engine(ext, callback)
  • app.render(view, [locals], callback)

Request

  • req.params - 路径参数
  • req.query - 查询参数
  • req.body - 请求体
  • req.get(field) - 获取请求头
  • req.accepts(types) - 内容协商
  • req.is(type) - 检查 Content-Type

Response

  • res.status(code) - 设置状态码
  • res.send(body) - 发送响应
  • res.json(obj) - 发送 JSON
  • res.redirect([status], url) - 重定向
  • res.render(view, [locals], [callback]) - 渲染视图
  • res.sendFile(path, [options], [callback]) - 发送文件

🧪 测试

# 运行所有测试
pnpm test

# 运行特定模块测试
pnpm test:router
pnpm test:body-parser
pnpm test:serve-static

# 运行验收测试
pnpm test:acceptance

# 生成覆盖率报告
pnpm test-cov

🛠️ 开发

# 克隆仓库
git clone https://github.com/sj817/express.git
cd express

# 安装依赖
pnpm install

# 构建项目
pnpm build

# 运行 Lint
pnpm lint

# 修复 Lint 问题
pnpm lint:fix

📋 为什么要重写?

1. 类型安全

原版 Express 的类型定义存在于 @types/express,与实现分离,容易出现类型不匹配的问题。TypeScript 原生实现可以确保类型与代码完全一致。

2. 更好的维护性

Monorepo 架构使得核心依赖都在一个仓库中,便于整体维护和优化,减少版本不兼容的风险。

3. 现代化特性

  • 原生 ESM 支持
  • 更小的包体积(Tree-shaking)
  • 更好的构建性能(tsdown)

4. 学习和定制

完全掌握代码实现,方便根据项目需求进行定制和优化。

5. 性能优化

  • 减少依赖层级
  • 优化的路由匹配算法
  • 更高效的类型推导

🎯 项目目标

  • ✅ 完整的 TypeScript 重写
  • ✅ 保持 API 兼容性
  • ✅ Monorepo 架构
  • ✅ 完整的测试覆盖
  • ✅ 现代化构建系统
  • 🚧 性能优化
  • 🚧 更多示例和文档

📄 许可证

MIT

🤝 贡献

欢迎提交 Issue 和 Pull Request!

📦 打包产物

本项目使用 tsdown 进行打包,最终产物为零依赖的纯 ESM 模块:

✨ 打包产物信息:
ℹ dist/index.mjs   904.62 kB │ gzip: 278.74 kB
ℹ dist/index.d.ts   75.65 kB │ gzip:  20.25 kB
ℹ 2 files, total: 980.27 kB

📊 对比数据:
源包大小: 2.2MB / 65 packages (数据来源: https://pkg-size.dev/express)
打包后: 980.27 kB / 0 dependencies ⚡

🎯 零依赖优势

打包后的代码完全独立运行,无需安装任何额外依赖:

  • ✅ 部署简单:无需担心依赖版本冲突
  • ✅ 体积更小:打包后仅 980 KB(压缩后 278 KB)
  • ✅ 安全可靠:减少供应链攻击风险
  • ✅ 性能优化:减少模块加载开销

🚀 ESM 现代化

由于采用 ESM 格式,代码可完全参与任何现代化打包器的优化:

  • 🌲 Tree-shaking:自动移除未使用的代码
  • 📦 打包器友好:完美支持 Vite、Rollup、esbuild、webpack 等
  • 🔒 类型完整:包含完整的 TypeScript 类型定义
  • ⚡ 按需加载:支持动态 import 和代码分割

妈妈再也不用担心打包器无法处理 Express 啦! 🎉

🙏 致谢

本项目基于 Express 进行重写,感谢 Express 团队及所有贡献者的杰出工作。

上游核心依赖

本项目将以下核心依赖整合到 Monorepo 中,并进行了 TypeScript 重写:

路由与中间件

静态文件服务

请求体解析

  • body-parser - 请求体解析器(已整合重写)
    • JSON 解析
    • URL-encoded 解析
    • Raw 解析
    • Text 解析

运行时依赖库

以下依赖库在打包时被内联,最终产物为零依赖:

HTTP 工具

工具库

开发工具

构建与类型

  • TypeScript (v5.9.3) - TypeScript 编译器
  • tsdown (v0.16.7) - 高性能 TypeScript 打包工具
  • tsx - TypeScript 执行器

测试框架

代码质量

特别感谢

📮 联系方式


如果这个项目对你有帮助,请给一个 ⭐️ Star 支持一下!

About

Fast, unopinionated, minimalist web framework for node.

Resources

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages