TPT

ts-package-template

Overview

Comprehensive technical overview of the ts-package-template architecture, build system, and publishing workflow

The content in this page may have been generated by AI.

ts-package-template is a future-proof TypeScript package template designed for library authors. It focuses on modern tooling, developer experience, and production-ready configuration for publishing npm packages. The template provides everything needed to quickly start developing TypeScript libraries with minimal setup.

This template is perfect for library authors, offering zero-configuration modern tooling for TypeScript packages. It includes Rolldown bundler, Biome linting, Vitest testing, and np publishing - everything you need to quickly start developing TypeScript libraries with minimal setup.


Architecture

The template follows a minimal but complete structure that balances simplicity with production readiness:

index.ts
index.test.ts
biome.json
cliff.toml
tsconfig.json
tsconfig.build.json
tsdown.config.ts
package.json
pnpm-workspace.yaml

Design Philosophy

The template is built on four key principles:

Minimal but Complete

Only essential files are included, but all necessary configurations are present for a production-ready package.

Modern by Default

Uses latest versions of all tools with sensible, opinionated defaults.

Zero-Configuration

Works out of the box with opinionated but customizable settings.

Production-Ready

Includes testing, linting, changelog generation, and publishing workflows.


Core Technologies

Language & Runtime

Prop

Type

Bundling

Prop

Type

Why Rolldown?

Rolldown is a Rollup-compatible bundler written in Rust, offering: ✅ Excellent performance (Rust-based) ✅ Rollup compatibility (familiar configuration) ✅ Modern ESM support ✅ Growing ecosystem

Code Quality

Prop

Type

Biome Benefits

Biome replaces ESLint + Prettier with a single, faster tool: ✅ Faster linting and formatting ✅ Simpler configuration ✅ Consistent code style ✅ Built-in formatter

Testing

Prop

Type

Vitest Features

✅ Native ESM support ✅ Fast test execution ✅ TypeScript support out of the box ✅ Watch mode for development

Publishing & Versioning

Prop

Type


Key Implementation Details

Build System: Rolldown + tsdown

The template uses Rolldown as the bundler with tsdown for TypeScript integration:

Key build features include:

  • Fast builds with Rust-based bundler
  • Rollup compatibility for familiar configuration
  • Seamless TypeScript integration with tsdown
  • ESM-first optimization

Configuration

tsdown.config.ts
import { defineConfig } from "tsdown";

export default defineConfig({
  entry: {
    index: "src/index.ts",
  },
  dts: true,
  tsconfig: "tsconfig.build.json",
  format: "esm",
  sourcemap: false,
});

Prop

Type

Build Process

TypeScript Compilation

tsc runs first with tsconfig.build.json to check types.

Bundling

Rolldown processes the compiled output with tsdown plugin.

Declaration Generation

tsdown generates .d.ts and .d.mts type declaration files.

Build Outputs

Prop

Type

Package Configuration

The package.json is optimized for modern package publishing:

package.json
{
  "type": "module",
  "exports": {
    ".": {
      "import": "./dist/index.mjs",
      "types": "./dist/index.d.mts"
    }
  },
  "files": ["dist", "LICENSE", "README.md", "CHANGELOG.md"],
  "types": "dist/index.d.ts",
  "scripts": {
    "dev": "tsdown --watch ./src",
    "build": "tsc && tsdown",
    "check": "ultracite check",
    "test": "vitest run",
    "changelog": "git-cliff --config ./cliff.toml --output CHANGELOG.md",
    "publish": "np --package-manager npm",
    "publish:all": "pnpm run build && pnpm run publish"
  }
}

Key configuration features:

  • ESM-first: "type": "module" declares the package as ESM
  • Conditional Exports: Different entry points for ESM and CJS consumers
  • Type Exports: Separate type files for ESM and CommonJS
  • Selective Publishing: Only essential files are published

TypeScript Configuration

The template uses two TypeScript configuration files for different purposes:

Development Configuration

