How to use custom modules in Twilio Functions? - node.js

I was looking for a way to simplify and extract some of the code into a custom common.js module to make my Twilio function more readable.
I was expecting the serverless api to take the custom js file automatically and let me require it where I wanted it, but after deploying, it cant be found.
Is there a proper way if any, to do something like:
const utils = require('./libs/utils.js');
exports.handler = async function(context, event, callback) {
...
utils.do_this();
Trying this brings me to:
{"Message":"Cannot find module './libs/utils.js'\nRequire stack:\n- /var/task/handlers/ZN5be18c53f5acf0299a224607fdeccedb.js\n- /var/task/node_modules/runtime-handler/index.js\n- /var/task/runtime-handler.js\n- /var/runtime/UserFunction.js\n- /var/runtime/index.js","name":"Error","stack":"Error: Cannot find module './libs/utils.js'\nRequire stack:\n- /var/task/handlers/ZN5be18c53f5acf0299a224607fdeccedb.js\n- /var/task/node_modules/runtime-handler/index.js\n- /var/task/runtime-handler.js\n- /...

Swimming deep in Twilio's doc swamp, I noticed there is a hint on how to do this.
Basically you MUST
Add the .js file as an PRIVATE ASSET <- IMPORTANT! *unprotected wont work!
i.e. if your file name is utils.js, rename it to utils.private.js
Get the path of that asset in the following way:
// notice you don't need to write .private.
const path = Runtime.getAssets()['/utils.js'].path;
Require the path inside the handler:
exports.handler = async function(context, event, callback) {
const path = Runtime.getAssets()['/utils.js'].path;
const utils = require(path);

Related

Why isn't my Node package being imported?

I'm learning Node.js and am using a Node-based Azure Function.
I'm trying to bring in Chalk, to log coloured messages to the console.
However, all of the below fail (in my main index.js file).
One
module.exports = async (ctx, req) => {
const chalk = require('chalk');
return console.log(chalk.blue('Hello world!'));
Despite being the approach recommended in this answer, this results in a console error that says:
Exception: require() of ES Module C:...\node_modules\chalk\source\index.js from C:...\index.js not supported.
Instead change the require of C:...\chalk\source\index.js in C:...\index.js to a dynamic import() which is available in all CommonJS modules.
Two
If I do as the error suggests, and use
const chalk = async import('chalk')
...I then get
Exception: chalk.blue is not a function
...even though console.log(chalk) does seem to show the Chalk API and its various properties.
Three
The Chalk docs themselves recommend this:
module.exports = async (ctx, req) => {
import chalk from 'chalk'
return console.log(chalk.blue('Hello world!'));
That yields an error saying I can't use import outside of a module (but surely I'm in one?)
Four
Same as three ^^ but moving the import outside module.exports:
import chalk from 'chalk'
module.exports = async (ctx, req) => {
return console.log(chalk.blue('Hello world!'));
...yields the same error.
I'm sure this is a basic error but I can't find what I'm doing wrong so I'd be so grateful if someone could help. Thank you!
When you import something using import as a function(lazy import), It'll return an object with a default property and all exported properties. That you should use to access the module.
const module = async import('chalk')
const chalk = module.default
console.log(chalk.red('Hello world!'))

How to import a JSON object from an AWS Lambda Layer?

This may seem simple but I have had a hard time trying to figure it out. I could not seem to find the solution on the web too.
//nodejs/models.js:
// City = ...
// ...
module.exports = {City, Country, Coupon, Player, Pollfish, Tree};
After zipping nodejs, I uploaded the zip file as an AWS Layer and added the layer to my Lambda function.
When I tried to retrieve the objects in my Lambda function:
import { createRequire } from 'module';
const require = createRequire(import.meta.url);
const {Player} = require('./models.js');
It resulted in an error:
2023-01-06T09:19:49.469Z undefined ERROR Uncaught Exception {"errorType":"Runtime.ImportModuleError","errorMessage":"Error: Cannot find module 'models.js'\nRequire stack:\n- /var/task/index.mjs","stack":["Runtime.ImportModuleError: Error: Cannot find module 'models.js'","Require stack:","- /var/task/index.mjs"," at _loadUserApp (file:///var/runtime/index.mjs:1000:17)"," at async UserFunction.js.module.exports.load (file:///var/runtime/index.mjs:1035:21)"," at async start (file:///var/runtime/index.mjs:1200:23)"," at async file:///var/runtime/index.mjs:1206:1"]}
So what should be the proper way to do it?
I got it! It should be:
const {Player} = require('/opt/nodejs/models.js');

How to create an import/export script using Node.JS?

I'm looking to import/export a list of files in a directory through an index.js file in the same directory.
For example, I have 2 files in a directory: admin.js and user.js and I am looking to require and exporting them in the in the index.js like so
module.exports = {
admin: require("./admin"),
users: require("./users"),
};
The script I have come up with looks like this but it is not working and giving me an error
fs.readdirSync(__dirname, (files) => {
files.forEach((file) => {
module.exports[file] = require(`./${file}`);
});
});
How can I improve this script to make it work?
Thank you!
[Update - 2022 December 18]
Found a solution based off of sequelize models/index.js, this will pretty much require and export your files and folders, feel free to use and modify
const fs = require('fs')
const path = require('path')
const basename = path.basename(__filename)
const controllers = {}
fs.readdirSync(__dirname)
.filter((folder) => {
return folder.indexOf('.') !== 0 && folder !== basename
})
.forEach((folder) => {
const controller = require(path.join(__dirname, folder))
controllers[controller.name] = controller
})
module.exports = controllers
fs.readdirSync() does NOT accept a callback. It directly returns the result:
const files = fs.readdirSync(__dirname);
for (let file of files) {
module.exports[file] = require(`./${file}`);
}
Note, the future of the Javascript language is using import and export with statically declared module names instead of require()and module.exports and this structure will generally not work with the newer way of doing things. So, if you expect to eventually move to the newer ESM modules, you may not want to bake in this type of architecture.
There is a dynamic import in ESM modules, but it's asynchronous (returns a promise that you have to wait for).
Also, note that this will attempt to reload your index.js file containing this code. That's might not be harmful, but may not be your intention.

Node js - Issue with my syntax in require(module) . When to use {} and when not to use {} in require('module')

I have a query with the syntax in the require statement. Please refere the sample code below.
const nodemailer = require("nodemailer");
const {google} =require('googleapis');
const {OAuth2}=google.auth;
Some times , I see sample codes which use
const {<variable>} = require('moduleName')
Other times, I see like below
const <variable> = require('moduleName')
What is the difference between them?
Thanks in Advance.
Grateful to the Developers Community.
So, you use { } in this context when you want to do object destructuring to get a property from the exported object and create a module-level variable with that same name.
This:
const { google } = require('googleapis');
is a shortcut for this:
const __g = require('googleapis');
const google = __g.google;
So, within this context, you use the { google } only when you want the .google property from the imported module.
If you want the entire module handle such as this:
const nodemailer = require("nodemailer");
then, you don't use the { }. The only way to know which one you want for any given module is to consult the documentation for the module, the code for the module or examples of how to use the module. It depends entirely upon what the module exports and whether you want the top level export object or you want a property of that object.
It's important to realize that the { } used with require() is not special syntax associated with require(). This is normal object destructuring assignment, the same as if you did this:
// define some object
const x = { greeting: "hello" };
// use object destructuring assignment to create a new variable
// that contains the property of an existing object
const { greeting } = x;
console.log(greeting); // "hello
When you import the function with {}, it means you just import one function that available in the package. Maybe you have've seen:
const {googleApi, googleAir, googleWater} = require("googleapis")
But, when you not using {}, it means you import the whole package, just write:
const google = require("googleapis")
So, let say when you need googleApi in your code. You can call it:
google.googleApi

Nodejs - Create modules from string with the npm package 'module'

I want to load a custom module using the npm package 'module', to be able to require it like any other local folder that exports something.
I cannot find any documentation on the use of the package https://www.npmjs.com/package/module
I tried to use it without any documentation on it, but i simply cannot as i dont understand how you use it.
let myFunction = module.wrap(`module.exports = () => console.log("hej")`);```
Honestly, I've never read documentation about this but I've been using Node.js for years so I'll explain how I import modules. Given a project that has the files app.js and mod1.js and the subfolder utils with the file mod2.js, you could do something like this:
prj/mod1.js
module.exports = {
test: "testing"
}
prj/utils/mod2.js
module.exports = () => {
console.log("testing");
}
prj/app.js
var mod1 = require("mod1"),
mod2 = require("utils/mod2");
console.log(mod1.test);
mod2();
I think you are trying to create a module of your own to be able to use it at multiple places within your project ( correct me if I am wrong).
SO you can do that like :
In utils/custom.js
module.exports = {
logThis: "Hi"
}
OR
var a={
logThis:function (){
console.log('HI')
}
module.exports=a;
And then in the file where you want to access this :
In app.js
let custom=require('./utils/custom.js')

Resources