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

esbuild (and TypeScript) Beta Support Feedback #3700

Closed
mildaniel opened this issue Mar 1, 2022 · 56 comments
Closed

esbuild (and TypeScript) Beta Support Feedback #3700

mildaniel opened this issue Mar 1, 2022 · 56 comments

Comments

@mildaniel
Copy link
Contributor

esbuild Support Beta

Recently, we added support for building Node.js and TypeScript lambda functions with esbuild. This allows for bundling and minification of Node.js functions and eases the process of writing TypeScript-based lambdas.

We now want to hear your feedback on the experience.

What feedback are we looking for?

  1. How is the new TypeScript development experience? Is there any way that we can make it better for building and testing TypeScript?
  2. How is the general user experience of configuring and using esbuild?
@collindutter
Copy link

This is a very exciting feature, great work!

Can we use the full esbuild API under BuildProperties? I'm trying to provide aws-sdk as an external, but it doesn't seem to have any effect:

    Metadata:
      BuildMethod: esbuild
      BuildProperties:
        External: 
          - 'aws-sdk'

Error after sam build:

✘ [ERROR] Could not resolve "aws-sdk"

    app.ts:11:20:
      11 │ const AWS = require('aws-sdk');
         ╵                     ~~~~~~~~~

  You can mark the path "aws-sdk" as external to exclude it from the bundle, which will remove this error. You can also surround this "require" call with a try/catch block to handle this failure at run-time instead of bundle-time.

@mildaniel
Copy link
Contributor Author

Can we use the full esbuild API under BuildProperties?

Unfortunately we don't have support for the entire esbuild API, but having an option to set the aws-sdk as external definitely makes sense.

Thanks for the feedback!

@LuizPelegrini
Copy link

Hi @mildaniel the feature certainly brings some handful build shortcuts when developing my lambdas in Typescript

I also have the same question as @collindutter's. I would not like to have my dependencies bundled with my lambda function, I would like to use AWS Layers instead, how can I achieve this?

@iRoachie
Copy link
Contributor

iRoachie commented Mar 6, 2022

Hey folks, just tried this out. Couple of pain points I found:

  • No way to specify esbuild for all functions/layers Support BuildProperties/BuildMethod config for multiple functions #3713
  • esbuild is required in the dependencies for each function which seems a bit noisy. Most js projects will have a top-level pacakge.json. Would make sense to have it as a dev dependency there. Same thing for eslint, prettier, etc
  • I can't seem to find a way to make this work for local layers

@mildaniel
Copy link
Contributor Author

Thanks everyone, this is all great feedback.

Just wanted to quickly address some of it:

  • We agree that setting your build args for each individual buildable resource can be tedious. We're currently looking into ways of making the configuration UX better and are considering various improvements.
  • Layers support is also something we're working on and unfortunately is not currently supported. This one requires us to address some technical challenges surrounding the way that the esbuild external API rewrites import paths. We understand this is an important feature and are working on providing a suitable solution.

@mildaniel
Copy link
Contributor Author

@iRoachie

esbuild is required in the dependencies for each function which seems a bit noisy. Most js projects will have a top-level pacakge.json. Would make sense to have it as a dev dependency there. Same thing for eslint, prettier, etc

Could you expand on this a little bit? The way it currently works is by installing the dependencies in the package.json at the CodeURI level. If esbuild is there as a dev dependency, Lambda Builders should find and use the corresponding executable.

@iRoachie
Copy link
Contributor

iRoachie commented Mar 7, 2022

@mildaniel Yes what you said is correct but that would mean if I have 10 functions, I have to install esbuild as a dependency for each one.

This is kinda backwards from how a normal JS project would be set up. Usually, there would be a top-level package.json that includes all your dev dependencies like esbuild, prettier, eslint etc.

For example, this is how esbuild works in CDK atm - https://docs.aws.amazon.com/cdk/api/v1/docs/aws-lambda-nodejs-readme.html#local-bundling. One install of esbuild at the root package.json that is used for all functions.

@nocquidant
Copy link

As a user, this is also one of my concerns...

For me, one package.json and one node_modules folder per function was needed to avoid zipping all the dependencies and deploying the full zip with every function, even the one with no dependencies.

But it seems to me that it's not really necessary anymore because bundling with esbuild involves tree shaking (size is no longer an issue).

That said, changing a "shared" dependency will impact all functions that were using that dependency and cause a new redeployment.

