5

I have 3 separate functions each in their own folders. All of them make use of a Twilio client and Apollo Client for dealing with SMS and GraphQL server respectively.

Rather than having all the code to instantiate each client (get keys from env etc.) in each file, can it be put somewhere and required in?

I've tried putting the code into a .js file in the top level functions/ folder and requiring it in the function code as below and this works fine locally on netlify dev but errors with Module not found '../twilioClient' when the function is called in live environment.

/functions
  apolloClient.js
  twilioClient.js
  package.json - specifying deps used by above files
  /auth
    auth.js - require('../apolloClient')
    ...
  /trails
    trails.js - require('../twilioClient') etc.
    ...
Jon Wyatt
  • 1,786
  • 1
  • 11
  • 16
  • Have just tried packaging up the js files by moving them to own directory and `npm init` then listing them in the top level package.json dependencies like `"apollo-client": "file:./apollo-client"`. Again this works locally andI can reuse the modules across all functions with `const apolloClient = require('apollo-client')` however same error in live environment – Jon Wyatt Feb 11 '20 at 09:29

4 Answers4

3

I had success with this approach.

Short answer:

Create a utils file in your functions folder and require it in your function files.

Long answer:

My netlify.toml file looks like this:

[build] 
    functions = "./functions"

And functions folder:

/functions
 function-1.js
 function-2.js
 utils.js

And utils.js:

exports.helloWorld = () => {
    console.log('hello world')
}

And function-1.js:

const {helloWorld} = require('./utils')

exports.handler = async (event) => {
  helloWorld()
}

To test it:

Run netlify dev or deploy it. Your Functions logs or terminal should say 'hello world'.

My netlify site deploys from GitHub.

nth-child
  • 402
  • 8
  • 15
2

I did get some success (locally & live) in putting shared modules in a local npm package:

/functions
  /utils
    package.json
    index.js
  /src
    /auth
      auth.js
    /trails
      trails.js
  package.json

Export all common modules in functions/utils/index.js and set property "main": "index.js" in functions/utils/package.json.

In functions/package.json install the module:

{
  "dependencies": {
    ...
    "utils": "file:utils"
  }
}

And import it in your functions (in functions/src/auth/auth.js): import { apolloClient, twilioClient } from "utils"

Please take a look at this repository for reference.

nomadoda
  • 4,561
  • 3
  • 30
  • 45
  • Thanks, I'm sure I tried something similar but will try this out and report back. I've been using a hacky workaround involving a prebuild script that copies the shared code to all the directories that use it! – Jon Wyatt May 14 '20 at 18:56
  • Oh please share that as well! :) – nomadoda May 15 '20 at 19:17
1

Posting my interim solution in case it helps before I get a chance to try out @nomadoda's answer.

My functions folder looks like this

/functions
  /utils
    apolloClient.js
    twilioClient.js
  /receive-sms
  /auth
  /stripe
  /scripts

Where auth, scripts, receive-sms and stripe are my lambda functions.

I have "prebuild": "sh scripts/prebuild.sh" in my root package.json which looks like this:

cp -rf functions/utils functions/receive-sms
cp -rf functions/utils functions/auth
cp -rf functions/utils functions/scripts
cp -rf functions/utils functions/stripe

This is also where I cd into each lambda function folder and run yarn to install their dependencies.

Then in my function folders I can make use of the utils code by simply importing from the local /utils folder i.e. const apolloClient = require('./utils/apolloClient');

I also gitignore the copied /utils folders so only the master version of utils is tracked by git.

As I said, it's less than ideal but does work though I hope above answer works for me instead.

Jon Wyatt
  • 1,786
  • 1
  • 11
  • 16
0

For anyone else stumbling upon this issue, Netlify added support for esbuild back in April 2021. The specific change that I needed to add to my project was the configuration below in my netlify.toml file:

[functions]
  node_bundler = "esbuild"

After that, I was able to reference local shared files via either esmodules import/export statements or via commonjs require statements.

mralexlau
  • 1,823
  • 1
  • 16
  • 23