evok

Evok is a minimal framework for building event-driven workflows in TypeScript.

View on GitHub

Development Guide

This document provides technical details for developers working on this TypeScript package template, including build architecture, development workflows, and implementation patterns.

Build Architecture

TypeScript Configuration

Multiple TypeScript Configurations:

Key Settings:

[!TIP] For detailed information about TypeScript setup, see the TypeScript Setup Guide.

Build System (tsup)

Why tsup over tsc:

Configuration (tsup.config.ts):

export default defineConfig({
  target: "node20", // Target Node.js 20+
  entry: ["src/index.ts"], // Single entry point
  outDir: "dist", // Output directory
  format: ["esm", "cjs"], // Dual module format
  sourcemap: true, // Source maps for debugging
  clean: true, // Clean output before build
  dts: true, // Generate .d.ts files
  splitting: true, // Code splitting for better tree-shaking
  treeshake: true, // Remove unused code
  esbuildOptions(options) {
    options.alias = {
      "@": "./src",
    };
  },
});

Module Format Strategy

Dual ESM/CJS Support:

package.json Configuration:

{
  "main": "./dist/index.cjs", // CommonJS entry
  "module": "./dist/index.js", // ESM entry
  "types": "./dist/index.d.ts", // TypeScript declarations
  "exports": {
    ".": {
      "import": {
        "types": "./dist/index.d.ts",
        "import": "./dist/index.js"
      },
      "require": {
        "types": "./dist/index.d.cts",
        "require": "./dist/index.cjs"
      }
    },
    "./helpers": {
      "import": {
        "types": "./dist/helpers/index.d.ts",
        "import": "./dist/helpers/index.js"
      },
      "require": {
        "types": "./dist/helpers/index.d.cts",
        "require": "./dist/helpers/index.cjs"
      }
    }
  },
}

Testing Strategy

Vitest Configuration

Why Vitest:

Key Features Configured:

Test Patterns:

Coverage Configuration

Coverage Setup:

Development Workflow

Validation Pipeline

The npm run validate Command:

  1. Type checking - tsc --noEmit --project tsconfig.build.json
  2. Linting with auto-fix - eslint --fix
  3. Formatting with auto-fix - prettier --write .
  4. Testing - vitest run

Why This Order:

Development Scripts

Core Development:

Quality Assurance:

Testing:

Key Implementation Patterns

Runtime Validation Pattern

Dual Validation Strategy:

Implementation:

export const example = (person: Person) => {
  // Runtime validation for JavaScript users
  if (
    !person ||
    typeof person.name !== "string" ||
    typeof person.age !== "number"
  ) {
    throw new Error("Invalid person object...");
  }
  // Implementation continues...
};

Type Constraint Testing

Testing TypeScript Types:

// Test invalid types would fail compilation
const testCases = [
  { name: "John Doe" }, // missing age
  { age: 30 }, // missing name
];

testCases.forEach((invalidPerson) => {
  // @ts-expect-error - Intentionally testing invalid types
  expect(() => example(invalidPerson)).toThrow("Invalid person object");
});

Path Alias Usage

Clean Imports:

Code Quality Setup

ESLint Configuration

Rules Applied:

Prettier Configuration

Formatting Strategy:

File Organization

Source Structure

src/
├── index.ts      # Main exports and public API
└── logger.ts    # Logger utility for consistent logging
└── helpers/     # Helper functions and utilities

Test Structure

tests/
└── index.test.ts # Comprehensive tests including type constraints

Configuration Files

├── tsconfig.json         # Development TypeScript config
├── tsconfig.build.json   # Build-specific TypeScript config
├── tsup.config.ts        # Build configuration
├── vitest.config.ts      # Test configuration
├── eslint.config.js      # Linting rules
└── prettier.config.json  # Code formatting

Technical Decisions

Why These Tools?

tsup over tsc: Faster builds, easier dual-format output, better developer experience

vitest over jest: Native ES modules, faster execution, better TypeScript integration

ESLint + Prettier: Industry standard, extensive rule ecosystem, editor integration

tsx over ts-node: Faster TypeScript execution, better ES modules support

standard-version: Conventional commits, automated changelog, semantic versioning

Development Philosophy

  1. Fast Feedback Loops: Watch modes, hot reloading, instant type checking
  2. Comprehensive Validation: Multiple layers of checking before commits
  3. Modern Tooling: Embrace latest JavaScript/TypeScript capabilities
  4. Portability: Self-contained packages that work independently
  5. Developer Experience: Clear error messages, helpful tooling, good defaults