Require a file once and use it everywhere - node.js

I've read up on module.exports and how it works but I'm not sure if I can accomplish what I want with it - or at least I'm not sure how to. I have some helper functions in a file, one of which is used in a majority of files in my project. I'm wondering if it is possible to just "require" the file one time and then just use it across the entirety of the project when needed.
My file looks something like this:
discord-utils.js
const { MessageEmbed, Permissions } = require('discord.js')
module.exports = {
embedResponse (message, embedOptions, textChannel = null) {
const embed = new MessageEmbed()
if (embedOptions.color) embed.setColor(embedOptions.color)
if (embedOptions.title) embed.setTitle(embedOptions.title)
if (embedOptions.description) embed.setDescription(embedOptions.description)
if (embedOptions.url) embed.setURL(embedOptions.url)
if (embedOptions.author) embed.setAuthor(embedOptions.author)
if (embedOptions.footer) embed.setFooter(embedOptions.footer)
if (embedOptions.fields) {
for (const field of embedOptions.fields) {
embed.addFields({
name: field.name,
value: field.value,
inline: field.inline ? field.inline : false
})
}
}
if (textChannel) {
textChannel.send(embed)
return
}
message.embed(embed)
},
inVoiceChannel (voiceState, message, response = null) {
if (!voiceState.channel) {
this.embedResponse(message, {
color: 'RED',
description: response === null ? 'You need to be in a voice channel to use this command.' : response
})
console.warn(`${message.author.tag} attempted to run a music command without being in a voice channel.`)
return false
}
return true
},
isAdminOrHasPerms (user, permissionRole) {
return user.hasPermisssion(Permissions.FLAGS.ADMINISTRATOR) || user.hasPermission(permissionRole)
}
}
In pretty much every other file, I use the embedResponse function. So in the project I have to do require('discord-utils) and then do things like: discordUtils.embedResponse(blahblah...) and while that's fine, it seems really redundant since I know I'm going to be using it just about everywhere. I'm wondering if there's a way I can just use one require statement and pull the functions I need at any time?

You may define a globally accessible variable using the global object in NodeJS. However, this neither a common nor a recommended pattern in NodeJS.
global.foo = 1 // make the foo variable globally accessible
https://nodejs.org/api/globals.html#globals_global

Node.js actually has a neat little caching system that can be taken advantage of to achieve a singleton effect. The first time you require a file, it runs and sets module.exports. Every time you require that same file afterwards, it will return a reference to the same object that was returned the fist time, instead of actually re-executing.
There are some caveats though. It's not always a guarantee that the file won't execute a second time. For example sometimes if you require the file from a very different location far from the first one, it might re-execute the file. Like if you first required the file as require('./my-file') and later require it with require('../../../../my-file'), it could sometimes re-execute it and clear the cached reference.

Related

Is it possible to get all variables in scope through typescript?

I know there is an old post about this functionality in javascript: Getting All Variables In Scope
But I am desperately looking and thought I'd just ask in case there might be transpile magic in typescript (or a way we can extend it) that may acheve this..(e.g.)
.ts
() => {
const a = 123;
console.log(scope)
}
.js transpile
var scope = {};
() => {
scope.a = 123;
console.log(scope);
}
The reason I'm asking is that I'm looking for a node backend solution to be able to log a function's scope state and save it in a debug database for review. (So any time an error occurs the state is never lost but recorded instead)
#k0pernikus
Getting specific on my issue, I'm trying to get more context on what went wrong with my handler for a firebase event. functions.firestore.document('users/{uid}').onUpdate
// ====== Pretend code I wish would work =====
const logScopeSomewhere = (anonymousScope) => (err) => {
console.log(anonymousScope) // { pie: 'pie', apple: 'apple' }
// or write error to database..
// Main goal is that all variables in the function that errored are logged with the Type Error..
}
const handleUpdate = (change: Change<QueryDocumentSnapshot>, context: EventContext) => {
let anonymousScope;
return (async () => {
anonymousScope = scope; // special reserved - // Possible JS transpile manipulation can have a closure on top..
const pie = 'pie'; // anonymousScope.pie
const apple = 'apple'; // anonymousScope.apple
// apple.core.seed - // TypeError (will go to catch..)
})().catch(logScopeSomewhere(anonymousScope))
}
functions.firestore.document('users/{uid}').onUpdate(handleUpdate)
Trying to be more clear, I want to have an object that has a snapshot of the state of the executing function when the error occurred. I plan to catch it and will use it as logging information.
I don't think V8 exposes scope information in any other way than through DevTools.
You can parse your own source code, which lets you do any analysis you want. See this answer to the old question you linked for an example.
The TypeScript compiler must be doing the same analysis already internally, so I'm pretty sure it could be extended to dump that information. For example, it should be possible to extend the TypeScript language with a scope keyword (or whatever) that gets compiled to a JS object containing all in-scope variables and their values. That said, I have no idea whether something like that already exists, or how one would go about adding it.

FIrebase Firestore onCreate Cloud Function: Object unidentified [duplicate]

I'm building a cloud function that will use the Stripe API to process payments. This is within a firebase project. When I run firebase deploy I get the error "Object is possible 'undefined'" const existingSource = customer.sources.data.filter( (s) => s.id === source).pop();
I'm not sure how to resolve this.
Here is my xxx.ts where getorCreateCustomer exists
/** Read the stripe customer ID from firestore, or create a new one if missing */
export const getOrCreateCustomer = async(uid: string) => {
const user = await getUser(uid);
const customerId = user && user.stripeCustomerId;
//if missing customerId, create it
if (!customerId) {
return createCustomer(uid);
}
else {
return stripe.customers.retrieve(customerId);
}
}
Based on the definitions and contents of your functions, TypeScript is unable to infer the return type of getOrCreateCustomer. It is making the assumption that it could return undefined, and its strict mode is calling you out on the fact that you could be referencing a property on an undefined object, which would result in an error at runtime.
What you need to do is declare the return type to be something that can't possibly be undefined, and make sure the code in the body of the function is correct on that guarantee (otherwise you'll get a new error).
If you can't do that (but you really should do that), you might want to instead disable strict mode in your tsconfig.json file, since that is what's enforcing this level of correctness in your code.
I suggest the first option, even if you have to write more lines of code, as it's a better use of TypeScript's typing system.
What #Doug mentioned, but also you could write your logic to make sure that every part of customer.sources.data is not undefined...
ie:
const { sources } = customer
if (sources) {
const { data } = sources
if (data) {
// then filter / etc etc ...
}
}
7 months later, I figured out the best solution.
I simply wrapped the the contents of the firebase callable function in the following if/else statement. It's a bit redundant but it works.
if (!context.auth) {
// Throwing an HttpsError so that the client gets the error details.
throw new functions.https.HttpsError('failed-precondition', 'The function must be called ' +
'while authenticated.');
}
else{ ...copy function code here }
If you don't care about the authentication piece you can simply define the type of context as any.
(data, context:any)
Open tsconfig.json and add "strictNullChecks": false to angularCompilerOptions object. It worked for me.
{
...
"angularCompilerOptions": {
"strictNullChecks": false,
...
}
}

