serverless-heaven / serverless-webpack

Serverless plugin to bundle your lambdas with Webpack

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Cannot read property '1' of null

huysamen opened this issue · comments

This is a Bug Report

Description

Unable to upgrade serverless-webpack beyond version 2.0.0. This happens on a basic example, after the template was generated with serverless, and changing from Javascript to Typescript.

For bug reports:

  • What went wrong?
    As soon as we upgrade serverless-webpack past version 2.0.0 it is unable to compile.

  • What did you expect should have happened?
    Upgrading from version 2.0.0 to 2.1.0 (and beyond) should not break the compilation as no breaking changes are noted in the changelog.

  • What was the config you used?

# package.json
{
  "name": "google-nodejs",
  "version": "0.1.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "serverless.com",
  "license": "MIT",
  "dependencies": {
    "serverless-google-cloudfunctions": "^1.1.0"
  },
  "devDependencies": {
    "@types/express": "^4.0.36",
    "serverless-webpack": "2.1.0",
    "ts-loader": "^2.3.3",
    "ts-node": "^3.3.0",
    "tslint": "^5.6.0",
    "typescript": "^2.4.2",
    "webpack": "^3.5.5",
    "webpack-node-externals": "^1.6.0"
  }
}
# serverless.yml
service: rest

provider:
  name: google
  runtime: nodejs
  project: my-project
  credentials: ~/.gcloud/keyfile.json

plugins:
  - serverless-webpack
  - serverless-google-cloudfunctions

