global modules in node.js - node.js

I have made a custom error class for throwing error in node.js. I want to use this class in my entire project. But the problem is wherever I need to use first I have to require in that file and then use this class which is quite tedious. Anyone any idea how to make it global so that all the modules can use it without requiring it in every file.
This is a custom error class file "cti_error.js"
'use strict';
class CTIError extends Error {
constructor (status,message,details='') {
super(message)
this.name = status
Error.captureStackTrace(this, this.constructor);
this.status = status || 500;
this.details = details?details:message;
this.reason = message;
}
}
module.exports = CTIError;
My project structure:-
my_project
|
|____utility
| |
| |____cti_error.js
|
|____routes
| |
| |_____product.js
| |_____defects.js
|
|
|_____server.js
The solution what I know is to require the custom error class as below in every file where I want to throw an error:-
const cti_error = require('../../utility/cti_error.js');
throw new cti_error(403,"wrong details");
Any idea how to use cti_eror without requiring in every file?

You can assign it to nodejs's global variable.
Like this:
global.CTIError = CTIError;
Now you can access the CTIError anywhere as:
new CTIError()
Your linter might tell you that CTIError is not declared though.

Related

Node repl module not found

I am trying to write a simple node script with some classes.
I first define a class
export default class Checkout() {
constructor () {
console.log('checkout')
}
check() {
console.log('check')
}
}
Then I am trying to use it
>node
>repl
check = new Checkout()
Uncaught ReferenceError: Checkout is not defined
require('Checkout')
Uncaught Error: Cannot find module 'Checkout'
How can I solve this? I am coming from Ruby where the console is pretty straight forward.
Code in a file isn't included in any other scope outside of that file until you require or import the file. When requiring/importing, the name the object you exported from the file doesn't automatically get used, you still have to specify it.
However, you're currently mixing require (CommonJS module format) with export default (ECMAScript Module format). There is only very limited interoperability between these formats using dynamic import(), but it's not yet available in the Node REPL (open issue here). If you need to test your Checkout class in the REPL, you'd need to just switch to using CommonJS:
module.exports = class Checkout() {
constructor () {
console.log('checkout')
}
check() {
console.log('check')
}
}
Usage:
> Checkout = require('checkout.js')
> check = new Checkout()

How to set global modules in multiple node.js files

I have a project which i'm working on, but i realised it was over 2000 lines and wanted to split it up into different files for different group of functions. eg. send message and read message functions are in message.js. The problem is that i need alot of modules in each of the files and if i create an instance of the module, i will need to create a new instance in another file, but i want to use the same instance!
I've tried module.exports = { ... } and exports.function() to pass the modules and instances to other files but sometimes it says that the function does not exist.
For example in my app.js file:
const module = require('module')
instance = new module()
const message = require('./message.js')
message.passModule(instance)
And in my message.js file:
let module-instance
exports.passModule = function(instance) {
module-instance = instance
}
module-instance.doSomething()
So, how could I have all the modules to be available in all the files, but only declare them in one, and how do I get the instance I made in one File to be able to be used in the other Files?
Some library file
singleton/file.js
const someDependency = require('some-module');
class Singleton {
method() {
...
return someDependency.someFunctionality();
}
...
}
module.exports = new Singleton();
Someplace where you want to use your singleton
const singleton = require('singleton/file');
singleton.method();

Mocking a custom node module using jest.mock method

So, I am new to mocking a module using jest.mock()
So here is the scenario, I have created a node module and uploaded to the private npm registry from where I can that module in my app.
If suppose the name of the module is #a/lp-mod and if this the index.js of that module:
export const lpr = async () => {
// some code that does something and returns some data back
}
export default {
lpr
}
now let us all suppose I need to mock this module (#a/lp-mod) and have to return some static data whenever lpr function is gets called in the context of a test case.
So here is the code I have written:
> proj_directory
|---->__mocks__
| |--->#a
| | |--->lp-mod --> this directory has index.js with mock data
|---->node_modules
| |--->#a
| | |--->lp-mod --> this directory has index.js inside /src
| | |---> src
| | | |---> index.js
|---->test
| |--->1.test.js --->
node_modules/#a/lp-mod/src/index.js
// some npm imports like axios
export const lpr = async () => {
// has some I/O calls, but let's just keep it simple
return Promise.resolve('I am original call')
}
export default {
lpr
}
__mocks__/#a/lp-mod/index.js
const p = jest.genMockFromModule('#a/lp-mod')
p.lpr = () => Promise.resolve('This is mocked call')
export default p
1.test.js
// before describe (test case) I wrote this
jest.mock('#a/lp-mod')
But I am getting undefined when the file is trying to import the original #a/lp-mod module for the usage inside the test context.
As per my expectation, it should get the mocked module and return the data from there only, if I am testing my app.
Please shed some light & bear with me incase some of the info is missing, please let me know in case there is any doubt.
Happy coding :)

Dynamically exporting functions in firebase

I'm having the typical (according to many posts) issue with cold boot times in cloud functions. A solution that seemed promised suggests to import / export only the function actually being executed, as can be seen here:
https://github.com/firebase/functions-samples/issues/170#issuecomment-323375462
if (!process.env.FUNCTION_NAME || process.env.FUNCTION_NAME === 'sendFollowerNotification') {
exports.sendFollowerNotification = require('./sendFollowerNotification');
}
Which is a Javascript example, but I'm using typescript. I've tried a number of variations, and while some build, in the end I'm always stuck with my function not being exported and deploy warning me that I'm going to delete the existing function.
This is one of the numerous attempts:
if (!process.env.FUNCTION_NAME || process.env.FUNCTION_NAME === 'generateInviteURL') {
import ('./invite_functions').then ((mod) => { console.log ("mod follows" ); console.log (mod); exports.generateInviteURL = functions.https.onRequest( mod.generateInviteURL ); } )
.catch ((err) => {console.log ("Trying to import/export generateInviteURL ", err);}) ;
}
At mentioned, at deploy time what happens is that I get a warning about the function being deleted.
I was able to "avoid" that message with something like this:
console.log ("Function name: ", process.env.FUNCTION_NAME);
function dummy_generateInviteURL (req, res) { ; }
exports.generateInviteURL = functions.https.onRequest( dummy_generateInviteURL );
if (!process.env.FUNCTION_NAME || process.env.FUNCTION_NAME === 'generateInviteURL') {
console.log ("Doing the good import");
import ('./invite_functions').then ((mod) => { console.log ("mod follows" ); console.log (mod); exports.generateInviteURL = functions.https.onRequest( mod.generateInviteURL ); } )
.catch ((err) => {console.log ("Trying to import/export generateInviteURL ", err);}) ;
}
console.log ("Exported");
console.log (exports.generateInviteURL);
Which the idea of course that an empty function would be always be exported but would be replaced with the real one if that's the one being called.
In that case logs look like this:
generateInviteURL Function name: generateInviteURL generateInviteURL
generateInviteURL Exported generateInviteURL
{ [Function: cloudFunction] __trigger: { httpsTrigger: {} } }
So the first part looks promising (the environment variable is defined), then the import does something (enters the then block, never the catch), but the exported variable is not replaced.
I'm not sure if this is a TypeScript problem, a firebase problem, or a developer problem - probably I'm just missing something obvious.
So the question - how can I avoid importing/exporting anything I don't need for each specific function?
You can stick to the original index.js, with minor changes. I have tried a few times and came with a solution. Am including a sample dir structure and two typescript files (index.ts and another for your custom function). With this you will never have to change the index.ts to modify or add functions.
Directory Structure
+ functions
|
-- + src
| |
| -- index.ts
| |
| -- + get
| |
| -- status.f.ts
-- package.json (auto generated)
|
-- package-lock.json (auto generated)
|
-- tsconfig.json (auto generated)
|
-- tslint.json (auto generated)
|
-- + lib (auto generated)
|
-- + node_modules (auto generated)
src/index.ts
import * as glob from "glob";
import * as camelCase from "camelcase";
const files = glob.sync('./**/*.f.js', { cwd: __dirname, ignore: './node_modules/**'});
for(let f=0,fl=files.length; f<fl; f++){
const file = files[f];
const functionName = camelCase(file.slice(0, -5).split('/').join('_')); // Strip off '.f.js'
if (!process.env.FUNCTION_NAME || process.env.FUNCTION_NAME === functionName) {
exports[functionName] = require(file);
}
}
src/get/status.f.ts
import * as functions from 'firebase-functions';
exports = module.exports = functions.https.onRequest((req, res) => {
res.status(200).json({'status':'OK'})
})
Once you have created the above file install npm packages 'glob' and 'camelcase',
then try to deploy the firebase functions
Firebase will deploy a function named 'getStatus'
NOTE that the name of the function is camel case version of folder names and the file name where the function exists, so you can export only one function per .f.ts file
EDIT
I have updated the dir structure. Note that index.ts and all the subsequent files and folders resides within the parent folder 'src'
I've been having similar issues, and I wrote a pretty cool solution that worked for me.
I decided to release it as an open-source package - I've never done that before so if anyone can check it out, contribute or give feedback that would be great.
The package is called better-firebase-functions - https://www.npmjs.com/package/better-firebase-functions
All you have to do is import and run it. Two lines. Pretty much everything else is automated.
It will pick up the default exports of all function files in your directory and deploy them as properly named functions.
Here is an example:
import { exportFunctions } from 'better-firebase-functions';
exportFunctions({
__filename, // standard node var (leave as is).
exports, // standard node var (leave as is).
functionDirectoryPath: './myFuncs', // define root functions folder
// relative to this file.
searchGlob: '**/*.js' // file search glob pattern.
});
The only other thing you need to do is export your function.http.onRequest()... as a default export from every file that contains a cloud function that you want to deploy. So:
export default functions.http.onRequest()...
/// OR
const func1 = functions.http.onRequest()...
export default func1;
And that's it!
UPDATE: Answer edited to reflect newer version of package.

