Thank you for your interest in contributing to vext! We welcome contributions of all kinds — bug fixes, new features, documentation improvements, and more.
- Development Setup
- Project Structure
- Contribution Workflow
- Code Style
- Testing
- Commit Convention
- Pull Request Guidelines
- Reporting Issues
- Node.js >= 18.0.0
- npm >= 9.0.0
- Git
git clone https://github.com/YOUR_USERNAME/vext.git
cd vextnpm ci # Use ci for reproducible installs# Type check
npx tsc --noEmit
# Run all tests
npm test
# Run specific test suites
npm run test:unit # Unit tests only
npm run test:int # Integration tests only
npm run test:e2e # E2E tests only
npm run test:cov # With coverage reportvext/
├── src/
│ ├── adapters/ # Adapter implementations (hono, fastify, express, koa, native)
│ ├── cli/ # CLI commands (start, dev, build, create, stop, reload, status)
│ │ └── utils/ # CLI utilities (project detection)
│ ├── lib/ # Core framework modules
│ │ ├── build/ # Build compiler (esbuild)
│ │ ├── cluster/ # Cluster multi-process management
│ │ ├── dev/ # Dev server (hot reload, file watcher)
│ │ ├── middlewares/ # Built-in middlewares
│ │ ├── openapi/ # OpenAPI / Swagger generation
│ │ └── plugins/ # Built-in plugins (monsqlize)
│ ├── testing/ # Test utilities (createTestApp)
│ └── types/ # TypeScript type definitions
├── test/
│ ├── unit/ # Unit tests (mirrors src/ structure)
│ ├── integration/ # Integration tests
│ ├── e2e/ # End-to-end tests
│ └── benchmark/ # Performance benchmarks
├── .github/
│ ├── workflows/ # CI/CD pipelines
│ └── ISSUE_TEMPLATE/ # Issue templates
├── tsconfig.json
├── vitest.config.ts
└── package.json
- Adapters: vext supports 5 HTTP adapters (Hono, Fastify, Express, Koa, Native). All adapters implement the
VextAdapterinterface and must pass the same test suite. - Middleware Chain: Uses an onion model (
executeChainwithdispatch(i)recursion). Global middlewares are prepended to route-level chains. - Service Loader: Auto-scans
src/services/and injects instances intoapp.services. - Config Loader: Merges
default→{NODE_ENV}→localconfig files with environment variable overrides.
git checkout -b feature/your-feature-name
# or
git checkout -b fix/your-bug-fix- Follow existing code patterns and conventions
- Add JSDoc comments for all public APIs
- Keep functions focused and small
- Every new feature or bug fix must include tests
- Match the test file structure to the source file structure
- Use descriptive test names
# Type check (must pass with zero errors)
npx tsc --noEmit
# Run all tests
npm test
# Run only your tests during development
npx vitest run test/unit/your-test-file.test.tsPush your branch and open a PR against main.
- Strict mode enabled — no
anyunless absolutely necessary (witheslint-disablecomment) - ESM — use
import/export, file extensions in imports (.jssuffix for TypeScript) - Explicit types for function parameters and return types on public APIs
- Readonly where applicable
| Type | Convention | Example |
|---|---|---|
| Variables / Functions | camelCase | createApp, loadConfig |
| Classes | PascalCase | ClusterMaster, HttpError |
| Constants | UPPER_SNAKE_CASE | DEFAULT_CONFIG, EMPTY_MIXIN |
| Interfaces / Types | PascalCase | VextAdapter, VextRequest |
| Files | kebab-case | config-loader.ts, rate-limit.ts |
- All public APIs must have JSDoc with
@param,@returns, and@examplewhere helpful - Use
// ── Section Name ──comment separators for file organization - Keep comments meaningful — explain why, not what
// 1. Imports (grouped: node built-ins → third-party → project internal)
import fs from "node:fs";
import path from "node:path";
import type { VextApp } from "../types/app.js";
// 2. Type definitions
interface MyOptions {
/* ... */
}
// 3. Constants
const DEFAULT_VALUE = 42;
// 4. Main exports (classes, functions)
export function myFunction(): void {
/* ... */
}
// 5. Helper functions (private)
function helperFunction(): void {
/* ... */
}- Vitest for all tests
- No external test databases or services — use mocks for I/O
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
describe("ModuleName", () => {
describe("functionName", () => {
it("should do X when Y", () => {
// Arrange
// Act
// Assert
});
it("should throw when invalid input", () => {
expect(() => fn(null)).toThrow("[vextjs]");
});
});
});| Type | Location | Command | Purpose |
|---|---|---|---|
| Unit | test/unit/ |
npm run test:unit |
Test individual functions/classes in isolation |
| Integration | test/integration/ |
npm run test:int |
Test module interactions (cluster IPC, etc.) |
| E2E | test/e2e/ |
npm run test:e2e |
Test full HTTP request/response with real adapters |
| Benchmark | test/benchmark/ |
npm run test:bench |
Performance measurements (not part of CI) |
- Aim for 80%+ coverage on new code
- Critical paths (adapters, middleware chain, config loader) should be 90%+
- Run
npm run test:covto generate coverage reports
If your change affects adapter behavior, test across all 5 adapters:
const adapters = ["hono", "fastify", "express", "koa", "native"];
for (const adapter of adapters) {
describe(`${adapter} adapter`, () => {
it("should handle the scenario", async () => {
// Test with this adapter
});
});
}We follow Conventional Commits:
<type>(<scope>): <description>
[optional body]
[optional footer]
| Type | Description |
|---|---|
feat |
New feature |
fix |
Bug fix |
docs |
Documentation only |
test |
Adding or updating tests |
refactor |
Code change that neither fixes a bug nor adds a feature |
perf |
Performance improvement |
ci |
CI/CD changes |
chore |
Maintenance tasks |
adapter, cli, middleware, config, cluster, openapi, plugin, types, benchmark, dev
git commit -m "feat(adapter): add WebSocket support to native adapter"
git commit -m "fix(cli): handle spaces in project path for vext create"
git commit -m "test(middleware): add rate-limit edge case tests"
git commit -m "perf(adapter): reduce closure allocations in executeChain"
git commit -m "docs: update README with benchmark results"- TypeScript compiles with zero errors (
npx tsc --noEmit) - All tests pass (
npm test) - New code has test coverage
- JSDoc comments added for public APIs
- No unnecessary
console.logstatements left in code - Commit messages follow conventional commits
Use the PR template — it includes:
- Description of changes
- Type of change (bug fix, feature, breaking change, etc.)
- Adapter impact assessment
- Test results
- Checklist
- Automated checks: CI runs type checking, linting, and full test suite (Node 18/20/22)
- Code review: At least one maintainer review required
- Merge: Squash merge to
mainwith conventional commit message
If your PR introduces a breaking change:
- Add
💥to the PR title - Document the breaking change in the PR body
- Explain the migration path for users
- Breaking changes will be batched into the next major version
Use the Bug Report template. Include:
- Environment: Node.js version, OS, adapter in use
- Reproduction steps: Step-by-step instructions
- Minimal code example: The smallest code that reproduces the issue
- Error output: Full stack trace and log output
Use the Feature Request template. Include:
- Motivation: Why this feature is needed
- Proposed API: How you'd like to use it
- Adapter scope: Which adapters are affected
If you want to contribute a new adapter:
-
Create
src/adapters/<name>/with these files:adapter.ts— implementsVextAdapterinterfacerequest.ts— createsVextRequestfrom framework's native requestresponse.ts— createsVextResponsewrapping framework's native responseindex.ts— exports the factory function
-
Register in
src/lib/adapter-resolver.ts -
Add to
src/lib/config-loader.tsknownAdapterslist -
Create
test/unit/adapters/<name>-adapter.test.tswith full coverage -
Verify all E2E tests pass with the new adapter
-
Update
src/cli/create.tsto include the adapter inVALID_ADAPTERSandADAPTER_DEPS
By contributing to vext, you agree that your contributions will be licensed under the MIT License.
Thank you for helping make vext better! 🚀