Serverless + Plugins just keep giving new errors

I’m getting a bit frustrated with serverless deployment, everything I do seems to run into a new deployment error. I don’t want to seem unappreciative of the platform, it seems like a great tool but I just haven’t had any working deployments yet with a couple weeks now of troubleshooting. I really hope I can get some kind of guidance, my other posts are unanswered for now. I’m using nodejs 12 with express and typescript. Local testing with serverless offline works, but any deployment does not! I am trying to use the serverless-webpack plugin because a normal deployment gives a error in maximum zip file size.

Here is my folder structure:

Here is the main points of my handler function file at: server/server.ts

import serverless from 'serverless-http';
app.listen();

// Adding serverless express app from my app class.
module.exports.handler = serverless(app.app);

This is my serverless.yml:

service: editly-api
app: initiate-web # app and org for use with dashboard.serverless.com
org: arielf

# You can pin your service to only deploy with a specific Serverless version
# Check out our docs for more details
frameworkVersion: '2'
useDotenv: true

plugins:
  - '@kingdarboja/serverless-plugin-typescript'
  # - serverless-plugin-typescript
  - serverless-webpack
  - serverless-offline

package:
  individually: true
  exclude:
    - 'node_modules/.cache/**'
    - 'tests/**'
    - 'tests-integration/**'
    - '.idea/**'
    - 'serverless-configs/**'
    - 'envs/**'
    - 'support/**'
    - 'scripts/**'

custom:
  typeScript:
     tsconfigFilePath: tsconfig.backend.json
  webpack: # https://github.com/serverless-heaven/serverless-webpack
    webpackConfig: 'serverless.config.js' # Name of webpack configuration file
    packager: 'yarn' # Packager that will be used to package your external modules
    packagerOptions: {} # Optional, depending on the selected packager

provider:
  name: aws
  runtime: nodejs12.x
  lambdaHashingVersion: 20201221
  stage: dev
  region: us-west-1
  apiGateway:
    minimumCompressionSize: 1024
  environment:
    AWS_NODEJS_CONNECTION_REUSE_ENABLED: 1

functions:
  app:
    handler: server/server.handler
    events:
      - http: ANY /
      - http: 'ANY /{proxy+}'

My serverless.config.js file looks like this:

'use strict';
// This file is used for serverless deployment, use webpack.config.js for normal builds.

const fs = require('fs');
const path = require('path');
const webpack = require('webpack');
const NodemonPlugin = require('nodemon-webpack-plugin');
const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
const { CheckerPlugin } = require('awesome-typescript-loader');
// @ts-ignore
const slsw = require('serverless-webpack');
var nodeExternals = require('webpack-node-externals');



const config = (async function () {
  const serverPath = path.resolve('./server');
  const tempPath = path.join(__dirname, 'tmp');
  const buildPath = path.resolve(__dirname, '.build');
  const distPath = path.resolve(__dirname, '/dist');
  console.log('buildPath', buildPath);

  return {
    cache: true,
    entry: slsw.lib.entries,
    stats: {
      warnings: false,
    },
    mode: slsw.lib.webpack.isLocal ? 'development' : 'production',

    output: {
      publicPath: distPath,
      path: buildPath,
      filename: 'server.js',
    },
    devServer: {
      publicPath: distPath,

      path: buildPath,
      filename: 'server.js',
    },
    resolve: {
      extensions: ['.ts', '.tsx', '.js', '.jsx'],
    },
    },
    module: {
      rules: [
        {
          test: /\.tsx?$/,
          loader: 'awesome-typescript-loader',
        },
      ],
    },
    target: 'node',
    externals: [nodeExternals()],
    optimization: {
      minimize: false,
      concatenateModules: false,
    },
    watchOptions: {
      ignored: ['node_modules/**', tempPath],
    },
    plugins: [
      // @ts-ignore
      new NodemonPlugin({
        watch: serverPath,
        ignore: ['*.js.map', '*.mp4', '*.png', '*.mov', '*.mp3', './server/tmp/*', './build', '**/tmp/**'],
        ext: 'ts,tsx',
        verbose: true,
      }),
      new webpack.DefinePlugin({
        'process.env.FLUENTFFMPEG_COV': false,
      }),
      new webpack.DefinePlugin({
        'process.browser': 'true',
      }),
    ],
  };
})();

module.exports = config;

Here is my package.json:

  "dependencies": {
 "serverless": "^2.25.2",
    "serverless-http": "^2.7.0",
},
  "devDependencies": {
    "@kingdarboja/serverless-plugin-typescript": "^1.4.1",
    "serverless-offline": "^6.8.0",
    "serverless-plugin-typescript": "^1.1.7",
    "serverless-webpack": "5.1.0",
    "tsconfig-paths-webpack-plugin": "^3.3.0",
    "typescript": "^4.1.3",
    "webpack": "^4.20.2",
    "webpack-cli": "^3.1.1",
    "webpack-node-externals": "^2.5.2"
}

I am running the command: rimraf .build .serverless && serverless deploy because if I don’t delete the .build folder I run into EPERM errors.

 Serverless Error ---------------------------------------

  The webpack plugin could not find the configuration file at: C:\Users\Ariel\initiate-video\backend\.build\serverless.config.js

  Get Support --------------------------------------------
     Docs:          docs.serverless.com
     Bugs:          github.com/serverless/serverless/issues
     Issues:        forum.serverless.com

  Your Environment Information ---------------------------
     Operating System:          win32
     Node Version:              12.19.0
     Framework Version:         2.25.2 (local)
     Plugin Version:            4.4.3
     SDK Version:               2.3.2
     Components Version:        3.7.0

