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

Missing entries in slsw.lib when serverless functions are defined in a separate file

Open sohailalam2 opened this issue 7 years ago • 20 comments

This is a Bug Report

Description

For bug reports:

  • What went wrong?

Webpack fails to identify entry point when serverless functions are extracted out into a separate yml file. However, it works when serverless.yml has the functions defined in the same file.

  • What did you expect should have happened?

Should have identified the correct entry points in slsw.lib.entries

  • What was the config you used?

❗️ This configuration fails

serverless.yml

functions:
    - ${file(src/functions/index.yml)}

functions/index.yml

index:
  handler: src/handler.handle
  events:
    - http

This configuration works fine

serverless.yml

functions:
  misc:
    handler: src/handler.handle
    events:
      - http
  • What stacktrace or error message from your provider did you see?
Serverless: Bundling with Webpack...

  Webpack Options Validation Error -----------------------

  Invalid configuration object. Webpack has been initialised using a configuration object that does not match the API schema.
 - configuration.entry should be one of these:
   object { <key>: non-empty string | [non-empty string] } | non-empty string | [non-empty string] | function
   -> The entry point(s) of the compilation.
   Details:
    * configuration.entry should not be empty.
      -> Multiple entry bundles are created. The key is the chunk name. The value can be a string or an array.
    * configuration.entry should be a string.
      -> An entry point without name. The string is resolved to a module which is loaded upon startup.
    * configuration.entry should be an array:
      [non-empty string]
    * configuration.entry should be an instance of function
      -> A Function returning an entry object, an entry string, an entry array or a promise to these things.

Additional Data

  • Serverless-Webpack Version you're using: 5.1.0
  • Webpack version you're using: 4.2.0
  • Serverless Framework Version you're using: 1.26.1
  • Operating System: linux

sohailalam2 avatar Apr 21 '18 17:04 sohailalam2

Hi @sohailalam2 , thanks for reporting.

This behavior looks quite strange, because Serverless should be constructing the complete service in-memory, before the webpack plugin tries to evaluate the function handlers.

There have been a lot of changes done in Serverless recently regarding the variable resolution. Can you try the same setup with the current Serverless master branch (the upcoming 1.27)? Additionally, use --verbose to get some more detailed output.

HyperBrain avatar Apr 23 '18 07:04 HyperBrain

was this resolved?

Loag avatar May 12 '18 05:05 Loag

@immexerxez Not yet. It needs to be analyzed first, what exactly happens.

HyperBrain avatar May 12 '18 09:05 HyperBrain

For me it fails at the regex check "handlerEntry". in lib -> validate

    const getEntryForFunction = (name, serverlessFunction) => {
      const handler = serverlessFunction.handler;
      // Check if handler is a well-formed path based handler.
      const handlerEntry = /(.*)\..*?$/.exec(handler);
      if (!handlerEntry) {
        _.get(this.serverless, 'service.provider.name') !== 'google' &&
          this.serverless.cli.log(`\nWARNING: Entry for ${name}@${handler} could not be retrieved.\nPlease check your service config if you want to use lib.entries.`);
        return {};
      }
      const handlerFile = handlerEntry[1];
      const ext = getEntryExtension(handlerFile);

      // Create a valid entry key
      return {
        [handlerFile]: `./${handlerFile}${ext}`
      };
    };