@chris-armstrong
Copy link

  1. The new esbuild functionality is great, but because sam build isn't integrated with sam local start-api or sam local invoke, I need to either run 'sam build' before I use these. It would be great to have it integrated with esbuild's watch mode, which is really fast for rebuilding assets (I know this might be difficult given the way esbuild has been integrated, running a separate build for each file instead of one integrated build).
  2. It's very easy, but as mentioned, redeclaring the Metadata section is tedious. Also, by switching the CodeUri to point to the typescript file, I can no longer run a separate esbuild in watch mode pointing to a dist folder - I'm forced to generate the JS files in the same directory, which then interferes with my tests (which I run with jest).

@mildaniel
Copy link
Contributor Author

@nocquidant

That said, changing a "shared" dependency will impact all functions that were using that dependency and cause a new redeployment.

Would being able to mark that shared dependency as external and including it in a layer resolve this issue?

@nocquidant
Copy link

@mildaniel I think so. But this behavior is not an issue for me, I just wanted to mention it. Personally, I try to use layers only for heavy dependencies or system dependencies, but not as a package manager.

@collindutter
Copy link

Does sam esbuild use the tsconfig for a project? I'm trying to set the baseDir to avoid using relative paths, but sam esbuild doesn't seem to be picking it up. When I run esbuild manually, it works fine.

My problem is very similar to this issue: evanw/esbuild#2044

@fbn-roussel
Copy link

With the recent support of ESM in Lambda, it could be nice to support the format option from esbuild to allow esm instead of forcing the use of cjs.

https://esbuild.github.io/api/#format-esm

@chris-armstrong
Copy link

Another thing - with sam sync running on a large project, it is incredibly slow (minutes) to get to a state where I can start modifying functions (and difficult to recognise when, because when you think it is ready its just spinning for a minute or two)

@Cephyric-gh
Copy link

Support for esbuild plugins would be very helpful as currently this will only really work for pretty basic lambda functions. Being able to specify plugins for esbuild to use will allow compilation of certain typescript features that Evan has said that esbuild will never support, like decorators.

As an example (pulled right from the issue linked above) - any project that uses TypeORM to access a database (or most of their alternatives, e.g. Sequelize in my use-case) cannot currently use native compilation and must stick to any current build process that exists. I'd love to switch to this as I have been looking to replace my webpack build process with esbuild for quite a while, since webpack is notoriously slow to build

@jelder
Copy link

jelder commented Mar 15, 2022

Adding to @collindutter, support for esbuild --external has broad application beyond just omitting aws-sdk. In my particular case I need to use a Node module that is not compatible with esbuild (Knex). It would be ideal if the schema allowed for a list of exclusions.

@chris-armstrong
Copy link

Adding to @collindutter, support for esbuild --external has broad application beyond just omitting aws-sdk. In my particular case I need to use a Node module that is not compatible with esbuild (Knex). It would be ideal if the schema allowed for a list of exclusions.

I’ve started submitting patches for —external and others - what esbuild options do you think are also useful?

@maryborgwat
Copy link

Am I reading correctly (from above) that you cannot use typeORM with SAM (build) ? I get an error saying "aws_lambda_builders.actions.ActionFailedError: Esbuild Failed: ✘ [ERROR] Could not resolve "pg-native". exclude pg-native to resolve the issue. It is unclear to me where you would exclude it (in the SAM Build process) and if you exclude it would that resolve the problem?

@Cephyric-gh
Copy link

Am I reading correctly (from above) that you cannot use typeORM with SAM (build) ? I get an error saying "aws_lambda_builders.actions.ActionFailedError: Esbuild Failed: ✘ [ERROR] Could not resolve "pg-native". exclude pg-native to resolve the issue. It is unclear to me where you would exclude it (in the SAM Build process) and if you exclude it would that resolve the problem?

Until SAM supports both the --external flag and the ability to specify esbuild plugins/config for them it can't build packages like TypeORM.
You need --external as that is where you'd specify pg-native as excluded from the build, and you need plugins to be able to compile the TypeORM decorators

@zdorow
Copy link

zdorow commented Apr 28, 2022

This is a great feature and makes building for typescript super easy. Excluding external would solve our main issues with using it as well. Putting everything into one file makes you responsible for all the code in your dependencies, deprecation warnings and all so it can make things problematic when you have to use a dependency that cannot be updated as they get logged in the lambda and trigger alarms.