I noticed with TS plugin it searches for the webpack config file in the .build directory which is strange and does not happen without the TS plugin. So no problem I will change the webpackConfig path:

webpackConfig: '../serverless.config.js'

Here is the resulting path error:

Serverless: Deprecation warning: Starting with next major version, API Gateway naming will be changed from "{stage}-{service}" to "{service}-{stage}".
            Set "provider.apiGateway.shouldStartNameWithService" to "true" to adapt to the new behavior now.
            More Info: https://www.serverless.com/framework/docs/deprecations/#AWS_API_GATEWAY_NAME_STARTING_WITH_SERVICE
Serverless: Compiling with Typescript...
Serverless: Using local tsconfig.json at "C:\Users\Ariel\initiate-video\backend\tsconfig.backend.json"
Serverless: TypeScript compiled.
Serverless: Copying Extras...
Serverless: Finished Copying Extras
Serverless: Copying Dependencies ...
Serverless: Finished Copying Dependencies ...
Serverless: WARNING: More than one matching handlers found for 'server/server'. Using 'server/server.js'.
buildPath C:\Users\Ariel\initiate-video\backend\.build
config :>>  {}
compileName app
config.output undefined

  Type Error ---------------------------------------------

  TypeError: Cannot read property 'path' of undefined
      at C:\Users\Ariel\initiate-video\backend\node_modules\serverless-webpack\lib\validate.js:209:54
      at arrayMap (C:\Users\Ariel\initiate-video\backend\node_modules\lodash\lodash.js:653:23)
      at Function.map (C:\Users\Ariel\initiate-video\backend\node_modules\lodash\lodash.js:9622:14)
      at ServerlessWebpack.validate (C:\Users\Ariel\initiate-video\backend\node_modules\serverless-webpack\lib\validate.js:200:30)
      at ServerlessWebpack.tryCatcher (C:\Users\Ariel\initiate-video\backend\node_modules\bluebird\js\release\util.js:16:23)
      at Promise._settlePromiseFromHandler (C:\Users\Ariel\initiate-video\backend\node_modules\bluebird\js\release\promise.js:547:31)
      at Promise._settlePromise (C:\Users\Ariel\initiate-video\backend\node_modules\bluebird\js\release\promise.js:604:18)
      at Promise._settlePromiseCtx (C:\Users\Ariel\initiate-video\backend\node_modules\bluebird\js\release\promise.js:641:10)
      at _drainQueueStep (C:\Users\Ariel\initiate-video\backend\node_modules\bluebird\js\release\async.js:97:12)
      at _drainQueue (C:\Users\Ariel\initiate-video\backend\node_modules\bluebird\js\release\async.js:86:9)
      at Async._drainQueues (C:\Users\Ariel\initiate-video\backend\node_modules\bluebird\js\release\async.js:102:5)
      at Immediate.Async.drainQueues [as _onImmediate] (C:\Users\Ariel\initiate-video\backend\node_modules\bluebird\js\release\async.js:15:14)
      at processImmediate (internal/timers.js:461:21)

     For debugging logs, run again after setting the "SLS_DEBUG=*" environment variable.

I added some console logging in the serverless-webpack module’s validate.js and you can see in the above error the config is empty!

 this.webpackConfig = _.map(this.entryFunctions, entryFunc => {
        const config = _.cloneDeep(this.webpackConfig);
        console.log('config :>> ', config);
        config.entry = {
          [entryFunc.entry.key]: entryFunc.entry.value,
        };
        const compileName = entryFunc.funcName || _.camelCase(entryFunc.entry.key);
        console.log('compileName', compileName);
        console.log('config.output', config.output);
        config.output.path = path.join(config.output.path, compileName);
        return config;
      });

It seems something is going wrong with parsing the correct webpack config file. If I change the TS plugin to serverless-plugin-typescript with serverless-webpack I do get the same webpack path undefined error with the config being empty. I’m using the @kingdarboja/serverless-plugin-typescript plugin because trying the other main TS plugin: serverless-plugin-typescript was giving a different error on a different occasion which I honestly don’t remember. Here is the unzipped size error I get if I don’t use serverless-webpack

...
Serverless: Uploading service app.zip file to S3 (484.41 MB)...
...
Serverless: Publishing service to the Serverless Dashboard...
Serverless: Successfully published your service to the Serverless Dashboard: 
  Serverless Error ---------------------------------------

  An error occurred: AppLambdaFunction - Unzipped size must be smaller than 262144000 bytes (Service: AWSLambdaInternal; Status Code: 400; Error Code: InvalidParameterValueException; Request ID: 13171d34-9eda-40d7-81be-1e
9dc58e8e96; Proxy: null).

I hope this post gives all the necessary information for debugging/troubleshooting I wanted to be thorough. I’ve tried many different configurations and plugins I just want something to work!! Thank you all in advance.

Update: Finally got passed this error, basically my config in webpack was an async function that returned a config object. I changed it into just a regular config object and it started parsing correctly!

Hi, thanks for sharing the solution.