Search code examples
node.jsamazon-web-servicesaws-lambdaesbuildsam

SAM with esbuild mjs file failing with Dynamic require of "net" is not supported


I am using a SAM application and the lambda imports many libraries. I have a requirement to use await outside the handler for performance reasons. To support that, I used

    Metadata:
      BuildMethod: esbuild
      BuildProperties:
        Format: esm
        Minify: false
        Target: "es2022"
        OutExtension:
          - .js=.mjs        
        Sourcemap: false
        EntryPoints:
          - handler.ts    

This helps to execute the await outside the handler. Now I am getting below error from lambda and i noticed one of the referenced package internally using require('net')

Dynamic require of \"net\" is not supported

I searched and found a below solution with esbuild but not sure how i can integrate it with the current SAM setup? Could anybody handled this

https://github.com/evanw/esbuild/issues/1921#issuecomment-1491470829

Thanks


Solution

  • When working with AWS SAM and esbuild for Node.js projects, you might encounter issues with .mjs files and dynamic require statements. This problem often arises due to the way esbuild handles module resolution and packaging for AWS Lambda functions.

    One solution is to adjust the MainFields in the BuildProperties of your SAM template. This approach customizes the resolution order for module entry points in dependencies. By prioritizing the module field over main, you can favor ESM (ECMAScript Module) entry points in third-party libraries, which helps address compatibility issues between ESM and certain npm packages. Here's how you can configure it:

    BuildProperties:
      MainFields: module,main
    

    However, this solution might not work if your dependencies don't provide an ESM version. In such cases, you need an alternative approach.

    A workaround, as discussed in this GitHub issue, involves modifying the build configuration to better support ESM syntax and resolve issues related to dynamic require statements. You can apply the following settings in your SAM template:

    Metadata:
      BuildMethod: esbuild
      BuildProperties:
        Format: esm
        Minify: false
        Target: "es2022"
        OutExtension:
          - .js=.mjs        
        Sourcemap: false
        EntryPoints:
          - handler.ts    
        Banner:
          - js=import path from 'path';
            import { fileURLToPath } from 'url';
            import { createRequire as topLevelCreateRequire } from 'module';
            const require = topLevelCreateRequire(import.meta.url);
            const __filename = fileURLToPath(import.meta.url);
            const __dirname = path.dirname(__filename);
    

    It's important to note that the use of the Banner property in the BuildProperties of AWS SAM is currently not officially documented in the AWS SAM documentation. For more details on this workaround, refer to the discussion in this GitHub issue comment on the AWS SAM CLI repository.