2

I am trying to import custom dependencies from lambda layer but is not working.

Environment: nodejs8.10

I have a layer which consist of following directory structure:

mylayer.zip-
           |-nodejs-
                   |-util.js 

Here, util.js has following code:

module.exports = function SomeFunction() {
  console.log('Told you This Doesn't work');
}

and in myLambda.js I'm trying to call SomeFunction with following code:

const someFunction = require('/opt/nodejs/util')
exports.handler = async (event) => {

    someFunction();
    const response = {
        statusCode: 200,
        body: JSON.stringify('Hello from Lambda!'),
    };
    return response;
};

But, I'm getting this error:

{
  "errorMessage": "Cannot find module '/opt/nodejs/util'",
  "errorType": "Error",
  "stackTrace": [
    "Function.Module._load (module.js:474:25)",
    "Module.require (module.js:596:17)",
    "require (internal/module.js:11:18)",
    "Object.<anonymous> (/var/task/index.js:1:75)",
    "Module._compile (module.js:652:30)",
    "Object.Module._extensions..js (module.js:663:10)",
    "Module.load (module.js:565:32)",
    "tryModuleLoad (module.js:505:12)",
    "Function.Module._load (module.js:497:3)"
  ]
}

Thanks in advance.

3
  • " opt "is not in the directory structure you have shared. You probably need to fix the path . Commented Sep 28, 2019 at 10:41
  • @ArUn This isn't a relative path reference. It instead is a lambda layer which is supposed to extract given myLayer.zip under /opt during runtime Commented Sep 30, 2019 at 1:29
  • be sure that your zip command doesn't create additional directory like this mylayer.zip->mylayer->nodejs->..., it was a problem in my case Commented Dec 9, 2019 at 6:57

2 Answers 2

6

If you want to put libs into a layer, and you do not want to publish your lib on nmp, you can add a file or folder to the layers node_modules folder.

preventing naming collisions

To prevent naming clashes it is recommended that you use @scoped package names.

To create your own scope, go to https://www.npmjs.com/org/create and create an organization (f.e myscope). Now you can put whatever you like into node_modules/@myscope without risking a naming clash...

your layers folder structure may look like this:

mylayer.zip-
           |-nodejs-
                   |-node_modules-
                                 |-@myscope-
                                        |-utils-
                                             |-utils.js
                                             |-somthing.js

then you can require everything inside your scope folder:

const someFunction = require('@myscope/utils/utils.js')
const someOtherFunction = require('@myscope/utils/something.js')

alternative solution

another way to achieve your goal is to change your lambdas NODE_PATH environment variable.

the default value (depending on your lambdas node runtime) is:

/opt/nodejs/node12/node_modules:/opt/nodejs/node_modules:/var/runtime/node_modules:/var/runtime:/var/task

staying within the folder structure recommended by aws

just add /opt/nodejs to that list:

/opt/nodejs:/opt/nodejs/node12/node_modules:/opt/nodejs/node_modules:/var/runtime/node_modules:/var/runtime:/var/task

having a layer like this:

mylayer.zip-
           |-nodejs-
                   |-util.js 

now you can require your lib with require("/opt/nodejs/utils.js")

or just require("utils.js")

Sign up to request clarification or add additional context in comments.

12 Comments

I could do that but I have created internal lib to easily interact with aws-sdk from lambda and I would like to have it deployed as layer so every other lambda can use it directly from layer. I certainly could have it pushed to npm and used it as deps but I want to avoid that extra step of publishing npm package everytime something has changed in myLib. Just was wondering if anyone has does this before and was able to achieve what I am trying.
yes, just copy your utils.js in your layers .zip file ito the folder nodejs/node_modules/utils/utils.js as I indicated in my answer. deploy that layer and use utils.js from all your functions. no need to publish on npm... thats just how require resolves pathes ;-)
I'm using the exact same approach im my project now... did you get it to work? if not, don't hesitate to ask.
Actually I haven’t tried it yet, Thanks for your response
@HolgerWill Your solution works; however, it's really a workaround as require('utils/something') suggests that "utils" is a published package (with its own "package.json", etc.). It would make a lot more sense if, alongside "nodejs/node_modules/*", the layer zip could have "nodejs/utils/something.js", and allows require('./utils/something') to import it. It gives a clear distinction between local modules and published packages. Putting inside "node_modules" also increases the chance of naming collision since the dependency chain could bring in dozens of packages with trivial names.
|
0

I do not see an "opt" in your listed directory structure; maybe you need just '/nodejs/util' as your path?

Additionally, I think you need to reference the function within your module:

const util = require('./nodejs/util')
exports.handler = async (event) => {

    await util.someFunction();
    const response = {
        statusCode: 200,
        body: JSON.stringify('Hello from Lambda!'),
    };
    return response;
};

1 Comment

thanks, but '/nodejs/util' doesn't really live with my code and is extracted under "/opt" directory as per documentation. However I will calling function from imported Module and check if that works.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.