Can I expose a commonjs module object in the global namespace? - node.js

We're building a react/flux application using nodejs/webpack and therefore all of our new code is written in commonjs modules.
There are a few isolated cases where we need to access an object from one of our commonjs modules in legacy code. Is there any way to do this...and yes, I assume this is gross. We're eventually going to migrate all of our code to commonjs modules, but this is a stop-gap.

In the legacy JS code (non using CommonJS), create a function in the global namespace:
/* Legacy code NOT using CommonJS */
function getCommonJSObject(obj) {
...
}
In the CommonJS code you can test for this global function and if it exists, call it, passing whichever object you need access to.
/* CommonJS object */
if(window['getCommonJSObject']){
window.getCommonJSObject(obj);
}
By doing this we can still follow our flux pattern from legacy javascript code in our app. If there's a better way to do this, let us know. But this is a handy workaround.

Related

Node.js Globalize es6 modules to act like ImportScripts

The question is simple, how do we make es6 modules act like the ImportScript function used on the web browser.
Explanation
The main reason is to soften the blow for developers as they change their code from es5 syntax to es6 so that the transition does not blow up your code the moment you make the change and find out there are a thousand errors due to missing inclusions. It also give's people the option to stay as is indefinitely if you don't want to make the full change at all.
Desired output
ImportScript(A file path/'s); can be applied globally(implicitly) across subsequently required code and vise-verse inside a main file to avoid explicit inclusion in all files.
ES6 Inclusion
This still does not ignore the fact that all your libraries will depend on modules format as well. So it is inevitable that we will still have to include the export statement in every file we need to require. However, this should not limit us to the ability to have a main file that interconnects them all without having to explicitly add includes to every file whenever you need a certain functionality.
DISCLAIMER'S
(Numbered):
(Security) I understand there are many reasons that modules exist and going around them is not advisable for security reasons/load times. However I am not sure about the risk (if any) of even using a method like "eval()" to include such scripts if you are only doing it once at the start of an applications life and to a constant value that does not accept external input. The theory is that if an external entity is able to change the initial state of your program as is launched then your system has already been compromised. So as it is I think the whole argument around Globalization vs modules boils down to the project being done(security/speed needed) and preference/risk.
(Not for everyone) This is a utility I am not implying that everyone uses this
(Already published works) I have searched a lot for this functionality but I am not infallible to err. So If a simple usage of this has already been done that follows this specification(or simpler), I'd love to know how/where I can attain such code. Then I will promptly mark that as the answer or just remove this thread entirely
Example Code
ES5 Way
const fs = require('fs');
let path = require('path');
/* only accepts the scripts with global variables and functions and
does not work with classes unless declared as a var.
*/
function include(f) {
eval.apply(global, [fs.readFileSync(f).toString()])
}
Main file Concept example:
ImportScript("filePath1");loaded first
ImportScript("filePath2");loaded second
ImportScript("filePath3");loaded third
ImportScript("filePath4");loaded fourth
ImportScript("filePath5");loaded fifth
ImportScript("someExternalDependency");sixth
/* where "functionNameFromFile4" is a function defined in
file4 , and "variableFromFile2" is a global dynamic
variable that may change over the lifetime of the
application.
*/
functionNameFromFile4(variableFromFile2);
/* current context has access to previous scripts contexts
and those scripts recognize the current global context as
well in short: All scripts should be able to access
variables and functions from other scripts implicitly
through this , even if they are added after the fact
*/
Typical exported file example (Covers all methods of export via modules):
/*where "varFromFile1" is a dynamic variable created in file1
that may change over the lifetime of the application and "var" is a
variable of type(varFromFile4) being concatenated/added together
with "varFromFile4".
*/
functionNameFromFile4(var){
return var+varFromFile1;
}
//Typical export statement
exportAllHere;
/*
This is just an example and does not cover all usage cases , just
an example of the possible functionality
*/
CONCLUSION
So you still need to export the files as required by the es6 standard , however you only need to import them once in a main file to globalize their functionality across all scripts.
I'm not personally a fan of globalizing all the exports from a module, but here's a little snippet that shows you how one ESM module's exports can be all assigned to the global object:
Suppose you had a simple module called operators.js:
export function add(a, b) {
return a + b;
}
export function subtract(a, b) {
return a - b;
}
You can import that module and then assign all of its exported properties to the global object with this:
import * as m from "./operators.js"
for (const [prop, value] of Object.entries(m)) {
global[prop] = value;
}
// can now access the exports globally
add(1, 2);
FYI, I think the syntax:
include("filePath1")
is going to be tough in ESM modules because dynamic imports in an ESM module using import (which is presumably what you would have to use to implement the include() function you show) are asynchronous (they return a promise), not synchronous like require().
I wonder if a bundler or a transpiler would be an option?
There is experimental work in nodejs related to custom loaders here: https://nodejs.org/api/esm.html#hooks.
If you can handle your include() function returning a promise, here's how you put the above code into that function:
async function include(moduleName) {
const m = await import(moduleName);
for (const [prop, value] of Object.entries(m)) {
global[prop] = value;
}
return m;
}

How do the core modules in node.js work? (https://github.com/nodejs/node/blob/master/lib)

Does the node interpreter look for core modules (let's say "fs") within the node binary? If yes, are these modules packaged as js files. Are the core modules that are referenced within our code converted to c/c++ code first and then executed? For example, I see a method in the _tls_common.js (https://github.com/nodejs/node/blob/master/lib/_tls_common.js) file called "loadPKCS12" and the only place that I see this method being referenced/defined is within the "node_crypto.cc" file (https://github.com/nodejs/node/blob/master/src/node_crypto.cc). So how does node link a method in javascript with the one defined in the c/c++ file?
here is the extract from the _tls_common.js file that makes use of the "loadPKCS12" method:
if (passphrase) {
c.context.loadPKCS12(buf, toBuf(passphrase));
} else {
c.context.loadPKCS12(buf);
}
}
} else {
const buf = toBuf(options.pfx);
const passphrase = options.passphrase;
if (passphrase) {
c.context.loadPKCS12(buf, toBuf(passphrase));
} else {
c.context.loadPKCS12(buf);
There are two different (but seemingly related) questions asked here. The first one is: "How the core modules work?". Second one being "How does NodeJS let c++ code get referenced and executed in JavaScript?". Let's take them one by one.
How the core modules work?
The core modules are packaged with NodeJS binary. And, while they are packaged with the binary, they are not converted to c++ code before packaging. The internal modules are loaded into memory during bootstrap of the node process. When a program executes, lets say require('fs'), the require function simply returns the already loaded module from cache. The actual loading of the internal module obviously happens in c++ code.
How does NodeJS let c++ code get referenced in JS?
This ability comes partly from V8 engine which exposes the ability to create and manage JS constructs in C++, and partly from NodeJS / LibUV which create a wrapper on top of V8 to provide the execution environment. The documentation about such node modules can be accessed here. As the documentation states, these c++ modules can be used in JS file by requiring them, like any other ordinary JS module.
Your example for use of c++ function in JS (loadPKCS12), however, is more special case of internal c++ functionality of NodeJS. loadPKCS12 is called on a object of SecureContext imported from crypto c++ module. If you follow the link to SecureContext import in _tls_common.js above, you will see that the crypto is not loaded using require(), instead a special (global) method internalBinding is used to obtain the reference. At the last line in node_crypto.cc file, initializer for internal module crypto is registered. Following the chain of initialization, node::crypto::Initialize calls node::crypto::SecureContext::Initialize which creates a function template, assigns the appropriate prototype methods and exports it on target. Eventually these exported functionalities from C++ world are imported and used in JS-World using internalBinding.

Write a module that works both in nodejs and requirejs

I wrote a small parser that currently works in node app, but wondering if there is a way that I can make a module that will work both in NodeJS app and client side app that uses requirejs?
path/to/lib/index.js
function someRandom(strings) {
// we are doing something here
return strings
}
exports.someRandom = someRandom;
Right now I'm getting this in client-side
Uncaught ReferenceError: exports is not defined
I know that I can use node requirejs and then change the structure to use define but is there other way without adding node requirejs?
This is my js/main.js file
require(["path/to/lib/index"], function(something) {
// will do something here
});
The way I prefer to do it is to write all my modules in the AMD syntax (use define) and use amd-loader to load them in Node. Note that this solution is not using RequireJS, even though the AMD syntax is used.
However, there's a way to do it without having to use the AMD syntax. You can use r.js to wrap your Node modules. For instance, if you put your tree of Node modules in in, you can do:
$ r.js -convert in out
This will create in out a tree of files that correspond to those in in but wrapped with the define call. You can then load these in the browser using RequireJS. There are limitations. Some are obvious, like not being able to use the Node modules that depend on the Node runtime (like fs, child_process, etc.). Some are more subtle, like the fact that you can't use require(foo) where foo is a variable (RequireJS will handle only string literals there). See the documentation for the details.

Returning a module in RequireJS

I'm refactoring a large javascript codebase to use RequireJS. Unfortunately, many of the files I'm dealing with are not object-oriented, and cannot return an object without significant modification. Is there a more efficient way to give 'dependent' modules access to the functions and variables contained in a module (without returning an object) ?
I have read about using the exports syntax for defining modules, but it is very unclear whether that would be a valid solution for this situation.
In a defined module, the exports object is what gets exported from the module and passed to whatever module requires it.
Consider this:
define(["exports"], function(exports){
exports.myCustomFunction = function(){};
exports.myCustomObject = {};
exports.myCustomVariable = true;
})
This module will place all the disparate functions and/or objects that you want made public onto the exports object.
At this point RequireJS will use that exports object to pass to a module that requires it:
require(["nameOfCustomModule|filename"], function(myCustomModule){
//evaluates to true
console.log(myCustomModule.myCustomVariable);
})
Here's a simple fiddle. Just bring up your console and you will see the value logged there. http://jsfiddle.net/xeucv/
Hope this clears it up a bit!

Is there a better way to structure global variables in Node.js?

Trying to understand what would be the best way to structure some variables. For example in my Node.js Express app, I have the following in app.js:
var poolModule = require('generic-pool');
global.pools = {
/* ... */
};
Where pools is my global variable that keeps track of MySQL and Redis pools. I am also wondering if I can do the same with actual Redis and MySQL objects (and maybe configs variable) so I don't have to require them all over the app. And since they are going to be used the most.
Is this bad practice, and if yes, what's a better way to structure this kind of code?
Edit: added global.
If you require a file you are actually always requiring the same object. So that means you can do:
module.exports = {
// same object for everybody that requires me
};
You have the right idea, but you want to use module.exports to export your object as a module. The CommonJS approach is to have local variables within the module and exported variables for use outside the module. In this way modules can access each others' variables through the use of require. These variables aren't really "global", but in a way are more like "friend" classes in C++. You can in fact have your poolModule do more than store variables for you--you could put methods and other functionality in there too and make it reusable across your whole application.

Resources