How do I make sure an aggregate exists before publishing an event?

I was looking through the Wolkenkit API ... and it's not 100% clear how to know which commands require an aggregate ID and which ones do not.
From what I can tell, the client api offers something like this
app.accounting.invoice().issue({
amount: 1000
});
which is fine for creating a new invoice, but it shouldn't be possible to run the following that intends to update something that exists
app.accounting.invoice().update({
amount: 10
});
I assume this check should go into the command function, but how do I write it?
const commands = {
update (invoice, command, mark) {
const canInvoiceBeUpdated = // ...
if (!canInvoiceBeUpdated) {
return mark.asRejected('...');
}
// ... update invoice
mark.asDone();
}
};
What goes into canInvoiceBeUpdated check?
Answered 2018-06-08 by #goloroden in the wolkenkit slack
I'll try to explain it to you: If you want a new aggregate, you omit the ID. So, e.g., to stick with the chat example, when you want to send a new message you do:
app.communication.message().send({ /* ... */ });
If, instead, you want to edit an existing message, e.g. to like it, then you have to provide the ID of the message:
const messageId = '...';
app.communication.message(messageId).like({ /* ... */ });
Within every command you will probably want to check that it only works on a new aggregate (which we call a constructor command) or only on an existing aggregate. The easiest way to check this is to use the aggregate's exists function, which returns true for new aggregates, and false otherwise. So, inside of a command, you could do something like this:
const commands = {
send (message, command, mark) {
if (!message.exists()) {
return mark.asRejected('Aggregate does not exist yet.');
}
// ...
mark.asDone();
}
};
If you don't want to do this manually every time, you could also use a middleware for this, such as https://github.com/thenativeweb/wolkenkit-command-tools … then the previous example comes down to:
const { only } = require('wolkenkit-command-tools');
// ...
const commands = {
send: [
only.ifExists(),
(message, command, mark) {
// ...
mark.asDone();
}
]
};
Please note that the current version of this middleware module is 3.0, but that until wolkenkit 2.0 will be released, you will have to use version 2.0 of wolkenkit-command-tools.

Node.js: should I keep `assert()`s in production code?

A methodological question:
I'm implementing an API interface to some services, using node.js, mongodb and express.js.
On many (almost all) sites I see code like this:
method(function(err, data) {
assert.equal(null, err);
});
The question is: should I keep assert statements in my code at production time (at least for 'low significance' errors)? Or, are these just for testing code, and I should better handle all errors each time?
You definitively should not keep them in the production environment.
If you google a bit, there are a plethora of alternative approaches to strip out them.
Personally, I'd use the null object pattern by implementing two wrappers in a separate file: the former maps its method directly to the one exported by the module assert, the latter offers empty functions and nothing more.
Thus, at runtime, you can plug in the right one by relying on some global variable previously correctly set, like process.env.mode. Within your files, you'll have only to import the above mentioned module and use it instead of using directly assert.
This way, all around your code you'll never see error-prone stuff like myAssert && myAssert(cond), instead you'll have ever a cleaner and safer myAssert(cond) statement.
It follows a brief example:
// myassert.js
var assert = require('assert');
if('production' === process.env.mode) {
var nil = function() { };
module.exports = {
equal = nil;
notEqual = nil;
// all the other functions
};
} else {
// a wrapper like that one helps in not polluting the exported object
module.exports = {
equal = function(actual, expected, message) {
assert.equal(actual, expected, message);
},
notEqual = function(actual, expected, message) {
assert.notEqual(actual, expected, message);
},
// all the other functions
}
}
// another_file.js
var assert = require('path_to_myassert/myassert');
// ... your code
assert(true, false);
// ... go on
Yes! asserts are good in production code.
Asserts allow a developer to document assumptions that the code makes, making code easier to read and maintain.
It is better for an assert to fail in production than allow the undefined behaviour that the assert was protecting. When an assert fails you can more easily see the problem and fix it.
Knowing your code is working within assumptions is far more valuable than a small performance gain.
I know opinions differ here. I have offered a 'Yes' answer because I am interested to see how people vote.
probably no
ref: When should assertions stay in production code?
Mostly in my code i put error handling function in a separate file , and use same error method everywhere, it mostly depends on logic anyways
like ppl generally forget this
process.on('uncaughtException', function (err) {
console.log(err);
})
and err==null doesn't hurts , it checks both null and undefined

Get all defined variables in scope in node.js

I am trying to get all the variables that have been defined, i tried using the global object
but it seems to be missing the ones defined as var token='44'; and only includes the ones defined as token='44';. What i am looking for idealy is something like the get_defined_vars() function of php. I need to access the variables because i need to stop the node process and then restart at the same point without having to recalculate all the variables, so i want to dump them somewhere and access them later.
It's impossible within the language itself.
However:
1. If you have an access to the entire source code, you can use some library to get a list of global variables like this:
var ast = require('uglify-js').parse(source)
ast.figure_out_scope()
console.log(ast.globals).map(function (node, name) {
return name
})
2. If you can connect to node.js/v8 debugger, you can get a list of local variables as well, see _debugger.js source code in node.js project.
As you stated
I want to dump them somewhere and access them later.
It seems like you should work towards a database (as Jonathan mentioned in the comments), but if this is a one off thing you can use JSON files to store values. You can then require the JSON file back into your script and Node will handle the rest.
I wouldn't recommend this, but basically create a variable that will hold all the data / variables that you define. Some might call this a God Object. Just make sure that before you exit the script, export the values to a JSON file. If you're worried about your application crashing, perform backups to that file more frequently.
Here is a demo you can play around with:
var fs = require('fs');
var globalData = loadData();
function loadData() {
try { return require('./globals.json'); } catch(e) {}
return {};
}
function dumpGlobalData(callback) {
fs.writeFile(
__dirname + '/globals.json', JSON.stringify(globalData), callback);
}
function randomToken() {
globalData.token = parseInt(Math.random() * 1000, 10);
}
console.log('token was', globalData.token)
randomToken();
console.log('token is now', globalData.token)
dumpGlobalData(function(error) {
process.exit(error ? 1 : 0);
});

Resources