@mildaniel
Copy link
Contributor Author

The external flag option is definitely an important feature that we plan on adding. We're also looking into improvements of esbuild with accelerate to make that a smoother experience.

Thank you for the feedback!

@gnowakpoloniex
Copy link

Having watch mode would be incredibly helpful

@mildaniel
Copy link
Contributor Author

Having watch mode would be incredibly helpful

This is already part of accelerate which is usable with esbuild! Is there a reason for not using accelerate for iterating and testing?

@praneetap
Copy link
Contributor

praneetap commented May 3, 2022

Another thing - with sam sync running on a large project, it is incredibly slow (minutes) to get to a state where I can start modifying functions (and difficult to recognise when, because when you think it is ready its just spinning for a minute or two)

Hi @chris-armstrong! Thanks for all the great feedback. We were unable to reproduce what you talk about here ^ and I was wonderng if we can get on a call to get more specific repro steps? We would also love to get feedback from you as we are working towards the full GA launch of this feature. Please DM me here, and we can set something up.

@yskkin
Copy link

yskkin commented May 11, 2022

Is deduped build not working when setting Metadata?
Migrating to esbuild disables deduped build for me.

@erashdan
Copy link

I have an issue to include custom layer

Running NodejsNpmBuilder:CopyNpmrcAndLockfile
Running NodejsNpmBuilder:CopySource
Running NodejsNpmBuilder:NpmInstall
Running NodejsNpmBuilder:CleanUpNpmrc
Running NodejsNpmBuilder:LockfileCleanUp
Running NodejsNpmEsbuildBuilder:EsbuildBundle
Error: NodejsNpmEsbuildBuilder:EsbuildBundle - Esbuild Failed: ✘ [ERROR] Could not resolve "/opt/nodejs/database"

    latest-posts.ts:4:24:
      4 │ const sayName = require('/opt/nodejs/database')
        ╵                         ~~~~~~~~~~~~~~~~~~~~~~

@nubpro
Copy link

nubpro commented May 28, 2022

Documentation lacking, in my opinion. I can't seem to locate in-depth descriptions of any of the options for the template.yaml file.

Also, I have been experiencing this strange issue:

"errorMessage": "Error: Cannot find module 'app'\nRequire stack:\n- /var/runtime/UserFunction.js\n- /var/runtime/index.js"

coupled within a Runtime.ImportModuleError.

Personally, I don't think the beta is anywhere close to where it needs to be. I think having TypeScript options bundled into Sam CLI as templates is a bad idea while everything is still being ironed out.

I get this error alot Runtime.ImportModuleError.
I simply delete .aws-sam from the root folder and re-run the sync command again.
Painful, but it does the job.

SAM CLI Team, please thoroughly test this functionality and apply the tool on other aws projects please. Dogfooding, you need it. This tool is great but it's reliability is still something less to be desired.

@mildaniel
Copy link
Contributor Author

Thanks everyone for the continued feedback, we really appreciate it. We understand the dependency bug is a real pain point for this feature and are looking into it.

@erashdan this issue seems to be that esbuild is searching for the dependency on your machine but can't find it. Try setting those dependencies as External and trying again.

@ptejada
Copy link

ptejada commented May 30, 2022

Was the support for the External option added already?

@mildaniel
Copy link
Contributor Author

Yes, support for External and Loader were added in 1.49.0.

@lightpriest
Copy link

The last esbuild features are awesome and really help us reduce some of the in-house tooling we wrote to support our projects. A couple of issues remain, and they might have an answer in the the current form but I'd appreciate any help here.

  1. How are we expected to deal with dynamic references? For example, sequelize depends on mysql2 at runtime, but dynamically loaded.
  2. Other static files which are not directly referenced (for example, config/ for node-config).

In standard backend project, you can have a giant node_modules directory which includes the "External" dependencies or some other static files. Is there a way you recommend doing this now?

@terrywarwar
Copy link

@praneetap I'm also experiencing very slow sam sync of many minutes for a large project.

@praneetap
Copy link
Contributor

@praneetap I'm also experiencing very slow sam sync of many minutes for a large project.

Hey @terrywarwar ! Thanks for reporting this. We are aware of the issue and working on a fix.

@jacobduba
Copy link

jacobduba commented Jul 5, 2022

Here's some feedback: getting unexpected configuration of sourcemaps in the build folder. Debugging with Typescript is not working because the source maps seem to be incorrectly configured. This is the file app.js.map from the build of the hello-world example.