tsconfig.json
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "ESNext",
    "moduleResolution": "bundler",
    "strict": true,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "forceConsistentCasingInFileNames": true,
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "types": ["vitest/globals"]
  },
  "include": ["src", "test"],
  "exclude": ["dist", "node_modules"]
}

Development config has noEmit: true to prevent accidental emission during development. Includes Vitest globals for type-safe testing.

Build Configuration

tsconfig.build.json
{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "noEmit": false,
    "emitDeclarationOnly": true,
    "outDir": "./dist"
  },
  "include": ["src"]
}

Build config extends development config and enables declaration emission. Only processes src/ directory (not tests).

Changelog Generation with git-cliff

The template uses git-cliff for automatic changelog generation based on conventional commits:

cliff.toml
[changelog]
body = '''
# Changelog

All notable changes to this project will be documented in this file.
'''

[git]
conventional_commits = true
topological_order = true

[commit_parsers]
feat = { message = "^feat", group = "Features" }
fix = { message = "^fix", group = "Bug Fixes" }
doc = { message = "^doc", group = "Documentation" }
perf = { message = "^perf", group = "Performance" }
refactor = { message = "^refactor", group = "Refactor" }
style = { message = "^style", group = "Styling" }
test = { message = "^test", group = "Testing" }
chore = { message = "^chore", group = "Miscellaneous Chores" }
revert = { message = "^revert", group = "Reverts" }

Conventional Commits

The template follows Conventional Commits specification: ✅ feat: - A new feature ✅ fix: - A bug fix ✅ docs: - Documentation only changes ✅ style: - Changes that do not affect code meaning ✅ refactor: - Code change that neither fixes a bug nor adds a feature ✅ perf: - A code change that improves performance ✅ test: - Adding missing tests ✅ chore: - Changes to the build process ✅ revert: - Reverts a previous commit

Publishing with np

The template uses np for a better npm publish experience:

np Features

✅ Interactive prompts for version bump and confirmation ✅ Safety checks before publishing ✅ Automatic version bump based on commit messages ✅ Git tag creation (annotated tags) ✅ Package manager support (npm, yarn, pnpm)

Publishing Commands
# Check code quality first
pnpm check

# Generate changelog
pnpm changelog

# Publish to npm
pnpm publish

# Build and publish (all-in-one)
pnpm publish:all

Intended Use Case

This template is ideal for:

Perfect For

✅ Library development (reusable TypeScript packages for npm) ✅ Modern ESM packages with native ES Modules support ✅ Type-safe libraries with full TypeScript declaration support ✅ Production publishing with complete CI/CD ready configuration ✅ Maintainable projects with built-in changelog generation ✅ Developer tools, CLI utilities, and frameworks


Development Workflow

Setup

Clone the repository

git clone https://github.com/LuanRoger/ts-package-template.git

Install dependencies

cd ts-package-template && pnpm install

Modify package.json

# Set your package name, version, description, author, etc.

Development

Start watch mode

pnpm dev

Runs: tsdown --watch ./src Watches for changes in src/ and rebuilds automatically.

Edit source files

Modify files in src/ directory. Changes trigger automatic rebuilds.

Build

Build the package

pnpm build

Runs: tsc && tsdown

  1. TypeScript compilation check
  2. Rolldown bundling with tsdown

Code Quality

Check code quality

pnpm check

Runs: ultracite check Checks for linting and formatting issues.

Auto-fix issues

pnpm check:write

Runs: ultracite fix Automatically fixes linting and formatting issues.

Testing

Run tests once

pnpm test

Runs: vitest run

Run tests in watch mode

pnpm test:watch

Runs: vitest (watch mode) Automatically re-runs tests on file changes.

Publishing

Generate changelog

pnpm changelog

Runs: git-cliff --config ./cliff.toml --output CHANGELOG.md Generates or updates CHANGELOG.md based on conventional commits.

Publish to npm

pnpm publish

Runs: np --package-manager npm Interactive publishing with safety checks.

Build and publish

