Search code examples
typescriptnrwl-nxesbuildtypescript-decorator

Use ESBuild plugins for decorators with NX


I have created a Node.js project with Typescript with nx using the command

nx g @nx/node:application [name] --framework none --projectNameAndRootFormat derived

Here is the build configuration in my project.json:

"build": {
  "executor": "@nx/esbuild:esbuild",
  "defaultConfiguration": "production",
  "fileName": "main.js",
  "options": {
    "platform": "node",
    "outputPath": "dist/apps/project-name",
    "format": ["esm"],
    "bundle": true,
    "main": "apps/project-name/src/main.ts",
    "tsConfig": "apps/project-name/tsconfig.app.json",
    "assets": ["apps/fproject-name/src/assets"],
    "generatePackageJson": true,
    "esbuildOptions": {
      "sourcemap": true,
      "outExtension": {
        ".js": ".js"
      }
    }
  },
  "configurations": {
    "development": {},
    "production": {
      "esbuildOptions": {
        "sourcemap": false,
        "outExtension": {
          ".js": ".js"
        }
      }
    }
  }
}

The created project uses the NX executor @nx/esbuild:esbuild. Now I want to be able to use dependency injection frameworks, such as TypeDI. The problem is that ESBuild does not support the tsconfig property "emitDecoratorMetadata": true which is required for most dependency injection frameworks for Typescript. There are plugins that can make ESBuild support this such as esbuild-decorators.

Previously it seems like it hasn't been possible to add a plugin to ESBuild with NX. However, based on this issue and this PR it seems like it should now be possible. The problem is that I cannot find any documentation on how it is done.

So in summary: How do I add the esbuild-decorators plugin to my NX app running ESBuild?


Solution

  • Passing a custom config is done like this:

    apps/project/project.json

    "targets": {
      "build": {
          "executor": "@nx/esbuild:esbuild",
          "outputs": ["{options.outputPath}"],
          "defaultConfiguration": "production",
          "options": {
              "platform": "node",
              "outputPath": "dist/apps/project-name",
              "format": ["esm"],
              "bundle": true,
              "main": "apps/project-name/src/main.ts",
              "tsConfig": "apps/project-name/tsconfig.app.json",
              "assets": ["apps/fproject-name/src/assets"],
              "generatePackageJson": true,
              "esbuildConfig": "apps/project/esbuild.config.ts"
          },
          ...
      },
      ...
    }
    

    And:

    apps/project/esbuild.config.ts

    const { esbuildDecorators } = require("@anatine/esbuild-decorators")
    
    module.exports = {
      sourcemap: true,
      outExtension: {
          ".js": ".js"
      },
      plugins: [esbuildDecorators()],
      keepNames: true
    }
    

    Let me know how it works for you!