TypeScript Project Template with esbuild

TypeScript Serverless Project Template

A robust template for building serverless applications using TypeScript, AWS Lambda, and Serverless Framework with esbuild bundling.

Project Structure

lib/
└── helper.ts              # Shared utility functions
services/ts-test/
├── serverless.yml        # Serverless configuration
├── src/
│   ├── handlers/         # Lambda function handlers
│   │   └── view.ts
│   └── utils/           # Service-specific utilities
│       └── util.ts
└── tsconfig.json        # TypeScript configuration

Features

  • TypeScript support with strict type checking
  • Serverless Framework for easy AWS Lambda deployments
  • esbuild for fast bundle compilation
  • Shared library support across multiple services
  • Local development with serverless-offline
  • Source maps for better debugging
  • CORS support out of the box

Prerequisites

  • Node.js (v18.x or later)
  • AWS CLI configured with appropriate credentials
  • Serverless Framework CLI (npm install -g serverless)

Quick Start

  1. Clone this template:
git clone https://7EDGEx@dev.azure.com/7EDGEx/Backend/_git/Backend
  1. Install dependencies:
cd serverless-typescript/
npm install
cd services/ts-test
  1. Run locally:
serverless offline
  1. Deploy:
# Deploy to dev stage (default)
serverless deploy

# Deploy to specific stage
serverless deploy --stage dev

Install Serverless plugins and esbuild (if not exists in package.json)

npm install --save-dev serverless-esbuild esbuild serverless-offline

Configuration

TypeScript Configuration (tsconfig.json)

The project uses a TypeScript configuration optimized for AWS Lambda:
(customize based on your requirements)

{
  "compilerOptions": {
    "preserveConstEnums": true,
    "strictNullChecks": true,
    "sourceMap": true,
    "allowJs": true,
    "target": "es2020",
    "module": "commonjs",
    "moduleResolution": "node",
    "outDir": ".build",
    "rootDir": "./",
    "baseUrl": "./",
    "paths": {
      "@lib/*": ["../../lib/*"]
    }
  },
  "include": [
    "src/**/*.ts",
    "lib/**/*.ts"
  ],
  "exclude": [
    "node_modules"
  ]
}

Key features:

  • Path aliases for shared library imports (@lib/*)
  • Source map generation for debugging
  • Strict null checks for better type safety
  • ES2020 target for modern Node.js features

Serverless Configuration (serverless.yml)

service: ts-test
provider:
  name: aws
  runtime: nodejs20.x
  region: ap-south-1

functions:
  view:
    handler: src/handlers/view.handler
    events:
      - http:
          path: /
          method: get
          cors: true

plugins:
  - serverless-esbuild
  - serverless-offline

custom:
  esbuild:
    bundle: true
    minify: false
    sourcemap: true
    target: "node20"
    platform: "node"
    concurrency: 10

Key features:

  • esbuild configuration for optimal bundling
  • CORS enabled by default
  • Environment variables support
  • Local development support

Handler Example

Here’s an example of a typical Lambda handler with TypeScript:

import { APIGatewayProxyEvent, APIGatewayProxyResult } from 'aws-lambda';
import { headers } from '@lib/helper';

export const handler = async (
  event: APIGatewayProxyEvent
): Promise<APIGatewayProxyResult> => {
  return {
    statusCode: 200,
    headers,
    body: JSON.stringify({
      message: 'Success',
      data: headers,
    }),
  };
};

Shared Library Usage

The project supports a shared library pattern. Example usage:

// In lib/helper.ts
export const headers: Record<string, string> = {
    'Content-Type': 'application/json',
    'Access-Control-Allow-Origin': '*',
    'Access-Control-Allow-Credentials': 'true',
};

// In your handler
import { headers } from '@lib/helper';

Development Workflow

Local Development

Start the local development server:

cd services/ts-test
serverless offline

This will:

  • Start a local API Gateway emulator
  • Enable automatic rebuilding on file changes
  • Provide local endpoints for testing
  • Watch for file changes (with esbuild watch mode)

Deployment

Deploy to AWS (from within the service directory):

# Deploy to dev stage
serverless deploy

# Deploy to specific stage
serverless deploy --stage production

# Deploy a single function
serverless deploy function -f functionName

Package Only (No Deployment)

Create deployment package without deploying:

serverless package

Testing Functions Locally

Test specific functions locally:

serverless invoke local -f functionName

esbuild Configuration

The project uses serverless-esbuild plugin with optimized settings:

custom:
  esbuild:
    bundle: true          # Bundles all dependencies
    minify: false        # Keeps code readable
    sourcemap: true      # Enables debugging
    target: "node20"     # Optimizes for Node.js 20
    platform: "node"     # Targets Node.js platform
    concurrency: 10      # Parallel bundling

Git Ignore

sample .gitignore for ignoring .map and build files

# Ignore built JavaScript files in specific directories
serverless-typescript/services/**/lib/**/*.js
serverless-typescript/services/**/lib/**/*.js.map
serverless-typescript/lib/**/*.js
serverless-typescript/lib/**/*.js.map

# Ignore the entire .build directory
.build/

Additional esbuild features available:

  • Custom plugins support
  • External dependency management
  • Watch mode for development
  • Customizable build options

Best Practices

  1. Type Safety

    • Use strict TypeScript configurations
    • Define interfaces for all data structures
    • Utilize AWS Lambda types
  2. Code Organization

    • Keep handlers focused on routing logic
    • Move business logic to separate services
    • Share common code through the lib directory
  3. Error Handling

    • Implement proper error boundaries
    • Use typed error responses
    • Include appropriate HTTP status codes
  4. Testing

    • Write unit tests for business logic
    • Use integration tests for API endpoints
    • Test locally before deployment

Troubleshooting

Common issues and solutions:

  1. Path Resolution Issues

    # Ensure you're in the correct service directory
    cd services/ts-test
    # Check tsconfig.json paths configuration
    
  2. Build Errors

    # Clear esbuild cache
    rm -rf .esbuild
    # Try deploying again
    serverless deploy
    
  3. Deployment Failures

    • Verify AWS credentials
    • Check CloudWatch logs
    • Ensure proper IAM permissions
    • Run serverless print to check the final configuration
  4. Local Development Issues

    # Start with debugging
    serverless offline --verbose
    # Or with specific stage
    serverless offline --stage dev
    
6 Likes