`

Loag avatar May 12 '18 18:05 Loag

So this issue for me was I was just exporting my functions and the regex would fail trying to find the "." I haven't really been following the development of serverless over the past few months so maybe this is the accepted/expected way of doing things?

// expected
module.exports.some_name = (event, context, callback) => {
  callback(null, 'hi');
};

// mine
module.exports = (event, context, callback) => {
  callback(null, 'hi');
};

Loag avatar May 12 '18 18:05 Loag

Hi @immexerxez .

The specification is, that you must export the named function, so the regex resembles exactly what Serverless specifies. We should not add a different semantics in the plugin as that what Serverless defines. Serverless' correct way of defining a handler function is: handler: <module>.<handlerFuncExport>. This is a vital assumption in Serverless and is used e.g. in invoke local to determine and load the handler.

Additionally, AWS themselves document their configuration in that way: https://docs.aws.amazon.com/lambda/latest/dg/nodejs-prog-model-handler.html

Maybe a proper solution of the issue would be to add a hint to the documentation (README) that shows the right layout and close the PR that introduces a non-spec-conform behavior.

HyperBrain avatar May 13 '18 10:05 HyperBrain

Ah yes I'm behind the times! Thanks for letting me know. I agree pointing that out in the docs is the best solution.

Loag avatar May 15 '18 16:05 Loag

@immexerxez @HyperBrain I think we are missing the point here and not focusing on the reported issue. The problem is that when I place the function declarations in the serverless.yml file, everything works as expected, however, when I extract the function declarations to a separate file and try to include that file in the yaml config, it blows up. NOTE: Serverless does support this pattern

❗️ This configuration fails

serverless.yml

functions:
    - ${file(src/functions/index.yml)}

functions/index.yml

index:
  handler: src/handler.handle
  events:
    - http

This configuration works fine

serverless.yml

functions:
  misc:
    handler: src/handler.handle
    events:
      - http

sohailalam2 avatar May 15 '18 18:05 sohailalam2

Hi @sohailalam2 Agree. @immexerxez 's issue was a "cross-in" and my answer only relates to the issue with not specifying the handler function. Of course the original issue is still valid and has to be analyzed 😃

HyperBrain avatar May 15 '18 18:05 HyperBrain

I'm experiencing the same issue since I split my serverless file.

Nomeyho avatar Jun 28 '18 06:06 Nomeyho

I am expecting this same issue when I split my resources into separate files. I do not have functions. Any solution or workaround to this yet?

xaxist avatar Sep 29 '18 20:09 xaxist

I'm experiencing this same issue. Any solution yet?

jameswberry avatar Feb 25 '19 21:02 jameswberry

@sohailalam2 I believe the issue is with your example, if you change the files to look like the following, it should work:

serverless.yml:

functions:
  index: ${file(src/functions/index.yml)}

functions/index.yml:

handler: src/handler.handle
events:
  - http

As I understand it, the functions property on serverless.yml should be an object, not an array.

hassankhan avatar Apr 26 '19 20:04 hassankhan

@anupsarode IIRC you need at least one function if you're using serverless-webpack. We should probably improve the DX on this though, its definitely bitten me a few times in the past too.

hassankhan avatar Apr 26 '19 20:04 hassankhan

@hassankhan I just hit this and my setup is as you specified in https://github.com/serverless-heaven/serverless-webpack/issues/372#issuecomment-487191427. Will try and find the time to make a min repo for the issue but pretty confident this is still a bug..

kbrownlees avatar Sep 01 '19 21:09 kbrownlees

Had the same issue just now. Everything worked (including the separate functions file) until I attempted to add webpack into the project, and got to this error. The solution recommended above does not seem to work. My functions file looks like this though (contains multiple functions):

get:
  handler: functions/get.handler 
  events:
    - http: 
        path: /get
        method: get
        cors: true

create:
  handler: functions/create.handler
  events:
    - http: 
        path: /create
        method: put
        cors: true

and the serverless.yml contains this as the functions reference:

functions: 
  index: ${file(./functions/functions.yml)}

Would be grateful as to any advice as I*m a bit confused how to proceed further. Thank you.

andreimcristof avatar Sep 08 '19 10:09 andreimcristof

I had the name problem, but in my case, it had a lost function who doesn't have any handler. I had removed then it worked

functionName:
    handler: handler

ErickWendel avatar Mar 31 '20 20:03 ErickWendel

  WebpackOptionsValidationError: Invalid configuration object. Webpack has been initialised using a configuration object that does not match the API schema.
   - configuration.entry should be an non-empty object.

same problem here, I'm clueless about fixing this: webpack.config.js

const path = require('path');
const slsw = require('serverless-webpack');
// var nodeExternals = require('webpack-node-externals')

module.exports = {
  mode: slsw.lib.webpack.isLocal ? 'development' : 'production',
  entry: slsw.lib.entries,
  // externals: [nodeExternals()],
  devtool: 'source-map',
  resolve: {
    extensions: ['.js', '.jsx', '.json', '.ts', '.tsx'],
  },
  output: {
    libraryTarget: 'commonjs',
    path: path.join(__dirname, '.webpack'),
    filename: '[name].js',
  },
  target: 'node',
  module: {
    rules: [
      // all files with a `.ts` or `.tsx` extension will be handled by `ts-loader`
      { test: /\.tsx?$/, loader: 'ts-loader' },
    ],
  },
};

ggmartins avatar Jun 16 '20 01:06 ggmartins

  WebpackOptionsValidationError: Invalid configuration object. Webpack has been initialised using a configuration object that does not match the API schema.
   - configuration.entry should be an non-empty object.

same problem here, I'm clueless about fixing this: webpack.config.js

const path = require('path');
const slsw = require('serverless-webpack');
// var nodeExternals = require('webpack-node-externals')

module.exports = {
  mode: slsw.lib.webpack.isLocal ? 'development' : 'production',
  entry: slsw.lib.entries,
  // externals: [nodeExternals()],
  devtool: 'source-map',
  resolve: {
    extensions: ['.js', '.jsx', '.json', '.ts', '.tsx'],
  },
  output: {
    libraryTarget: 'commonjs',
    path: path.join(__dirname, '.webpack'),
    filename: '[name].js',
  },
  target: 'node',
  module: {
    rules: [
      // all files with a `.ts` or `.tsx` extension will be handled by `ts-loader`
      { test: /\.tsx?$/, loader: 'ts-loader' },
    ],
  },
};

@ggmartins Conseguiu resolver?

hectorgrecco avatar Jul 24 '21 14:07 hectorgrecco

@hectorgrecco sorry this was a long time ago. IIRC what I did was to regenerate tsx code from the template and migrate the old files to the latest version.

ggmartins avatar Jul 24 '21 15:07 ggmartins