{
  "version": 3,
  "sources": ["../../../../../../../tmp/tmptvm1fyck/app.ts"],
  "sourcesContent": ["import { APIGatewayProxyEvent, APIGatewayProxyResult } from 'aws-lambda';\n\n/**\n *\n * Event doc: https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html#api-gateway-simple-proxy-for-lambda-input-format\n * @param {Object} event - API Gateway Lambda Proxy Input Format\n *\n * Return doc: https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html\n * @returns {Object} object - API Gateway Lambda Proxy Output Format\n *\n */\n\nexport const lambdaHandler = async (event: APIGatewayProxyEvent): Promise<APIGatewayProxyResult> => {\n    let response: APIGatewayProxyResult;\n    try {\n        response = {\n            statusCode: 200,\n            body: JSON.stringify({\n                message: 'hello world',\n            }),\n        };\n    } catch (err) {\n        console.log(err);\n        response = {\n            statusCode: 500,\n            body: JSON.stringify({\n                message: 'some error happened',\n            }),\n        };\n    }\n\n    return response;\n};\n"],
  "mappings": "yaAAA,wDAYO,GAAM,GAAgB,KAAO,IAAgE,CAChG,GAAI,GACJ,GAAI,CACA,EAAW,CACP,WAAY,IACZ,KAAM,KAAK,UAAU,CACjB,QAAS,aACb,CAAC,CACL,CACJ,OAAS,EAAP,CACE,QAAQ,IAAI,CAAG,EACf,EAAW,CACP,WAAY,IACZ,KAAM,KAAK,UAAU,CACjB,QAAS,qBACb,CAAC,CACL,CACJ,CAEA,MAAO,EACX",
  "names": []
}

As you can see the sources point at /tmp and not the source code. This causes line by line debugging to break.

You can reproduce this by using the hello-world example with sam init, and then attaching to the node process with this launch.json.

{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Attach to SAM CLI",
      "type": "node",
      "request": "attach",
      "address": "localhost",
      "port": 9999,
      "localRoot": "${workspaceRoot}/.aws-sam/build/HelloWorldFunction",
      "remoteRoot": "/var/task",
      "protocol": "inspector",
      "stopOnEntry": false,
    }
  ]
}

@chris-fryer
Copy link

Unable to set breakpoints in TypeScript code via VSCode

I'm also experiencing the same problem as @jacobduba above in being unable to set debug breakpoints within the TypeScript code in the Hello World sample produced by sam init. In VSCode I see the error/warning:

"Some of your breakpoints could not be set. If you're having an issue, you can troubleshoot you launch configuration"

Having done some troubleshooting I can see that when running sam build the app.js and app.js.map get produced in the .aws-sam/build/HelloWorldFunction/ directory, but like @jacobduba in the app.js.map file I see the sources path set to a relative path in a temp folder:

"sources": ["../../../../../../Users/[**removed**]/AppData/Local/Temp/tmpfruu62fk/app.ts"],

Browsing to that path shows the temp folder no longer exists.

I'm running the latest Windows 10, I've tried the latest sam version (1.53.0) and the latest sam nightly (1.53.0.dev202208090902) but have the same issue with both.

The troubleshooting in VSCode suggests that esbuild is producing the app.js.map with the wrong relative path. I've been unable to find the options we can pass into esbuild. Are there any esbuild options I can specify to adjust the relative path to allow me to set TypeScript breakpoints in VSCode? (e.g. in the template.yaml BuildProperties section or via command line for sam build?)

@jacobduba
Copy link

@chris-fryer I submitted a PR that fixes the issue.

@JamieClayton7
Copy link

JamieClayton7 commented Aug 17, 2022

One issue I have just encountered is again tied to the inability to access the entire esbuild API I think. I'm attempting to use uglifyjs and (as intended) esbuild does not resolve "require.resolve()" calls without a plugin to prompt it do so. My Lambda is now throwing:

Runtime.ImportModuleError: Error: Cannot find module '../lib/utils.js'"

from the following uglifyjs code (post esbuild bundling):

