Require in lambda functions

I have a problem with building a chatbot backend using netlify lambda functions. While building all other lambda functions proved to be seamless so far, it seems like Google’s dialogflow library has some dependencies with unusual resolution of require functions. The function builds itself with a warning:

WARNING in /mnt/c/Projects/deploy-landing/node_modules/google-gax/node_modules/semver/index.js 3:51-64
Critical dependency: the request of a dependency is an expression
 @ /mnt/c/Projects/deploy-landing/node_modules/google-gax/build/src/grpc.js
 @ /mnt/c/Projects/deploy-landing/node_modules/google-gax/build/src/index.js
 @ /mnt/c/Projects/deploy-landing/node_modules/dialogflow/src/v2/sessions_client.js
 @ /mnt/c/Projects/deploy-landing/node_modules/dialogflow/src/v2/index.js
 @ /mnt/c/Projects/deploy-landing/node_modules/dialogflow/src/index.js
 @ ./dialogflow.js

Then, trying to call it in the browser I get another error:

Function invocation failed: TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string. Received type number

The code from the module in question that seems to be causing issues is as follows:

const lrCache = {}
const lazyRequire = (path, subkey) => {
  const module = lrCache[path] || (lrCache[path] = require(path))
  return subkey ? module[subkey] : module
}

Is there any way to circumvent this issue?

EDIT:
After some more debugging I found out that it chokes on compiled file in this place, specifically in path.dirname:

// Load Google's well-known proto files that aren't exposed by Protobuf.js.
{
    // Protobuf.js exposes: any, duration, empty, field_mask, struct, timestamp,
    // and wrappers. compiler/plugin is excluded in Protobuf.js and here.
    var wellKnownProtos = ['api', 'descriptor', 'source_context', 'type'];
    var sourceDir = path.join(path.dirname(/*require.resolve*/(39)), 'google', 'protobuf');
    for (var _i = 0, wellKnownProtos_1 = wellKnownProtos; _i < wellKnownProtos_1.length; _i++) {
        var proto = wellKnownProtos_1[_i];
        var file = path.join(sourceDir, proto + ".proto");
        var descriptor_1 = Protobuf.loadSync(file).toJSON();
        // @ts-ignore
        Protobuf.common(proto, descriptor_1.nested.google.nested);
    }
}

I created a file webpack.functions.js:

module.exports = {
  externals: { dialogflow: 'dialogflow' }
};

Then in package.json I modified the scripts that I run to start lambda functions to use this config file:

{

  "scripts": {
    "lambda-build": "netlify-lambda build --config ./webpack.functions.js \"./netlify/dev\""
    ...
  }
  ...
}

As far as I understand netlify now doesn’t bundle dialogflow and instead it is used as a node module. One way or another - it’s working.

Great that you found a resolution. Another way is to not bundle your function at all. The netlify buildbot supports “zip-it-and-ship-it” by default. All you have to do is point to where you have your function and make sure you have its dependencies either in your main package.json (easiest) or in a package.json where your function lives (requires manually running npm install in your function folder). Once you’ve done this, our buildbot will package your function up as a zip file and deploy it as-is. No bundling.