serverless-heaven/serverless-webpack

V3: Invoke lokally does not have access to files bundled with the file-loader

cwaltken-edrans opened this issue · 6 comments

Bug Report

Description

I have a sample-file.yaml file I want to bundle this together with my lambda function using file-loader.
Executing locally with sls webpack invoke -f test does not have this bundled file in it's environment. It is bundled to upload for aws though.

Additional Data

Minimal failing example on github

  • Serverless-Webpack Version 2.2.0 and 3.0.0 branches
  • Webpack version: 3.4.1
  • Serverless Framework Version: 1.19.0
  • Operating System: linux

Stack Trace

$ sls webpack invoke -f test
{ handler: './handler.js' }
Serverless: Bundling with Webpack...
Time: 2892ms
                                Asset      Size  Chunks             Chunk Names
59ca0efa9f5633cb0371bbc0355478d8.yaml  13 bytes          [emitted]  
                           handler.js   3.21 kB       0  [emitted]  main
   [0] ./handler.js 183 bytes {0} [built]
   [1] external "fs" 42 bytes {0} [not cacheable]
   [2] ./sample-file.yaml 83 bytes {0} [built]
Serverless: Run function test...
 
  Error --------------------------------------------------
 
  ENOENT: no such file or directory, open '59ca0efa9f5633cb0371bbc0355478d8.yaml'
 
     For debugging logs, run again after setting the "SLS_DEBUG=*" environment variable.
 
  Get Support --------------------------------------------
     Docs:          docs.serverless.com
     Bugs:          github.com/serverless/serverless/issues
     Forums:        forum.serverless.com
     Chat:          gitter.im/serverless/serverless
 
  Your Environment Information -----------------------------
     OS:                     linux
     Node Version:           6.11.1
     Serverless Version:     1.19.0
 

I analyzed the problem and found the reason (my test setup is SLS 1.19, webpack 3.4.1 and the v3.0.0-individual-packaging branch of the plugin). I used serverless invoke local --function=test.

It seems that the serverless command sets the CWD to the service root, so that the file load within the handler cannot find it, because it is bundled together with the handler. Deployed on AWS the directory, where the handler is in is also the CWD. That's why it works on AWS Lambda.

A proper fix would be to set the CWD correctly, just before SLS invokes the handler in the callback.

I just verified with a small local hack that this is the reason of the issue and that it will solve the problem properly:

$ node node_modules/serverless/bin/serverless invoke local --function=test      
{ handler: './handler.js' }
Serverless: Bundling with Webpack...
Time: 561ms
                                Asset      Size  Chunks             Chunk Names
59ca0efa9f5633cb0371bbc0355478d8.yaml  13 bytes          [emitted]
                           handler.js   3.21 kB       0  [emitted]  handler
   [0] ./handler.js 183 bytes {0} [built]
   [1] external "fs" 42 bytes {0} [not cacheable]
   [2] ./sample-file.yaml 83 bytes {0} [built]
Hello world!

Implemented the fix. Now the execution context of the locally invoked function is correct. It also works with serverless invoke local --function=test --watch and changing the bundled file triggers a recompile correctly and the executed handler is restarted.

I changed the sample yaml file in this case which retriggered the invoke as expected.

$ node node_modules/serverless/bin/serverless invoke local --function=test --watch
{ handler: './handler.js' }
Serverless: Bundling with Webpack...
Time: 3351ms
                                Asset      Size  Chunks             Chunk Names
b4f9269aa828ed207f6f92f888408feb.yaml  14 bytes          [emitted]
                           handler.js   3.23 kB       0  [emitted]  handler
   [0] ./handler.js 211 bytes {0} [built]
   [1] external "fs" 42 bytes {0} [not cacheable]
   [2] ./sample-file.yaml 83 bytes {0} [built]
aHello world!

Serverless: Watch function test...
Serverless: Waiting for changes ...
Serverless: Sources changed.
Serverless: Bundling with Webpack...
Time: 94ms
                                Asset      Size  Chunks             Chunk Names
59ca0efa9f5633cb0371bbc0355478d8.yaml  13 bytes          [emitted]
                           handler.js   3.23 kB       0  [emitted]  handler
   [0] ./handler.js 211 bytes {0} [built]
   [1] external "fs" 42 bytes {0} [not cacheable]
   [2] ./sample-file.yaml 83 bytes {0} [built]
Hello world!

The fix is merged into the v3.0.0 branch. Please verify there, if it works.

This is fixed in v3. If any other issues arise, please reopen or create a new issue. Closing this now.

I believe this is happening again. serverless-webpack 5.1.1

I temporarily fixed it like this:

function getStaticFilePath(pathToFile: string) {
  const devPath = path.join(process.cwd(), '.webpack', 'service', pathToFile);
  const prodPath = path.join(__dirname, pathToFile);
  return process.env.NODE_ENV === 'production' ? prodPath : devPath;
}

Where pathToFile either comes from a require statement or is a hardcoded path provided by you.