Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

decorators not running with esbuild #2509

Closed
fridaystreet opened this issue Nov 6, 2024 · 2 comments
Closed

decorators not running with esbuild #2509

fridaystreet opened this issue Nov 6, 2024 · 2 comments

Comments

@fridaystreet
Copy link

Describe the bug

Apologies I'm not 100% sure this is a bug, but I've tried all the usual stuff relating to esbuild with decorators and with still doesn't work. So maybe just looking for some guidnace as to what I'm missing as I've searched all over and can't find much in the way of questions etc related to this stuff

To Reproduce
use esbuild to build your module

(will try and get a sandbox up)

Expected behavior
dependancy injector decorators inject the depancies

Environment:

  • OS: OSX 15
  • @graphql-modules/...: ^2.4.0",
  • NodeJS: 20.18.0

Additional context

bable

{
  "presets": [
    ["@babel/preset-env", { "targets": { "node": "20.18.0" } }], // the target node version, boolean true, or "current".
    "@babel/preset-typescript"
  ],
  "plugins": [
    "babel-plugin-transform-typescript-metadata",
    ["@babel/plugin-proposal-decorators", { "legacy": false }],
//    "@babel/plugin-transform-class-properties"
    [
      "@babel/plugin-proposal-class-properties",
      {
        "loose": true
      }
    ]
  ]
}

tsconfig

{
  "compilerOptions": {
    "experimentalDecorators": true,
    "module": "ESNext",
    "target": "es6",
    "lib": ["es6", "esnext", "es2015"],
    "noImplicitAny": false,
    "allowSyntheticDefaultImports": true,
    "ignoreDeprecations": "5.0",
    "moduleResolution": "node",
    "emitDecoratorMetadata": true,
    "sourceMap": true,
    "inlineSources": true,
    "declaration": true,
    "sourceRoot": "/",
    "outDir": "./dist",
    "rootDir": "./src",
    "baseUrl": "./",
    "paths": {
      "@utils": ["./src/@utils"],
      "@api/*": ["./src/modules/api/*"],
      "@modules": ["./src/modules"],
      "@data": ["./src/modules/data"],
      "@services": ["./src/modules/services"],
      "@graphql-errors": ["src/@graphql-errors"],
      "@lambda-websocket-server": ["src/@lambda-websocket-server"]
    }
  },
  "include": ["src/**/*.ts", "src/modules/data/MongoDatasource/providers/index.js", "src/modules/data/DynamoDBDatasource/providers/index.js", "src/modules/services/index.js", "src/modules/data/Neo4jDatasource/schema/scalars/scalarResolvers.js", "src/@utils/scalars/scalarResolvers.js", "src/modules/data/initDataConnections.js"],
  "exclude": ["node_modules"]
}

esbuild

import { copy } from 'esbuild-plugin-copy'
import { esbuildDecorators } from 'esbuild-plugin-typescript-decorators'
import path from 'path'

const devMode = process.env.NODE_ENV === 'development'