Parent/Child class hierachy in nodejs

child.js
class Child {
constructor(){
this.helloWorld = "Hello World";
}
run() {
}
}
export default new Child();
parent.js
import child from './child.js';
class Parent {
constructor() {
this.child = child;
}
}
export default new Parent();
index.js
import parent from './parent.js'
console.log(parent.child.helloWorld); <-- does not throws an error, displays "Hello World"
console.log(parent.child.run); <-- throws an error (Cannot read property run from undefined)
console.log(parent.child.run()); <-- throws an error (Cannot read property run from undefined)
If I do console.log(parent.child) in index.js, run does not show up, however the property helloWorld does..
How can I have the functions exposed as well? I was hoping to be able to do this to help keep my code a bit more organized, so was going to separate it out into separate classes to help minimize the amount of code in each file.
To make one thing clear from the start: The error you seem to get has nothing to do with run not appearing in the console.log output.
If your code really throws that error then that means that the value of parent.child is undefined. Hence when you call console.log(parent.child), you should see undefined, not an object. However, I don't see why you'd get that error.
Anyways, run is defined on the prototype of parent.child, not on itself. console.log most likely shows an object's own properties (the console API is not standardized, so results can vary between environments). That's normal.
Simple example to reproduce:
var foo = {
x: 42
};
var bar = Object.create(foo);
bar.y = 21;
console.log(bar, bar.x, bar.y);
// Open the browser console to see output
bar.x is accessible even though console.log doesn't show it (in Chrome at least).
Well I'm not sure if helps you to solve the problem, but whenever I want to add inheritance, I use extends and super here is an example:
Base Class:
class BaseDataModel {
constructor() {
}
getModel() {
return 'model';
}
module.exports.BaseDataModel = BaseDataModel;
Class extending Base Class:
"use strict"
// Imports
const BaseDataModel = require('../baseDataModel').BaseDataModel; // use the proper location
class UserMembershipModel extends BaseDataModel {
constructor() {
super(); // this is optional, I use this to inherit the constructors
}
getChildModel() {
return super.getModel(); // This is how you access the function from your extended class
}
module.exports.UserMembershipModel = UserMembershipModel;
Again, not sure if it solves your problem, since your actually adding a property with a Child class. My example is actually extending (or UserMembershipModel inherits from BaseDataModel).
Hope this helps you a bit.

Resources