var require_node2 = __commonJS({
  "node_modules/uglify-js/tools/node.js"(exports) {
    var fs = require("fs");
    exports.FILES = [
      require.resolve("../lib/utils.js"),
      require.resolve("../lib/ast.js"),
      require.resolve("../lib/transform.js"),
      require.resolve("../lib/parse.js"),
      require.resolve("../lib/scope.js"),
      require.resolve("../lib/compress.js"),
      require.resolve("../lib/output.js"),
      require.resolve("../lib/sourcemap.js"),
      require.resolve("../lib/mozilla-ast.js"),
      require.resolve("../lib/propmangle.js"),
      require.resolve("../lib/minify.js"),
      require.resolve("./exports.js")
    ];```

@samesfahani-tuplehealth
Copy link

samesfahani-tuplehealth commented Aug 30, 2022

I'm finding it very hard to configure esbuild as I need it. As others have mentioned, the lack of plugin support is very limiting due to the decoratorMetadata problem that is prevalent when you use esbuild with NestJS, typeorm, etc.

Is there any way I can just tell sam build to run and use a custom build script instead where I call out to esbuild.build() myself directly? Any workarounds would be appreciated.

@mildaniel
Copy link
Contributor Author

Hey @samesfahani-tuplehealth. I understand where you're coming from with wanting to use the plugins API. There currently isn't a way to use it today, but I'll try to come up with a solution for this.

Thank you for the continued feedback.

@samesfahani-tuplehealth
Copy link

samesfahani-tuplehealth commented Aug 30, 2022

Thanks for the quick response @mildaniel.

As a workaround, in case this helps anyone, I just figured I could write my own script build.ts that will call out to esbuild.build() directly and output to an intermediary folder dist/. I then set my CodeUri in my template.yml to dist/ and ran sam build without the new esbuild BuildMethod.

This workaround of course is completely side-stepping the feature at hand here, but it does 1) build and bundle your Javascript as you need it with plugins, exclusions, etc, 2) builds your artifact as sam expects (with proper template.yaml and build.toml files).

Quick dirty example:

build.ts

import { esbuildDecorators } from '@anatine/esbuild-decorators';
import { build } from 'esbuild';

build({
  bundle: true,
  entryPoints: ['src/app.ts'],
  outdir: 'dist',
  external: [
    'pg-native',
  ],
  format: 'cjs',
  platform: 'node',
  plugins: [
    esbuildDecorators({ tsx: false, tsconfig: '../../tsconfig.json' }), // this feature is missing from current set of features!
  ],
  sourcemap: true,
});

Again the only caveat is you set your CodeUri: dist/.

@mildaniel In case this is useful, the serverless framework supports esbuild plugins through the following API: https://www.serverless.com/plugins/serverless-esbuild#esbuild-plugins

Even in our codebase there are nuances with certain libraries needing static files copied over and as mentioned the decorator issue. While I do see the appeal in providing an abstraction over esbuild by exposing only the minimum required flags, inevitably someone is going to need some flag exposed or want some specific nuance. I fear that by the end of it, all of esbuild.BuildOptions will be exposed in a clunky yaml format. Perhaps what might be best is to just provide the basic minimum set of fields as they currently are, but support a backchannel format to run a build script for advanced cases where users need more granular control over their build. Just food for thought, of course!

@mildaniel
Copy link
Contributor Author

Thanks for providing a workaround @samesfahani-tuplehealth.

Perhaps what might be best is to just provide the basic minimum set of fields as they currently are, but support a backchannel format to run a build script for advanced cases where users need more granular control over their build.

This is my thinking too. I will need to put some more thought into how exactly to support plugins through the SAM-CLI, bu ultimately would like to have support for something like this as well.

@tunesmith
Copy link

I'm having trouble figuring out how to attach the IntelliJ debugger and breakpoints when using typescript. Using sam local start-api, I can invoke api requests using curl/Insomnia/whatever, but currently I have to sam build whenever I make changes (rather than have it auto-reload) since it requires reading from .aws-sam. And I'm needing to use console.log for debugging since I can't attach the debugger.

As for the debugger, so far I've tried:

  1. using tsc to compile to a build folder and pointing template.yml to that build folder, but the problem there is the /opt import path which lambda requires for layers paths. (I otherwise have this working using the tsconfig.json paths config.)

  2. Using .aws-sam and turning on Sourcemap: true in Metadata:BuildProperties, but I'm not sure how to link it to my actual typescript source file breakpoints when developing. I've tried --debug-port. (Tangent: If this is on the right path, can we get "intrinsic functions" support in the Metadata section? I'd like Sourcemap to be an env-specific parameter.)

@lucashfreitas
Copy link

lucashfreitas commented Oct 4, 2022

  • The sam debugger doesn't seems to work with typescript. The debugger bundles typescript using tsc but the breakpoints are not triggered. (Maybe some configuration for source mapping?): https://docs.aws.amazon.com/toolkit-for-vscode/latest/userguide/serverless-apps-run-debug-config-ref.html
  • +1 on being able to compile typescript on the flight when invoking sam local invoke - so it means we don't need to run sam build every time before sam invoke: This is not a major issue as there is ways of watching changes using nodemon to run builds or even having npm run build && npm run invoke.)
  • watch mode: Currently we need to use nodemon or something similar to keep rebuilding the functions in the background whenever we do code changes, but if the invoke is able to compile typescript on the flight it wouldn't be required anymore I guess for invoke? But if we are using start api (continuously running) would be very cool to have a reload feature when file changes.

@tunesmith yeah I also had a hard time getting the debug function to work as we have very little content/tutorials on that, but I managed to get that working - ofc there is a lot that can be done to improve the developer experience, but basically, you should be able to get the debug working on typescript by following this tutorial:

  1. Add this launch.json file (You need to modify some files as I highlight)
{
    "configurations": [
        {
            "type": "node",
            "request": "attach",
            "name": "Attach to SAM Local Invoke",
            "address": "localhost",
            "port": 8066, //the port used when you trigger the function in debug mode
            //Modify this to match the .aws-sam output from your function
            "localRoot": "${workspaceRoot}/.aws-sam/build/DemoFunction",
            "remoteRoot": "/var/task",
            "skipFiles": [
                "<node_internals>/**",
                "/var/runtime/**/*.js",
                "/var/runtime/node_modules/**",
            ],
            "protocol": "inspector",
            "stopOnEntry": false,      
            //Modify this to match the .aws-sam output from your function
            "outFiles": ["${workspaceRoot}/.aws-sam/build/DemoFunction/**/*.js"]
        },

  
    ]
}
  1. Run the lambda into debug mode:

sam local invoke DemoFunction --env-vars env.json -d 8066 -e event.local.json : Note the DEBUG port must match the port defined in the launch.json

  1. Once the debug start you need to attach the debugger to get the function running on debug mode. Then you should be able to debug it.

Note: For every change you need to "rebuild" your lambda function, so you can use nodemon to watch file changes and run sam build in paralel.

Please let me know if you need any extra help.

@sebelga
Copy link

sebelga commented Oct 18, 2022

I am testing esbuild with typescript and I get a strange behaviour when using layers.
I have the node_modules layer referenced in my function. When I want to use a dependency, import does not work but require does...

import uuid from 'uuid'; // This will be undefined and thus does not work

const uuid = require('uuid'); // This will work

The problem is that using require returns any which defeats the purpose of using Typescript. Any idea why this is happening and if it is expected to use require?

[EDIT]: Answering my own question: I needed to change my import to make it work

import * as uuid from 'uuid';

@sebelga
Copy link

sebelga commented Oct 26, 2022

I have been now debugging the following error for a while ...

2022-10-26T08:44:10.921Z	undefined	ERROR	Uncaught Exception 	{"errorType":"Runtime.ImportModuleError","errorMessage":"Error: Cannot find module 'app'\nRequire stack:\n- /var/runtime/index.mjs","stack":["Runtime.ImportModuleError: Error: Cannot find module 'app'","Require stack:","- /var/runtime/index.mjs","    at _loadUserApp (file:///var/runtime/index.mjs:1000:17)","    at async Object.UserFunction.js.module.exports.load (file:///var/runtime/index.mjs:1035:21)","    at async start (file:///var/runtime/index.mjs:1200:23)","    at async file:///var/runtime/index.mjs:1206:1"]}
26 Oct 2022 08:44:10,933 [ERROR] (rapid) Init failed error=Runtime exited with error: exit status 129 InvokeID=
2022-10-26T08:44:10.981Z	undefined	ERROR	Uncaught Exception 	{"errorType":"Runtime.ImportModuleError","errorMessage":"Error: Cannot find module 'app'\nRequire stack:\n- /var/runtime/index.mjs","stack":["Runtime.ImportModuleError: Error: Cannot find module 'app'","Require stack:","- /var/runtime/index.mjs","    at _loadUserApp (file:///var/runtime/index.mjs:1000:17)","    at async Object.UserFunction.js.module.exports.load (file:///var/runtime/index.mjs:1035:21)","    at async start (file:///var/runtime/index.mjs:1200:23)","    at async file:///var/runtime/index.mjs:1206:1"]}
END RequestId: 790ce6af-fac8-4dd8-9433-f3a7ebee7876
REPORT RequestId: 790ce6af-fac8-4dd8-9433-f3a7ebee7876	Init Duration: 0.14 ms	Duration: 123.99 ms	Billed Duration: 124 ms	Memory Size: 128 MB	Max Memory Used: 128 MB
{"errorType":"Runtime.ImportModuleError","errorMessage":"Error: Cannot find module 'app'\nRequire stack:\n- /var/runtime/index.mjs","trace":["Runtime.ImportModuleError: Error: Cannot find module 'app'","Require stack:","- /var/runtime/index.mjs","    at _loadUserApp (file:///var/runtime/index.mjs:1000:17)","    at async Object.UserFunction.js.module.exports.load (file:///var/runtime/index.mjs:1035:21)","    at async start (file:///var/runtime/index.mjs:1200:23)","    at async file:///var/runtime/index.mjs:1206:1"]}%

I could not find the reason why suddenly it was not finding my module app.. I tried everything... until I finally see at async Object.UserFunction.js.module.exports.load. Not sure what the UserFunction refers to (maybe some old trials) ??

I rename my initial LoadFooFunction in my template.yaml to UserFunction and run

sam local invoke UserFunction

It works!

I changed back the name to LoadFooFunction

sam local invoke LoadFooFunction

It throws the above error... I then changed the name to something completely different TestFunction: it works
Back to LoadFooFunction: it throws

It seems like there is a caching issue somewhere.

@sriram-mv
Copy link
Contributor

This issue will be closed after collecting the separate feedback requests into individual issues. esBuild support is now GA.

@serkan-ozal
Copy link

Hi all,

In Thundra, we are also suffering from the same problem. Currently only workaround I see is that manually editing source map file to point to the workspace path ("../../../hello-world/app.ts") instead of "scratch dir".

Is there any other workaround and/or how we can automate this manual editing as part of sam build?

@mildaniel
Copy link
Contributor Author

@serkan-ozal, there aren't any automated ways of doing that today withing sam build. However, this is an issue we're tracking and are looking to resolve.

@mildaniel
Copy link
Contributor Author

As @sriram-mv mentioned, this feature is now generally available. We appreciate everyone's feedback and have collected it all to plan our next steps for esbuild support! Please open a new issue in our repository for anything that comes up.

@adam-brewer-meshii
Copy link

I don't see how this could be marked as completed since it doesn't work with sam local start-api – surely it would work with all sam commands for it to be considered working?

@dangeReis
Copy link

@sriram-mv The debugging is still not working in typescript as far as I can tell. Where is this issue being tracked?

@rrrokhtar
Copy link

For template.yml:

Replace the Default value with packages names space separated with empty space

Parameters:
  ExternalDependencies:
    Type: String
    Default: "aws-sdk mysql2 better-sqlite3 oracledb mysql tedious pg-query-stream sqlite3"

Resources
  someFunction:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: ....
      Handler: ....
      Role: ....
    Metadata:
      BuildMethod: esbuild
      BuildProperties:
        ....
        External: !Split [" ", !Ref ExternalDependencies]
        ....

@himalayanelixir
Copy link

For template.yml:

Replace the Default value with packages names space separated with empty space

Parameters:
  ExternalDependencies:
    Type: String
    Default: "aws-sdk mysql2 better-sqlite3 oracledb mysql tedious pg-query-stream sqlite3"

Resources
  someFunction:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: ....
      Handler: ....
      Role: ....
    Metadata:
      BuildMethod: esbuild
      BuildProperties:
        ....
        External: !Split [" ", !Ref ExternalDependencies]
        ....

tytyty, this is exactly what i was looking for.

@eydelrivero
Copy link

Thanks for providing a workaround @samesfahani-tuplehealth.

Perhaps what might be best is to just provide the basic minimum set of fields as they currently are, but support a backchannel format to run a build script for advanced cases where users need more granular control over their build.

This is my thinking too. I will need to put some more thought into how exactly to support plugins through the SAM-CLI, bu ultimately would like to have support for something like this as well.

Are esbuild plugins supported today? I'm going through the docs but haven't found any references.

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

No branches or pull requests