pnpm publish:all

Runs: pnpm run build && pnpm run publish Complete workflow in one command.


Project Structure Details

Source Code (src/)

The src/ directory contains your package's source code:

Best Practices

✅ Export your public API from index.ts ✅ Use named exports for better tree-shaking ✅ Keep internal modules in separate files ✅ Use TypeScript types for better developer experience ✅ Document all public APIs with JSDoc comments

Tests (test/)

The test/ directory contains your test files:

test/index.test.ts
import { describe, expect, it } from "vitest";
import { hello } from "../src";

describe("hello", () => {
  it("should return a greeting", () => {
    expect(hello("World")).toBe("Hello, World!");
  });
});

// Test async functions
import { greetAsync } from "../src";

describe("greetAsync", () => {
  it("should return a greeting asynchronously", async () => {
    const result = await greetAsync("World");
    expect(result).toBe("Hello, World!");
  });
});

Testing Features

✅ Vitest: Fast, modern test runner ✅ Native ES Modules support ✅ Full TypeScript support ✅ Watch mode for development ✅ Concurrent test execution

Configuration Files

Prop

Type

Prop

Type


Best Practices

Package Naming

Naming Guidelines

Follow these conventions for package naming:

  • Scoped packages: Use @yourname/package-name for organization
  • Naming: Use kebab-case: my-awesome-package
  • Length: Keep names short and descriptive
  • Uniqueness: Avoid generic names that might conflict

Versioning

Semantic Versioning

Follow SemVer principles:

  • Major: Breaking changes
  • Minor: New features (backwards-compatible)
  • Patch: Bug fixes (backwards-compatible)

Use conventional commits for automatic version bumps with np.

Exports

Export Guidelines

✅ Use named exports for better tree-shaking ✅ Provide TypeScript declarations for all exports ✅ Consider conditional exports for ESM/CJS compatibility ✅ Document all public APIs

Good vs Bad Exports
// ✅ Good: Named exports with types
export interface Options {
  timeout?: number;
  retries?: number;
}

export function fetchData(url: string, options?: Options): Promise<Response> {
  // Implementation
}

export function postData(url: string, data: unknown): Promise<Response> {
  // Implementation
}

// ❌ Bad: Default export only
export default function(url: string) {
  // Harder to tree-shake
  // Less clear API
}

// ❌ Bad: No types
export function fetch(url: any) {
  // No type safety for consumers
}

Dependencies

Dependency Management

✅ Minimize dependencies (only include what's necessary) ✅ Use peerDependencies for optional dependencies ✅ Specify exact versions in devDependencies ✅ Test with latest versions of dependencies

TypeScript

TypeScript Best Practices

✅ Enable strict mode (all strict type-checking options) ✅ Use explicit types (avoid any and unknown where possible) ✅ Document types with JSDoc comments ✅ Export types to make them available to consumers


Comparison with Other Templates

Why Choose ts-package-template?

Comparison with traditional templates:

Prop

Type


Troubleshooting

Common Issues & Solutions

Find quick solutions to common problems:

Build Issues

TypeScript errors during build

pnpm check

Check for linting and formatting issues first.

Missing type definitions

Install required types:

pnpm add -D @types/node

Configuration issues

Verify tsconfig.json and tsdown.config.ts are properly configured.

Test Issues

Tests not running

Ensure test files have .test.ts or .spec.ts extension.

Type errors in tests

Add Vitest globals to tsconfig.json:

{ "types": ["vitest/globals"] }

Vitest not installed

pnpm add -D vitest

Changelog Issues

Changelog not updating

Ensure commits follow conventional commits format.

Configuration issues

Check cliff.toml configuration.

Git history missing

Verify git history is available in the repository.

Publish Issues

Publish fails

Ensure you're logged in to npm:

npm login

Package name conflict

Check package name is unique on npm.

Missing files

Verify files in package.json includes necessary files.


Additional Resources


Last updated: 2026-06-26T21:07:13.735Z

On this page