Ben Force
Ben Force - 5x AWS Certified Senior Software Engineer.
Published 2 min read

How to Use TypeScript Decorators with esbuild

How to Use TypeScript Decorators with esbuild

Just about every developer that I meet has one, or more, side-projects that they work on. My primary side project (an Alexa skill called Movie Quiz) has helped me learn several new technologies over the years. Working on this skill has taught me everything from DynamoDB single-table design to CI/CD pipelines.

I recently learned about NestJS at work and the power of Inversion of Control and Dependency Injection. It just so happens that someone kindly added Dependency Injection to the framework that I use for my skill. Also, I’ve been having a difficult time getting some updates in the skill through certification, so it seemed like a good time to implement DI and write more some unit tests.

Issues with esbuild

Esbuild is a super fast typescript bundler. It gains this speed by completely ignoring the typescript. The problem with that is the Dependency Injection that I wanted to use relies on TypeScript Decorators. I had to turn on emitDecoratorMetadata and experimentalDecorators in my tsconfig file, but since esbuild just ignores that, all I get are errors.

Slowing Down esbuild

The solution was to get a plugin that negated all of the performance gained by ignoring TypeScript. The plugin runs each typescript file through tsc before passing it to esbuild.

First, install the esbuild-plugin-tsc package:

pnpm install -D esbuild-plugin-tsc

Now import it and pass it into your esbuild configuration. I’m using esbuild with serverless stack, so the options are a little nested, but you can use plugins directly with esbuild as well.

import esbuildPluginTsc from 'esbuild-plugin-tsc';
...
const handler = new sst.Function(stack, 'Handler', {
  nodejs: {
    esbuild: {
      plugins: [
        esbuildPluginTsc({
          tsconfigPath: path.join(HANDLER_ROOT, 'tsconfig.json'),
        }),
      ],
    }
  }
});

Use the Right Format

In addition to using the plugin, I had to update my esbuild options to create commonjs formatted output. While this was frustrating to figure out, it was pretty easy to implement. Just set the format setting to cjs. In the serverless stack function this is done in the nodejs configuration:

nodejs: {
  format: 'cjs',
  esbuild: {
    ...
  }
}

Summary

In this article, you’ve seen how to use decorators in a TypeScript project that’s bundled with esbuild. Hopefully, decorators will be standardized soon and we won’t have to worry about all of this. In the meantime, I hope this article saves a few people from the frustration of getting this to work!


Related Posts

Dynamic CDK Dashboards

Dynamic CDK Dashboards
Published 5 min read

Manually created dashboards can take up a lot of time to create and maintain. Learn how to automatically create CloudWatch dashboards in the AWS CDK using Aspects.

What Makes a Great Admin Portal?

What Makes a Great Admin Portal?
Published 7 min read

In this guide you will be covering all the aspects that you must keep in mind when building an admin portal, including security, backend data connectivity, charts and actionable UIs.

Optimizing Nest-Commander: User Inputs

Optimizing Nest-Commander: User Inputs
Published 4 min read

Learn how to boost the functionality of your Nest-Commander application by incorporating user inputs effectively. Discover essential tips and techniques for adding inputs to enhance user interaction and command versatility.