export default async (serverless) => {

  return {
    outdir: 'dist',
    outExtension: { '.js': '.mjs' },
    entryPoints: ['src/index.ts'],
    bundle: true,
    minify: !devMode,
    sourcemap: devMode,
    sourcesContent: devMode,
    sourceRoot: devMode ? path.resolve('src') : undefined,
    target: 'node20',
    format: 'esm',
    mainFields: ['module', 'main'],
    tsconfig: './tsconfig.json',
    loader: {
      '.js': 'tsx',
      '.ts': 'tsx',
      '.tsx': 'tsx',
      '.graphql': 'text',
      '.gql': 'text',
      '.html': 'text'
    },
    banner: {
      js: `
        import { createRequire } from 'module';
        import { fileURLToPath } from 'url';
        import { dirname as _dirname } from 'path';
        import { DOMParser, DOMImplementation, XMLSerializer } from 'xmldom';
        const require = createRequire(import.meta.url);
        const __filename = fileURLToPath(import.meta.url);
        const __dirname = _dirname(__filename);
        global.DOMParser = DOMParser;
        global.XMLSerializer = XMLSerializer;
        global.document = new DOMImplementation().createDocument(null, 'xml', null);
      `
    },
    mainFields: ['module', 'main'],
    logLevel: devMode ? 'info' : 'warning',
    plugins: [
      esbuildDecorators(),
      copy({
        assets: [
          {
            from: ['src/config/**/*'],
            to: ['src/config']
          },
          {
            from: ['src/templates/**/*.ejs'],
            to: ['src/templates'],
            ignore: devMode ? ['**/*'] : []
          }
        ]
      }),
    ],
    external: [
      'http',
      'https',
      'crypto',
      'fs',
      'os',
      'path',
      'stream',
      'tty',
      'util',
      'zlib',
      'dns',
      'net',
      'tls',
      'assert',
      'timers',
      'module',
      'domain',
      'async_hooks',
      'inspector',
      'child_process',
      'node:zlib',
      'node:stream',
      'node:util',
      'node:dns',
      'console',
      'constants',
      // Map any other node: prefixed modules
      'zlib',
      'stream',
      'util',
      'dns',
      'bcrypt',
      'utf-8-validate',
      'dtrace-provider',
      'bufferutil',
      '@aws-sdk/*',
      '!@aws-sdk/client-bedrock-runtime',
      'aws-sdk',
      'mock-aws-s3',
      'nock',
      '@types/jest',
      'babel-plugin-transform-typescript-metadata',
      'fork-ts-checker-webpack-plugin',
      'jest',
      'nodemon',
      'serverless',
      'serverless-dynamodb-client',
      'serverless-dynamodb-local',
      'serverless-offline',
      'serverless-offline-dynamodb-stream',
      'serverless-plugin-offline-dynamodb-stream',
      'serverless-webpack',
      'ts-node',
      'typescript',
      'ts-loader',
      'tsconfig-paths',
      'tsconfig-paths-webpack-plugin',
      'webpack-cli',
      'webpack',
      'webpack-node-externals',
      'passport-token-google',
      'moment-range'
    ],
    define: {
      'global': 'global',
      'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
      'Reflect.metadata': 'Reflect.metadata'
    },
    alias: {
      '@utils': path.resolve('src/@utils'),
      '@modules': path.resolve('src/modules'),
      '@api': path.resolve('src/modules/api'),
      '@services': path.resolve('src/modules/services'),
      '@data': path.resolve('src/modules/data'),
      '@graphql-errors': path.resolve('src/@graphql-errors'),
      '@lambda-websocket-server': path.resolve('src/@lambda-websocket-server')
    }
  }
}
@dotansimha
Copy link
Collaborator

What version of esbuild are you using?
I think the latest esbuild already supports TS decorators (since TS >=5 supports it as built-in). Also, why do you use Babel AND esbuild? Do you have a specific limitation here? How does your tsconfig.json looks like?

Related: evanw/esbuild#104

@fridaystreet
Copy link
Author

Thanks for getting back, sorry was about to post up and say we managed to get it sorted. Not entirely sure how, but yes I think there was some legacy stuff getting in the way and we were trying to build out to esm and run in lambda which I think it wasn't happy about. We did still need to use the esbuil tsc plugin to get it to pickup the dependancy injection though.

So the resulting working config if it's of use to anyone is

tsconfig

{
  "compilerOptions": {
    "experimentalDecorators": true,
    "module": "esnext",
    "target": "esnext",
    "lib": [
      "dom",
      "esnext",
      "esnext.asynciterable"
    ],
    "noImplicitAny": false,
    "allowSyntheticDefaultImports": true,
    "ignoreDeprecations": "5.0",
    "moduleResolution": "node",
    "removeComments": true,
    "emitDecoratorMetadata": true,
    "sourceMap": true,
    "inlineSources": true,
    "importHelpers": true,
    "esModuleInterop": true,
    "declaration": true,
    "sourceRoot": "/",
    "outDir": "./dist",
    "rootDir": "./src",
    "baseUrl": "./"
  },
  "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.js", "src/**/*.mjs", "src/**/*.ejs", "src/**/*.graphql"],
  "exclude": ["node_modules"]
}

esbuild.config.js

export default async (serverless) => {

  const devMode = process.env.NODE_ENV === 'development' || !process.env.NODE_ENV

  return {
    color: true,
    metafile: true,
    logLevel: 'info',
    outdir: serverless ? undefined : 'dist',
    outExtension: { '.js': '.js' },
    entryPoints: ['src/index.ts'],
    bundle: true,
    minify: !devMode,
    sourcemap: devMode,
    sourcesContent: devMode,
    format: 'cjs', //needs to be cjs for lambda, but local dev environment can stay as esm/module
    target: 'node20',
    platform: 'node',
    loader: {
      '.graphql': 'text',
      '.gql': 'text',
      '.html': 'text'
    },
    resolveExtensions: ['.ts', '.js', '.mjs', '.cjs', '.graphql'],
    external: [
      '@aws-sdk/*',
      'dtrace-provider',
      'reflect-metadata',
      'graphql*',
      '@escape.tech/*',
      '@envelop/*'
    ],
    plugins: [
      esbuildPluginTsc({ force: true }),
      ...copyPlugin
    ],
    define: {
      'global': 'global',
      'Reflect.metadata': 'Reflect.metadata'
    }
  }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants