```"GET /dist": { function: { bu...
# help
j
Copy code
"GET /dist": {
  function: {            
    bundle: false,
    srcPath: "../../dist/apps/lambda/",
    handler: "index.handler",
  },          
  authorizationType: sst.ApiAuthorizationType.NONE,
}
results in
Copy code
127e794d-009b-4136-b06e-dda7d1f2c97a REQUEST jplacek-sst-my-stack-ApiLambdaGETdist77255DFF-QTX6rp9SQ4te [index.handler] invoked by API GET /dist
X [ERROR] Cannot use "external" without "bundle"

127e794d-009b-4136-b06e-dda7d1f2c97a ERROR build_failure: The function index.handler failed to build
m
Could you share your folder structure?
j
Atm the
dist
dir with lambda is outside of sst project directory, is that the issue?
I am going to change this in a moment anyway, because the watcher doesn't work outside the sst dir and can't be configured.
To clarify further I have a
nx
monorepo:
Copy code
root/
root/apps/sst (sst project)
root/apps/web (angular project)
root/apps/lambda (nestjs project)
root/dist/apps/lambda (builded nestjs project)
Ok, I changed it so the SST project is now on root, so its like this:
Copy code
"GET /dist": {                    
          function: {   
            // ERROR: Cannot use "external" without "bundle"         
            bundle: false,
            srcPath: "dist/apps/lambda/",
            handler: "index.handler",
          },          
          authorizationType: sst.ApiAuthorizationType.NONE,
}
still the same error
f
@Jan Plaček I’m able to reproduce this on my end. Putting in a fix now.
j
@Frank Awesome, thank you. Will watcher pickup the changes when I rebuild the app?
when index.handler gets replaced by a new one...?
f
By watcher you mean
sst start
right?
If
sst.json
is at the root, it should.
j
Yes. Basically I am trying to avoid
esbuild
due to some incompatibilities with
nestjs
. So the idea is to setup watcher on my
nestjs
project use own build process, and then the sst should pickup the changes and reload lambda with new build.
f
even right now, with this
Copy code
"GET /dist": {                    
  function: {   
    bundle: false,
    srcPath: "dist/apps/lambda/",
    handler: "index.handler",
  },          
  authorizationType: sst.ApiAuthorizationType.NONE,
}
When u make a change to
index.handler
and save, do u see
Copy code
Building function index.handler
printed out in the terminal?
j
yes when I modify it directly it does seem to reload the lambda function
not sure if it also works on replacement, will try
yea it does seem to work as well, thank you
f
Sounds good. I will cut a release in ~15min or so w/ the fix
j
Btw I dunno if its bug or misuse, but when I omit the
function
like this: "GET /dist": { bundle: false, srcPath: "dist/apps/lambda/", handler: "index.handler", authorizationType: sst.ApiAuthorizationType.NONE, }
then
authorizationType
seems to be ignored
the other fields are effective
f
Ah yeah, you need the
function
prop in there.
You can either set a route like this:
Copy code
"GET /dist": {                    
  function: {   
    bundle: false,
    srcPath: "dist/apps/lambda/",
    handler: "index.handler",
  },          
  authorizationType: sst.ApiAuthorizationType.NONE,
}
or like this as a shortcut:
Copy code
"GET /dist": {                    
  bundle: false,
  srcPath: "dist/apps/lambda/",
  handler: "index.handler",
}
But if you use the shortcut, u won’t be able to set
authorizationType
@Jan Plaček Just released v0.66.3 with the fix!
t
@Jan Plaček have you tried setting bundle.nodeModules instead of disabling bundling?
j
@thdxr I did not. I am not sure if/how I could utilize it in this case. I need to exclude basically the whole application from
esbuild
not just some dependency (
nestj
)
t
I'm not sure if disabling bundling will solve this for you. This means you'll have to make sure all dependencies are available to the function yourself. We generally recommend avoiding heavy frameworks like nestjs - they aren't super compatible with a serverless approach and you'll likely run into continuing issues
j
It's something we are aware of and discussing in our company. Atm moment I am trying to figure out what the possibilites/limitations are. We have existing codebase written in
nestjs
. It's just a small prototype so rewriting would be fine. The bigger issue is developers that are familiar with it (they also use
angular
which is very similar). I set a goal to make it work if possible for now and then try to move (maybe gradually) away from. I don't want to immediately push us to unknown territory. Also, I really like the way
sst
handles serverless development, but if a problem occurs I want to be able to fallback to previous setup. I've already checked the thread and related issue on github, but thank you. Btw the maturity of the project makes me a bit worried, but I am very pleased and surprised by the level of support here and the overall attitude.
t
that makes sense - if you look in that thread Kujtim got it working without disabling bundling
j
yes it uses a plugin for esbuild which basically runs TS compiler first... its more of workaround then solution...
t
Is that what the plugin is doing?
j
well, that's my understanding I didn't dig too deep
t
I'm not sure that's what the plugin does, there's a few frameworks that need decorator support and I've seen people using it
afaik it adds an extra step to esbuild which compiles the decorator, it'll add some slowness but it won't be the same as running
tsc
Btw
esbuild
seems cool and all, but also quite young and opinionated. Supporting other bundlers somehow would be nice. I know there is an issue opened, just adding my vote 🙂
t
ah interesting
what other bundler are you interested in?
j
webpack/rollup or perhaps a custom script that could delegate to whatever. I did not think much about it so I dunno what kind of problems such integration poses.
t
The reason we're building on esbuild is the other bundlers (outside of swc) are too slow for interactive development (rebuilds)
Esbuild does fall short in some places, getting esm working was a pain but we've mostly been able to get everything to work
j
I totally understand that and I think it was a good call and good default. I do like the fact
sst
is very focused on DX, because other products seems to fall short in this regard. However people are used to some tools, have certain knowledge, (bizzare) existing setups, opinions... for them it's not a question of speed, but whether they can use it or not.
Can't get it working :( For some reason the bundled
nestjs
app throws:
Copy code
Unhandled Promise Rejection 	{"errorType":"Runtime.UnhandledPromiseRejection","errorMessage":"Runtime.HandlerNotFound: C:\\\\talsec-cloud\\\\.sst\\\\artifacts\\\\jplacek-sst-my-stack-Api-Lambda_GET_-dist\\\\dist\\\\apps\\\\lambda\\\\index.handler is undefined or not exported","reason":"Runtime.HandlerNotFound: C:\\\\talsec-cloud\\\\.sst\\\\artifacts\\\\jplacek-sst-my-stack-Api-Lambda_GET_-dist\\\\dist\\\\apps\\\\lambda\\\\index.handler is undefined or not exported","promise":{},"stack":["Runtime.UnhandledPromiseRejection: Runtime.HandlerNotFound: C:\\\\talsec-cloud\\\\.sst\\\\artifacts\\\\jplacek-sst-my-stack-Api-Lambda_GET_-dist\\\\dist\\\\apps\\\\lambda\\\\index.handler is undefined or not exported","    at process.<anonymous> (file:///C:/talsec-cloud/node_modules/@serverless-stack/aws-lambda-ric/lib/index.js:34:23)","    at process.emit (node:events:390:28)","    at process.emit (node:domain:475:12)","    at emit (node:internal/process/promises:136:22)","    at processPromiseRejections (node:internal/process/promises:242:25)","    at processTicksAndRejections (node:internal/process/task_queues:97:32)"]}
If I setup simple lambda function in the exactly the same way, it does work. If I import somewhere both the bundled app and the simple lambda, they both export `handler`:
Copy code
lambda { handler: [Function: handler] } // this is the bundled nestjs
bar { handler: [AsyncFunction (anonymous)] } // this is simple lambda
f
hmm.. is the
sst.json
at the root?
j
yes
but i do not have a default export there...
I tried to deploy the app manually to AWS and it does work, so there doesn't seem to be a problem with the code itself - the AWS sees and runs the handler as usual...
WTF if I add the following at the end of that
index.js
, it suddenly works:
Copy code
const originalHandler = exports.handler; 
exports.handler = async (event,ctx) => {       
    return originalHandler(event, ctx);    
};
actually this is sufficient
exports.handler = exports.handler;
I assume it's because even though it's JS file it's still passed to TS compiler and it doesn't support dynamic exports?
t
curious why you're using module.exports syntax instead of esm exports?
j
this file is produced by webpack
I am just passing it to lambda handler with disbaled bundling
t
Copy code
lambda { handler: [Function: handler] } // this is the bundled nestjs
bar { handler: [AsyncFunction (anonymous)] } // this is simple lambda
It looks like it's getting double nested,
module.exports.handler.handler
- we noticed this with default exports and wrote a workaround for it
ultimately we're marching towards being very esm focused as that provides us with a more consistent structure to build on top of
j
Switching to module output was something I wanted to try to resolve the issue, but I was still wondering why this happens
Copy code
console.log(module.exports.handler.handler);
console.log(exports.handler.handler);
both undefined
I think the esbuild/TS or whatever just can't handle the
export.handler
being set dymaically in some self invoked function generated by webpack
But it's a bit weird, because this file doesn't need any more processing, it's already compiled, it should be used as is....