Make your lambda functions lightweight
Tags: javascript, node, serverless, aws
Published: 2021-08-17 16:51:51

I see a lot of articles on how to create a lambda with simple steps, always showing the hello world. But every time you start using dependencies in your lambda function, it starts to weigh.

So, this article will show you how to make your lambda more lightweight and have only the function that we need to execute

Before jumping into the code you need these requirements:

1) AWS CLI installed
2) Configure your aws credentials locally with `aws configure`. 
3) Obviously node installed (We are going to use node v12)
4) Serverless installed `npm install -g serverless`

Do you have it all configured? Alright! Let's start coding!! 🙂

**First, I wanna show you the problem**

Create a folder or create a repo and clone it. In my case, I created a repo and clone it.

![CreateRepo](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1yutie17xnduiy1gm8h6.png)

I will use npm to install the dependencies, you could use yarn if you want to

```bash
> npm init -y
```

![npmInit](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zdfnw0xhejflaet21kgn.png)
This will create a package.json 

Now we are going to create our lambda function with

```bash
> sls init aws-node-rest-api
```
![slsInit](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x768pzc6cvkg48ujh8fd.png)

We are going to make a few changes to the project. 

The `aws-node-rest-api` will change it to `src` and copy `serveless.yml` from `src` in our root folder

```bash
> mv aws-node-rest-api src
> mv src/serveless.yml ./serverless.yml
```

![Moving Files](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mza8zdahaccsjgdsba91.png)

And the last thing to change will be the path of where is our lambda function

Before

```bash
app: aws-node-rest-api
service: aws-node-rest-api

provider:
  name: aws
  runtime: nodejs12.x

functions:
  hello:
    handler: handler.hello
    events:
      - http:
          path: /
          method: get
```

After

```bash
app: aws-node-rest-api
service: aws-node-rest-api

provider:
  name: aws
  runtime: nodejs12.x

functions:
  hello:
    **handler: src/handler.hello**
    events:
      - http:
          path: /
          method: get
```

I highlighted the changed path of the lambda function. 

And that's it. Let's deploy our function!!

```bash
> serverless deploy
```

After a while, you'll get the following picture

![Deployed](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ps93r68gh89j2teufpdz.png)

And if you go to aws you can see your new lambda function!! YEY!!! GOOD JOB!!!

![AwsFunction](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2s4f894t16t0euazo0nl.png)

And if go to see what is deployed in our lambda function we can see the code

![AwsFunctionCode](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zg9i1ertbs7l8o99o6ke.png)

Now that we are experts in serverless and lambda functions we want to add some packages

Our lambdas won't we simple right? most of the time we are using packages, to do some calls to the database, call an aws feature, call an api, manipulate an image, etc.

Now, let's install some packages. Let's say we are going to manipulate some images, in our case we are going to use `jimp` (this is only for the example. I needed a heavy npm package)

So in our console let's type the following command

```bash
> npm install --save jimp
```

And now let's deploy again a see what's going on

```bash
> severless deploy
```

![AwsFunctionNoCode](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2isiql83k1sec0bqzbcb.png)

Wait! What? Cannot see the code? What's going on?

Well, with the simple configuration we are uploading the node_modules folder into our lambda function and the package that we just installed makes the lambda too large to show the code.

How can avoid this and see my code again!!?  **Lambda Layers** to the rescue!!

That's right! serverless has the ability to create Lambda Layers. A Lambda Layer is a ZIP archive that contains libraries or other dependencies. With that, we can make our lambda function smaller again.

How we can achieve this? We are going to put our node_modules folder in a Lambda Layer.

For this, we are going to make a few changes to our code.

First, we are going to install this package

```bash
> npm i --save-dev serverless-hooks-plugin
```

and after that, we are creating a deployment folder and create a script where it has all the things that we need to create the layer.