package:
  exclude:
    - node_modules/**
    - .gitignore
    - .git/**

functions:
  rest:
    handler: rest
    events:
      - http: rest
# webpack.config.js
var path = require("path");
var nodeExternals = require("webpack-node-externals");

module.exports = {
  entry: "./src/index.ts",
  target: "node",
  externals: [nodeExternals()],

  module: {
    loaders: [
      { test: /\.ts(x?)$/, loader: "ts-loader", exclude: "/node_modules/" }
    ]
  },

  resolve: {
    extensions: [".ts", ".js"]
  },

  output: {
    libraryTarget: "commonjs",
    path: path.join(__dirname, "dist"),
    filename: "index.js"
  }
};
  • What stacktrace or error message from your provider did you see?
➜ sls webpack
Serverless: WARNING: Plugin ServerlessWebpack uses deprecated hook before:deploy:createDeploymentArtifacts,
                     use package:createDeploymentArtifacts hook instead
Serverless: WARNING: Plugin ServerlessWebpack uses deprecated hook after:deploy:createDeploymentArtifacts,
                     use package:createDeploymentArtifacts hook instead
 
  Type Error ---------------------------------------------
 
  Cannot read property '1' of null
 
     For debugging logs, run again after setting the "SLS_DEBUG=*" environment variable.
 
  Stack Trace --------------------------------------------
 
TypeError: Cannot read property '1' of null
    at getEntryForFunction (/Users/user/path/to/service/node_modules/serverless-webpack/lib/validate.js:11:48)
    at _.forEach.func (/Users/user/path/to/service/node_modules/serverless-webpack/lib/validate.js:36:23)
    at arrayEach (/Users/user/path/to/service/node_modules/lodash/lodash.js:537:11)
    at Function.forEach (/Users/user/path/to/service/node_modules/lodash/lodash.js:9359:14)
    at ServerlessWebpack.validate (/Users/user/path/to/service/node_modules/serverless-webpack/lib/validate.js:35:9)
From previous event:
    at PluginManager.invoke (/Users/user/.config/yarn/global/node_modules/serverless/lib/classes/PluginManager.js:242:22)
    at PluginManager.run (/Users/user/.config/yarn/global/node_modules/serverless/lib/classes/PluginManager.js:261:17)
    at variables.populateService.then (/Users/user/.config/yarn/global/node_modules/serverless/lib/Serverless.js:99:33)
    at runCallback (timers.js:672:20)
    at tryOnImmediate (timers.js:645:5)
    at processImmediate [as _immediateCallback] (timers.js:617:5)
From previous event:
    at Serverless.run (/Users/user/.config/yarn/global/node_modules/serverless/lib/Serverless.js:86:74)
    at serverless.init.then (/Users/user/.config/yarn/global/node_modules/serverless/bin/serverless:39:50)
 
  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:                     darwin
     Node Version:           6.11.1
     Serverless Version:     1.20.2

Additional Data

  • Serverless-Webpack Version you're using:
    2.1.0

  • Webpack version you're using:
    3.5.5

  • Serverless Framework Version you're using:
    1.20.2

  • Operating System:
    macOS Sierra 10.12.6

  • Stack Trace (if available):

Your handler name seems not to match your actual handler file in serverless.yml:

functions:
  rest:
    handler: rest
    events:
      - http: rest

The versions 2.1.0 and beyond enforce correct configurations now - it was a bug that the plugin did not do proper checks of the service configuration consistence before, which led to quite unstable runtime behavior of the plugin.

The important thing (especially from a sight of the Serverless framework) is, that the handlers are declared correctly, so your function definition should be:

functions:
  rest:
    handler: src/index.rest  # rest would be the function called within index
    events:
      - http: rest

in your webpack config you then should use the entry resolution mechanism, which makes sure that the webpack config is setup correctly for the service:

const slsw = require('serverless-webpack');
...
entry: slsw.lib.entries,
...
output: {
  ...
  filename: '[name].js'
  ...
}

Alternatively you can build that all manually and make sure that your handlers match:

entry: {
  'src/index': './src/index.ts'
}

output: {
  filename: './src/index.js'
}

BTW: individual packaging of a service will only work with the automatic stuff enabled.

Nevertheless I agree that the error message is wrong. It should emit something that points out that the handler file declared in the serverless.yml could not be found in that case.

That seems like an AWS way of declaring the handlers. We are using Goole Cloud Functions which does not use the handler: src/index.rest syntax of defining handlers.

If you try to use that syntax with the serverless-google-cloudfunctions plugin, you get:

  The "handler" property for the function "rest" is invalid. Handlers should be plain strings referencing only the exported function name without characters such as "." or "/" (so e.g. "http" instead of "index.http"). Do you want to nest your functions code in a subdirectory? Google solves this by utilizing the "main" config in the projects package.json file. Please check the docs for more info.

Thanks for the info. Hmmm.
@pmuens, can you tell me how the handler definitions are meant to be for the Google plugin? I thought handlers in Serverless in general should point to the handler file, regardless of the plugin used.
@huysamen , can you tell me what "rest" as handler exactly is supposed to do? Should it call something named "rest" in the Google context? If you'd run this serverless config without the webpack-plugin, how would the handler for the function be located by Serverless?

@huysamen One thing you additionally could try: can you try to change YOUR entry definition just to be an object and leave everything else as is?

entry: {
  "index.ts": "./src/index.ts"
}

Does that solve the crash?

@HyperBrain the rest endpoint is just a test function. I think the default when generating a template with sls create --template google-nodejs --path my-project the function is called first or something. It's just a test HTTP function. You can call it something else if you like. It is not Google specific at all.

With the serverless-google-cloudfunctions plugin it actually looks for the exported methods in the index.js to deploy from the handler name that you specify.

Let me try the entry object change quick.

@HyperBrain tried changing the entry to an object, same issue.

Ok. I'll check the template and do some tests.

From the sample template it seems that for Google, the handler definitions in serverless.yml are the names of the exports in the index.js. If that's the general approach for Google and all projects look like that, I might be able to provide a fix that ignores any handler evaluation in case a Google project is packed.

That would make it compile again with projects, that are structured like the sample template. This should end up in 2.2.1 then.

A further thought (that's not directly related to this - obvious - bug) is, that individual packaging and per function optimization would not be possible due to the structure of the projects. I'll investigate that after the bug is fixed and I have gathered more information, why the layout has been chosen in the way it is - if it's a necessary requirement for Google or if it was chosen just on purpose.
Opposed to AWS and OpenWhisk, this layout prevents gaining all the benefits from Webpacks TreeShaking and optimization mechanisms, because the functions are not separated physically.

The fix has to be ported to v3 as soon as the v2 bugfix has been released.

Released with 2.2.1