Function compiled with netlify-lambda throwing a dependency error once deployed

My app:
tender-engelbart-2ed7d8.netlify.app
Started off as a static page deployed with git (just HTML, CSS and JS), no pakage.json and no build step. No problems there.

I am attempting to add a lambda function (To fetch an OAuth token). This function has a dependency ‘node-fetch’.

To do so I restructured my project:

  • moved the static files out of the root into ./client (these files do not need a build)
  • added a empty functions directory (ready to contain a built function file for deploy)
  • a src/functions/ with my function source
  • a package.json to define a build script and dependencies (for my function)

Like so:

client/ (static files)
	emoji.js
	index.html
	index.js
functions/
	fetchToken.js (built function)
netlfiy.toml
package.json
src/functions/
	fetchToken.js (function source)

My intent is to use netlify-lambda to pre-compile my function to a standalone file locally. Then deploy the files with git as before.

netlify.toml:

[build]
	command = "npm run build"
	publish = "client/"
	functions = "functions/"

package.json:

{
  "name": "fetch-token",
  "version": "1.0.0",
  "description": "",
  "main": "functions/fetchToken.js",
  "scripts": {
	"build": "netlify-lambda build src/functions",
	"test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
	"netlify-lambda": "^1.6.3",
	"node-fetch": "^2.6.0"
  }
}

Running the build appears to work (no errors thrown and /function/fetchToken.js is written to disk):

Terminal output:

❯ npm run build

> fetch-token@1.0.0 build /Users/ollie/Repos/slack-status
> netlify-lambda build src/functions

netlify-lambda: Building functions
Hash: c777c9d03b51b2238e3b
Version: webpack 4.42.1
Time: 852ms
Built at: 04/26/2020 5:03:12 PM
		Asset      Size  Chunks             Chunk Names
fetchToken.js  18.6 KiB       0  [emitted]  fetchToken
Entrypoint fetchToken = fetchToken.js
[0] external "stream" 42 bytes {0} [built]
[1] external "zlib" 42 bytes {0} [built]
[2] external "url" 42 bytes {0} [built]
[3] external "http" 42 bytes {0} [built]
[4] external "https" 42 bytes {0} [built]
[5] ./fetchToken.js 978 bytes {0} [built]
[6] /Users/ollie/Repos/slack-status/node_modules/node-fetch/lib/index.mjs 39.9 KiB {0} [built]

Once deployed to git, when I call the function, it complains:

{
  "errorMessage": "Error: Cannot find module 'node-fetch'\nRequire stack:\n- /var/task/fetchToken.js\n- /var/runtime/UserFunction.js\n- /var/runtime/index.js", 
  "errorType": "Runtime.ImportModuleError", 
  "trace": [
	"Runtime.ImportModuleError: Error: Cannot find module 'node-fetch'", 
	"Require stack:", 
	"- /var/task/fetchToken.js", 
	"- /var/runtime/UserFunction.js", 
	"- /var/runtime/index.js", 
	"    at _loadUserApp (/var/runtime/UserFunction.js:100:13)", 
	"    at Object.module.exports.load (/var/runtime/UserFunction.js:140:17)", 
	"    at Object.<anonymous> (/var/runtime/index.js:43:30)", 
	"    at Module._compile (internal/modules/cjs/loader.js:1158:30)", 
	"    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1178:10)", 
	"    at Module.load (internal/modules/cjs/loader.js:1002:32)", 
	"    at Function.Module._load (internal/modules/cjs/loader.js:901:14)", 
	"    at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:74:12)", 
	"    at internal/main/run_main_module.js:18:47"
  ]
}

Where is the gap in my understanding? Any pointers are very welcome!

Hey! This post should have all that you seek:

Want to let us know if you continue to run into issues after taking a look and implementing the suggestion there?

Thanks for the pointer Jen, although it has left me more confused.

Looking at that post my mistake could be:

  • Compiling the function before deploying it. I should be zipping the whole node_modules function and shipping that (Isn’t the point of netlify-lambda to avoid the need for this?)
  • Using git to deploy – I should be using netlify deploy (The documentation suggests netlify-lambda is the best fit to compile a function, have I misread?)
  • Using node-fetch.
  • Not using encoding dependency with node-fetch (this appears to be an issue with the zip solution rather than netlify lambda which is a good clue as I am not expecting a build on the server at all! https://github.com/netlify/zip-it-and-ship-it/issues/30)

I commented out command = "npm run build" from my toml file.
Pushing this with the built function in place, and hitting the endpoint results in an error I understand:

ERROR	Invoke Error 	{"errorType":"ReferenceError","errorMessage":"Headers is not defined","stack":["ReferenceError: Headers is not defined","    at Runtime.t.handler (/var/task/fetchToken.js:1:1441)","    at Runtime.handleOnce (/var/runtime/Runtime.js:66:25)"]}

Headers is part of the fetch api I would expect node-fetch to provide. Seems the compile is not doing what I expected.

Other offered solutions don’t appear to apply to my case as my node_modules and package.json is in the root of my project, not in the functions directory.

I will persevere, seems a simple way forward is to avoid dependencies altogether!

Hi @Ollie, I’ve typically run into issues with node-fetch myself. Using zip it and ship it usually works better for me but I’ve seen reports that people using https://www.npmjs.com/package/isomorphic-fetch has had some success. Could you try using that and see if it works better?

Thank-you Dennis for taking the time to write, I’m back on the happy path by switching to isomorphic-fetch.
The built file is surprisingly large, but that is my browser served js bias talking, it is working!

1 Like