serverless-esbuild icon indicating copy to clipboard operation
serverless-esbuild copied to clipboard

Function-level package patterns move files into a separate __only_ folder which interferes with invoke local

Open mstein opened this issue 2 years ago • 3 comments

Describe the bug Function-level package patterns are put in a different folder prefixed with __only_ in the local .build folder. While they are eventually packaged correctly in the resulting zip file before being deployed, this is a problem when trying to do a serverless invoke local and that the code is trying to reach a packaged file since the file path now has a different root.

Note : I'm not using the serverless-offline plugin.

Consider the following project structure :

src/
  templates/
    tpl01.ejs
  lambdas/
    mylambda/
      index.ts

And the following function definition

mylambda:
  handler: src/lambdas/mylambda/index.handler
  package:
    patterns:
      - src/templates/tpl01.ejs

The lambda "mylambda' needs to read the template tpl01.ejs at runtime, and is thus trying to read it using a relative path from its own directory : paths.join(__dirname, '../../templates/tpl01.ejs')

Unfortunately, when running sls invoke local -f mylambda, the plugin generates the following .build output :

.esbuild/
  .build/
    __only_mylambda/
      src/
        templates/
          tpl01.ejs
    src/
      lambdas/
        mylambda/
          index.js

The lambda is thus unable to find the templates folder when executed locally since it was added to a completely different root folder.

Also note that whether the package individually option is set or not, it will generate the __only_ folder regardless.

While I can mitigate this issue by integrating in the lambda code itself a check on whether a __only_<lambdaAlias> path exists, I feel like this shouldn't be necessary.

Expected behavior The packaged files should be added to the same root folder just like the deployed zip file so that the sls invoke local execution work as expected with relative paths.

Versions:

  • OS: Windows 10
  • Serverless Framework Version: 3.18.1
  • Plugin Version: 1.43.1

mstein avatar Apr 24 '23 11:04 mstein

I have the same issue, my (temporary) workaround is to use IS_LOCAL inorder to set dynamically basepath of assets you want include. Like shown below.

image

My function name is __only_databaseMigration show you should chage it to match your function name. _only{function name}

tux86 avatar May 20 '23 18:05 tux86

Hello, fyi the issue is not directly related to database-migration scripts specifically, but just really the packaging of non-js/ts code that are part of the package pattern feature using the esbuild plugin. In my example, those were templates files that needed to be read at runtime.

But otherwise yes, workarounds like using s3 to host files (meaning that even in invoke local, the files would be fetched from S3 instead of the local filesystem) or writing a code that is aware about whether it is ran locally or not, would work. But I still consider the fact that we have to workaround this a bug, since the plugin is supposed to support invoke local out of the box.

mstein avatar May 22 '23 08:05 mstein

given this serverless function config (ts shown):

 handler: 'src/controllers/users/myfunctions.userLogin',
 package: {
      patterns: ['templates']
    },

this will parse the location based on the env variable _HANDLER which serverless-offline is setting. Not pretty but it works until this gets fixed. Will path local and when deployed as a lambda.

   let templateRoot = process.env.IS_OFFLINE
        ? `${__dirname}/../../../../__only_${process.env._HANDLER!.split('.')[1]}/templates/`
        : `${process.env.LAMBDA_TASK_ROOT as string}/templates/`;

ktwbc avatar Jun 03 '23 22:06 ktwbc