Mark's notes on software development

Building a Serverless Node.js Application with ESM and TypeScript in 2024

Have you ever encountered the frustrating challenge of trying to import an ESM module in Node.js, only to be met with a barrage of errors?

This common issue plagues many developers, especially when transitioning from older module systems to the modern ESM (ECMAScript Module) format. Perhaps you've found yourself stuck with import statements not working as expected, or the Node.js runtime throwing cryptic errors about module resolution. This hurdle is a significant one in the evolving JavaScript landscape.

In this comprehensive guide, we address these challenges head-on as we embark on a journey to construct a state-of-the-art Serverless Node.js application, utilizing ECMAScript Modules (ESM) and TypeScript. This article is designed as a progressive tutorial, where each section builds upon the previous one. Starting with a basic JavaScript setup, we incrementally integrate TypeScript and Serverless technologies, culminating in a sophisticated, deployable application. Whether you're new to modern JavaScript development or seeking to refine your skills with the latest standards, this guide will walk you through the entire process, layer by layer.

JavaScript

Initializing the Project:

Initialize your project with:

yarn init

Setting Up .gitignore for Node.js:

Retrieve a Node.js-specific .gitignore file:

curl https://www.toptal.com/developers/gitignore/api/node > .gitignore

Configuring package.json:

Amend your package.json as follows:

  "type": "module",
  "engines": {
    "node": ">=16"
  },

Installing Linting Tools:

Install xo for project linting:

yarn add -D xo

Creating Editor Configuration:

Create a .vscode/settings.json file:

{
    "xo.format.enable": true,
    "prettier.enable": false,
    "eslint.enable": false,
    "editor.defaultFormatter": "samverschueren.linter-xo",
    "eslint.codeActionsOnSave.rules": null,
    "[typescript]": {
        "editor.defaultFormatter": "samverschueren.linter-xo"
    },
    // ... other settings
}

XO will automatically correct paths like "./lib" to "./lib.js" and "fs" to "node:fs".

Adding a Lint Script:

Add a lint script to package.json:

{
  "scripts": {
    "lint": "xo"
  }
}

TypeScript

Writing Code in TypeScript:

Write your code in TypeScript, retaining ".js" extensions for imports.

Installing TypeScript Dependencies:

Install TypeScript essentials:

yarn add --dev typescript tsx @tsconfig/node20

Creating a tsconfig.json:

Establish a tsconfig.json with these settings:

{
    "extends": "@tsconfig/node20/tsconfig.json",
    "compilerOptions": {
        "moduleResolution": "node16",
        "outDir": "dist",
    },
}

Running your TypeScript Code:

Execute your code:

yarn tsx ./src/main.ts

Building your TypeScript Code:

Compile your TypeScript code:

yarn tsc

Serverless

Installing Dependencies:

Install necessary packages:

yarn add -D serverless serverless-offline serverless-plugin-typescript

Creating a serverless.yml File:

Set up a basic serverless.yml:

service: my-service

plugins:
  - serverless-offline
  - serverless-plugin-typescript

provider:
  name: aws
  runtime: nodejs18.x
  region: eu-west-1

functions:
  myFunction:
    handler: src/handler.handler
    events:
      - http:
          path: /
          method: get

Creating an AWS Lambda Handler:

Develop a handler in src/handler.ts:

export const handler = async (event: any) => ({
    statusCode: 200,
    body: JSON.stringify({
        message: 'Hello, World!',
    }),
});

Running Offline:

Test locally with:

yarn sls offline start

Deploying to AWS:

Deploy your application:

yarn sls deploy

Conclusion

Wrapping up, it's clear that building a modern Node.js app with ESM and TypeScript is more straightforward than you might think. It's all about getting the configuration right.

Check Out the Full Example:

For a hands-on look, visit my GitHub repo with the completed example from this guide: ESM Serverless Starter. It's a great resource for your projects.

What's Next?

This is just the start. I'll be writing more about using ESM, focusing on practical, real-world applications. Stay tuned for the next article on creating ESM modules.

Thanks for reading, and happy coding!

#esm #programming #tutorial #typescript