```bash
> mkdir deployment
> touch deployment/prepare.sh
```

 In our [prepare.sh](http://prepare.sh) we are going to copy the following code

```bash
echo '****** Starting Pre Deploy Script ******'
echo '1- Creating folder for layers and copy package.json' 
rm -rf ./.dist
rm -rf ./.serverless-layers
mkdir -p .serverless-layers/node-layers/nodejs
cp package.json .serverless-layers/node-layers/nodejs/
echo 'DONE!' 

echo '2 - Change path to serverless-layer, adding LIB dependency, remove npm and yarn files'
cd .serverless-layers/node-layers/nodejs
npm i --production
rm package.json
rm package-lock.json
cd ../../..
echo 'DONE!' 

echo '****** Finished Pre Deploy Script ******'
```

Basically we are creating a nodejs folder inside .serveless-layes/node-layers, copying the package.json from our root folder and install all the dependencies.

Then, in our package.json we are adding a new script

```bash
"deploy:prepare": "sh deployment/prepare.sh"
```

Leaving our package.json something like this.

```bash
{
  "name": "serverless-aws-node-layer-example",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "deploy:prepare": "sh deployment/prepare.sh",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/cesmunoz/serverless-aws-node-layer-example.git"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "bugs": {
    "url": "https://github.com/cesmunoz/serverless-aws-node-layer-example/issues"
  },
  "homepage": "https://github.com/cesmunoz/serverless-aws-node-layer-example#readme",
  "dependencies": {
    "jimp": "^0.16.1"
  },
  "devDependencies": {
    "serverless-hooks-plugin": "^1.1.0"
  }
}
```

And the last thing, we need to make this steps in our serveless.yml. 

Adding the following things:

1) Using the custom hook that the package `serverless-hooks-plugin` provides us

```bash
plugins:
  - serverless-hooks-plugin

custom:
  hooks:
    before:package:createDeploymentArtifacts:
      - npm run deploy:prepare
```

2) Creating the layer

```bash
layers:
  nodeModules:
    path: ./.serverless-layers/node-layers
    name: My-App-Node-Dependencies
    description: Node Modules for My App
    compatibleRuntimes:
      - nodejs12.x
    package:
      include:
        - ./**
```

3) Make our function package individually and exclude everything

```bash
package:
  individually: true
  exclude:
    - ./**
```

 4) Include only our handler.js in the lambda function and make use of the lambda layer

```bash
functions:
  hello:
    handler: src/handler.hello
    layers:
      - { Ref: NodeModulesLambdaLayer }
    package:
      include:
        - src/handler.js        
    events:
      - http:
          path: /
          method: get
```

The final serveless.yml will be something like this:

```bash
app: aws-node-rest-api
service: aws-node-rest-api

provider:
  name: aws
  runtime: nodejs12.x

plugins:
  - serverless-hooks-plugin

custom:
  hooks:
    before:package:createDeploymentArtifacts:
      - npm run deploy:prepare
 
layers:
  nodeModules:
    path: ./.serverless-layers/node-layers
    name: My-App-Node-Dependencies
    description: Node Modules for My App
    compatibleRuntimes:
      - nodejs12.x
    package:
      include:
        - ./**

package:
  individually: true
  exclude:
    - ./**
 
functions:
  hello:
    handler: src/handler.hello
    layers:
      - { Ref: NodeModulesLambdaLayer }
    package:
      include:
        - src/handler.js        
    events:
      - http:
          path: /
          method: get
```

Let's deploy it again and see what happens

```bash
> serverless deploy
```

![AwsFunctionCodeAgain](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/110d6vpngzkyzxcuwx31.png)

Woala! We can see our code again! 

And Where is our lambda layer? 

![AwsLambdaLayer](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sre3hw12wcynwn0dbtem.png)

We can see and the lambda function has a dependency on our new lambda layer

And if we go to lambda layers we can see it's there

![AwsLayers](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ix9g1an54u6ol1o3ruth.png)

So with that configuration we can view always our code.

Hope you found it useful as I do.

Repo: [https://github.com/cesmunoz/serverless-aws-node-layer-example](https://github.com/cesmunoz/serverless-aws-node-layer-example)

See you next time!!

C.