serverless / serverless

⚡ Serverless Framework – Effortlessly build apps that auto-scale, incur zero costs when idle, and require minimal maintenance using AWS Lambda and other managed cloud services.
https://serverless.com
MIT License
46.67k stars 5.74k forks source link

Dynamic require of \"<some package>\" is not supported Error when using "type":"module" in a project #13033

Closed Yan-Gurevich-MC14 closed 2 weeks ago

Yan-Gurevich-MC14 commented 1 month ago

Issue description

When i set my project to ESM with "type":"module", lambdas that contain certain packages fail. In my case, it is a lambda that accesses the database via TypeORM. logs in context. When i remove the "type":"module flag it works, but that causes other issues in the project so I ideally would like to continue working with ESM.

The specific issue seems to arise from typeorm using dotenv internally.

Context

serverless_summary.txt

Deployment and invocation:

yangurevich@Yans-MacBook-Pro grix-api % pnpm sls:deploy             

> grix-api@1.0.0 sls:deploy /Users/yangurevich/Desktop/github/yan-gurevich-mc14/mc14labs/grix-api
> serverless deploy --stage dev --verbose

Deploying "v2-grix-api" to stage "dev" (us-east-1)
Uploading CloudFormation file to S3
Uploading State file to S3
Uploading service v2-grix-api-postExample.zip file to S3 (7.58 kB)
Uploading service v2-grix-api-getAssetPrice.zip file to S3 (7.18 kB)
Uploading service v2-grix-api-getOptionPriceHistory.zip file to S3 (1.95 MB)
// removed function ids here
✔ Pruning of functions complete
Removing old service artifacts from S3
[serverless-api-gateway-caching] Updating API Gateway cache settings (1 of 1).
[serverless-api-gateway-caching] Done updating API Gateway cache settings.
✔ Service deployed to stack v2-grix-api-dev (56s)
endpoints:
  POST - https://hk4krurmu7.execute-api.us-east-1.amazonaws.com/dev/example/{path_param}/hi
  GET - https://hk4krurmu7.execute-api.us-east-1.amazonaws.com/dev/asset-price
  GET - https://hk4krurmu7.execute-api.us-east-1.amazonaws.com/dev/options/price-history
functions:
  postExample: v2-grix-api-dev-postExample (7.6 kB)
  getAssetPrice: v2-grix-api-dev-getAssetPrice (7.2 kB)
  getOptionPriceHistory: v2-grix-api-dev-getOptionPriceHistory (2 MB)
Stack Outputs:
// removed urls here
yangurevich@Yans-MacBook-Pro grix-api % sls invoke -f getOptionPriceHistory --path src/lambdas/getOptionPriceHistory/test-event.json

{
    "errorType": "Error",
    "errorMessage": "Dynamic require of \"fs\" is not supported",
    "trace": [
        "Error: Dynamic require of \"fs\" is not supported",
        "    at file:///var/task/src/lambdas/getOptionPriceHistory/handler.js:11:9",
        "    at node_modules/.pnpm/dotenv@16.4.7/node_modules/dotenv/lib/main.js (/node_modules/.pnpm/dotenv@16.4.7/node_modules/dotenv/lib/main.js:1:12)",
        "    at __require2 (file:///var/task/src/lambdas/getOptionPriceHistory/handler.js:17:50)",
        "    at node_modules/.pnpm/typeorm@0.3.21_pg@8.14.0_reflect-metadata@0.2.2_ts-node@10.9.2_@types+node@22.13.10_typescript@5.8.2_/node_modules/typeorm/platform/PlatformTools.js (/node_modules/.pnpm/typeorm@0.3.21_pg@8.14.0_reflect-metadata@0.2.2_ts-node@10.9.2_@types+node@22.13.10_typescript@5.8.2_/src/platform/PlatformTools.ts:2:1)",
        "    at __require2 (file:///var/task/src/lambdas/getOptionPriceHistory/handler.js:17:50)",
        "    at ConnectionManager (/node_modules/.pnpm/typeorm@0.3.21_pg@8.14.0_reflect-metadata@0.2.2_ts-node@10.9.2_@types+node@22.13.10_typescript@5.8.2_/src/globals.ts:2:1)",
        "    at __require2 (file:///var/task/src/lambdas/getOptionPriceHistory/handler.js:17:50)",
        "    at EntitySchemaOptions (/node_modules/.pnpm/typeorm@0.3.21_pg@8.14.0_reflect-metadata@0.2.2_ts-node@10.9.2_@types+node@22.13.10_typescript@5.8.2_/src/index.ts:9:1)",
        "    at __require2 (file:///var/task/src/lambdas/getOptionPriceHistory/handler.js:17:50)",
        "    at <anonymous> (/node_modules/.pnpm/typeorm@0.3.21_pg@8.14.0_reflect-metadata@0.2.2_ts-node@10.9.2_@types+node@22.13.10_typescript@5.8.2_/node_modules/typeorm/index.mjs:1:21)"
    ]
}

✖ ServerlessError3: Invoked function failed
    at AwsInvoke.log (file:///Users/yangurevich/.serverless/releases/4.8.0/package/dist/sf-core.js:1245:480)
    at invoke:invoke (file:///Users/yangurevich/.serverless/releases/4.8.0/package/dist/sf-core.js:1244:481)
    at process.processTicksAndRejections (node:internal/process/task_queues:105:5)
    at async PluginManager.runHooks (file:///Users/yangurevich/.serverless/releases/4.8.0/package/dist/sf-core.js:1433:9562)
    at async PluginManager.invoke (file:///Users/yangurevich/.serverless/releases/4.8.0/package/dist/sf-core.js:1433:10333)
    at async PluginManager.run (file:///Users/yangurevich/.serverless/releases/4.8.0/package/dist/sf-core.js:1433:11068)
    at async Serverless.run (file:///Users/yangurevich/.serverless/releases/4.8.0/package/dist/sf-core.js:1440:10575)
    at async runFramework (file:///Users/yangurevich/.serverless/releases/4.8.0/package/dist/sf-core.js:1467:1776)
    at async TraditionalRunner.run (file:///Users/yangurevich/.serverless/releases/4.8.0/package/dist/sf-core.js:1463:28364)
    at async route (file:///Users/yangurevich/.serverless/releases/4.8.0/package/dist/sf-core.js:1509:2779)
    at async Object.run (file:///Users/yangurevich/.serverless/releases/4.8.0/package/dist/sf-core.js:1510:3668)
    at async run2 (file:///Users/yangurevich/.serverless/releases/4.8.0/package/dist/sf-core.js:1510:4821)

For help, try the following:
  • Run the command again with the "--debug" option
  • Run "serverless support"
  • Review the docs: https://www.serverless.com/framework/docs/

yangurevich@Yans-MacBook-Pro grix-api % 
henrist commented 1 month ago

This is due to some of your dependencies being CommonJS and tries to import another file/dependency using require. esbuild does not transform require into ES imports, and it does not provide require for compatibility. Full details in https://github.com/evanw/esbuild/issues/1921

The workaround is to provide this yourself. Ensure your serverless.yml file contains something like:

build:
  esbuild:
    banner:
      # Compatibility towards CommonJS dependencies that is not rewritten by esbuild.
      js: |
        import { createRequire } from "node:module";
        globalThis.require = createRequire(import.meta.url);

You can also define problematic dependencies as external so they will not be bundled.

czubocha commented 2 weeks ago

Thanks for the clear explanation!

Closing this as it's not an issue with the Serverless Framework itself, but with using CommonJS dependencies in ESM projects. The workaround using createRequire in serverless.yml works well in this case. Feel free to reopen if anything else comes up.