Serverless Web Application with Lerna and Webpack

SERVERLESS

In this Guide we will learn how to write Serverless services in Monorepo style.

When I tried to write a solutions combine Serverless, Webpack and Lerna together, I can’t find any good guide how to do this, then, after implementing it I feel like I want to share my finding with the community,

What is Lerna?

Lerna,a tool for managing JavaScript projects with multiple packages, mostly used for Monorepo, Monorepo is beneficial strategy to keep all your repositories in a one global repository, contains all the common infrastructure and build tools, while each sub ‘package’ contains a different business project.

So if I have different services, I’ll keep all of them in one repository, each one in a different package.

You have a file structure that looks like this:

package.json
packages/
package-1/
package.json
package-2/
package.json

My root package.json contains some common dependencies like aws-sdk and some dev-dependencies like webpack

{
  "name": "root",
  "private": true,
  "dependencies": {
    "aws-sdk": "^2.531.0",
    "request-promise": "^4.2.5",
    "request": "^2.88.0"
  },
  "devDependencies": {
    "express": "4.17.1",
    "lerna": "^3.19.0",
    "serverless-webpack": "^5.3.1",
    "webpack": "^4.40.2",
    "webpack-cli": "^3.3.9"
  }
}

Read more about Lerna and it’s feature in Lerna github.

Let’s serverless it:

Serverless framework gives us the ability to deploy a serverless application (GCP,AWS,AZURE)

A basic example of yml file defining a Lambda:

service: MyService

provider:
  name: aws
  runtime: nodejs12.x

package:
  exclude:
    - node_modules/**

functions:
  myFunction:
    handler: index.myFunction

Let’s bundle it, Adding webpack to the party:

We obviously won’t want to deploy the full code to AWS, and we may want to use webpack to bundle it into one huge index file.

In order to do that I use serverless-webpack plugin

All the work needed, is just adding it to the serverless file:

service: MyService

provider:
  name: aws
  runtime: nodejs12.x

package:
  exclude:
    - node_modules/**

plugins:
  - serverless-webpack
functions:
  myFunction:
    handler: index.myFunction

And the index file wii look like this:

module.exports.myFunction = async (event, context) => {

    //doing all stuff needed :)
};

We mention that package is a business service unit, and it can be split to multiple Lambdas, for example UserService, can be split to 3 Lambdas for create, delete and update.

index.js will be like:

module.exports.createUser = async (event, context) => {

    //doing all stuff needed :)
};


module.exports.updateUser = async (event, context) => {

    //doing all stuff needed :)
};

module.exports.deleteUser = async (event, context) => {

    //doing all stuff needed :)
};

With its equivalent serverless.yml

service: UserService

provider:
  name: aws
  runtime: nodejs12.x

package:
  exclude:
    - node_modules/**

plugins:
  - serverless-webpack
functions:
  createUser:
    handler: index.createUser
  updateUser:
    handler: index.updateUser
  deleteUser:
    handler: index.deleteUser
What can I achieve from managing all my packages in the same repo?

Sure, I can have one yml file contains my VPC configuration, security groups, subnet ids, common environment variables and more, and all of them in a one root yml file. this can be referred from any serverless.yml:

provider:
  name: aws
  stage: prod
  runtime: nodejs12.x
  vpc:
    securityGroupIds: ${file(../../.root.yml):securityGroupIds}
    subnetIds: ${file(../../.root.yml):subnetIds}

  environment:
    ${file(../../.root.yml):environment}

And the root.yml:

securityGroupIds:
  - "sg-xxxxx"
subnetIds:
  - "subnet-xxxxx1"
  - "subnet-xxxxx2"
  - "subnet-xxxxx3"
environment:
  KEY1: value1
  KEY2: value2

Conclusion

In this Guide we implement monorepo contains some services, each service can contains multiple lambdas, and each lambda is deployed using serverless framework, and we set some common configuration in the root folder to affect all sub packages.

Leave a Reply

Your email address will not be published.