Load text as JavaScript object in Node.js - javascript

I have a javascript file for node.js:
module.exports = {
someString: 'blblalb'
}
I want to able to read the file as a javascript object, using fs.readFileSync. I can't use require because I am using a variable that may be modified in runtime to load the file.
Is that possible?

You can use eval('JavaScript string') but is highly recommended not to. It is a serious security risk if you cannot 100% trust the source of the text. If a malicious user figures out a way to modify the text they have complete control of your system. It is not a path I would take or recommend.
const text = 'console.log("Hello")';
eval(text);
If I saw that code when I was doing a code review we would definitely be having some words.

it's possible to evaluate a file or string variable as child module in hacky yet valid way.
The problem is that Node.js module environment should be unaware of these operations. Child module may load other modules and contain require(...), it will fail if there is no require function (there is none if it is evaluated with vm) or it uses wrong module relative path (this will happen with eval), also there will be no dedicated module.exports for a module. This can be fixed by wrapping module source with Node.js module wrapper that was rewired to match child module location.
const fs = require('fs');
const Module = require('module');
const path = require('path');
const childModuleAbsPath = path.resolve('./foo/bar.js');
const childModuleBody = fs.readFileSync(childModuleAbsPath);
const childModuleObj = { exports: {} };
const { dir: childModuleDirname, base: childModuleFilename } = path.parse(childModuleAbsPath);
const childRequire = modulePath => module.require(childModuleAbsPath);
require('vm').runInThisContext(Module.wrap(childModuleBody))(
childModuleObj.exports,
childRequire,
childModuleObj,
childModuleDirname,
childModuleFilename
);
In this case childModuleObj.exports.someString === 'blblalb' after bar child module was evaluated.
This is XY problem that should be addressed in another way.
If the intention is to reevaluate a module with new variables, this can be done by invalidating Node module cache by modifying require.cache, e.g. with decache:
decache('./foo/bar');
const reloadedBar = require('./foo/bar');

Related

Splitting the code(commands/events) in different files [duplicate]

I'm trying to get JavaScript to read/write to a PostgreSQL database. I found this project on GitHub. I was able to get the following sample code to run in Node.
var pg = require('pg'); //native libpq bindings = `var pg = require('pg').native`
var conString = "tcp://postgres:1234#localhost/postgres";
var client = new pg.Client(conString);
client.connect();
//queries are queued and executed one after another once the connection becomes available
client.query("CREATE TEMP TABLE beatles(name varchar(10), height integer, birthday timestamptz)");
client.query("INSERT INTO beatles(name, height, birthday) values($1, $2, $3)", ['Ringo', 67, new Date(1945, 11, 2)]);
client.query("INSERT INTO beatles(name, height, birthday) values($1, $2, $3)", ['John', 68, new Date(1944, 10, 13)]);
//queries can be executed either via text/parameter values passed as individual arguments
//or by passing an options object containing text, (optional) parameter values, and (optional) query name
client.query({
name: 'insert beatle',
text: "INSERT INTO beatles(name, height, birthday) values($1, $2, $3)",
values: ['George', 70, new Date(1946, 02, 14)]
});
//subsequent queries with the same name will be executed without re-parsing the query plan by postgres
client.query({
name: 'insert beatle',
values: ['Paul', 63, new Date(1945, 04, 03)]
});
var query = client.query("SELECT * FROM beatles WHERE name = $1", ['John']);
//can stream row results back 1 at a time
query.on('row', function(row) {
console.log(row);
console.log("Beatle name: %s", row.name); //Beatle name: John
console.log("Beatle birth year: %d", row.birthday.getYear()); //dates are returned as javascript dates
console.log("Beatle height: %d' %d\"", Math.floor(row.height/12), row.height%12); //integers are returned as javascript ints
});
//fired after last row is emitted
query.on('end', function() {
client.end();
});
Next I tried to make it run on a webpage, but nothing seemed to happen. I checked on the JavaScript console and it just says "require not defined".
So what is this "require"? Why does it work in Node but not in a webpage?
Also, before I got it to work in Node, I had to do npm install pg. What's that about? I looked in the directory and didn't find a file pg. Where did it put it, and how does JavaScript find it?
So what is this "require?"
require() is not part of the standard JavaScript API. But in Node.js, it's a built-in function with a special purpose: to load modules.
Modules are a way to split an application into separate files instead of having all of your application in one file. This concept is also present in other languages with minor differences in syntax and behavior, like C's include, Python's import, and so on.
One big difference between Node.js modules and browser JavaScript is how one script's code is accessed from another script's code.
In browser JavaScript, scripts are added via the <script> element. When they execute, they all have direct access to the global scope, a "shared space" among all scripts. Any script can freely define/modify/remove/call anything on the global scope.
In Node.js, each module has its own scope. A module cannot directly access things defined in another module unless it chooses to expose them. To expose things from a module, they must be assigned to exports or module.exports. For a module to access another module's exports or module.exports, it must use require().
In your code, var pg = require('pg'); loads the pg module, a PostgreSQL client for Node.js. This allows your code to access functionality of the PostgreSQL client's APIs via the pg variable.
Why does it work in node but not in a webpage?
require(), module.exports and exports are APIs of a module system that is specific to Node.js. Browsers do not implement this module system.
Also, before I got it to work in node, I had to do npm install pg. What's that about?
NPM is a package repository service that hosts published JavaScript modules. npm install is a command that lets you download packages from their repository.
Where did it put it, and how does Javascript find it?
The npm cli puts all the downloaded modules in a node_modules directory where you ran npm install. Node.js has very detailed documentation on how modules find other modules which includes finding a node_modules directory.
Alright, so let's first start with making the distinction between Javascript in a web browser, and Javascript on a server (CommonJS and Node).
Javascript is a language traditionally confined to a web browser with a limited global context defined mostly by what came to be known as the Document Object Model (DOM) level 0 (the Netscape Navigator Javascript API).
Server-side Javascript eliminates that restriction and allows Javascript to call into various pieces of native code (like the Postgres library) and open sockets.
Now require() is a special function call defined as part of the CommonJS spec. In node, it resolves libraries and modules in the Node search path, now usually defined as node_modules in the same directory (or the directory of the invoked javascript file) or the system-wide search path.
To try to answer the rest of your question, we need to use a proxy between the code running in the the browser and the database server.
Since we are discussing Node and you are already familiar with how to run a query from there, it would make sense to use Node as that proxy.
As a simple example, we're going to make a URL that returns a few facts about a Beatle, given a name, as JSON.
/* your connection code */
var express = require('express');
var app = express.createServer();
app.get('/beatles/:name', function(req, res) {
var name = req.params.name || '';
name = name.replace(/[^a-zA_Z]/, '');
if (!name.length) {
res.send({});
} else {
var query = client.query('SELECT * FROM BEATLES WHERE name =\''+name+'\' LIMIT 1');
var data = {};
query.on('row', function(row) {
data = row;
res.send(data);
});
};
});
app.listen(80, '127.0.0.1');
I noticed that whilst the other answers explained what require is and that it is used to load modules in Node they did not give a full reply on how to load node modules when working in the Browser.
It is quite simple to do. Install your module using npm as you describe, and the module itself will be located in a folder usually called node_modules.
Now the simplest way to load it into your app is to reference it from your html with a script tag which points at this directory. i.e if your node_modules directory is in the root of the project at the same level as your index.html you would write this in your index.html:
<script src="node_modules/ng"></script>
That whole script will now be loaded into the page - so you can access its variables and methods directly.
There are other approaches which are more widely used in larger projects, such as a module loader like require.js. Of the two, I have not used Require myself, but I think it is considered by many people the way to go.
It's used to load modules. Let's use a simple example.
In file circle_object.js:
var Circle = function (radius) {
this.radius = radius
}
Circle.PI = 3.14
Circle.prototype = {
area: function () {
return Circle.PI * this.radius * this.radius;
}
}
We can use this via require, like:
node> require('circle_object')
{}
node> Circle
{ [Function] PI: 3.14 }
node> var c = new Circle(3)
{ radius: 3 }
node> c.area()
The require() method is used to load and cache JavaScript modules. So, if you want to load a local, relative JavaScript module into a Node.js application, you can simply use the require() method.
Example:
var yourModule = require( "your_module_name" ); //.js file extension is optional
Necromancing.
IMHO, the existing answers leave much to be desired.
At first, it's very confusing.
You have a (nowhere defined) function "require", which is used to get modules.
And in said (CommonJS) modules, you can use require, exports and module, WITHOUT THEM EVER BEING DEFINED.
Not that it would be new that you could use undefined variables in JS, but you couldn't use an undefined function.
So it looks a little like magic at first.
But all magic is based on deception.
When you dig a little deeper, it turns out it is really quite simple:
Require is simply a (non-standard) function defined at global scope.
(global scope = window-object in browser, global-object in NodeJS).
Note that by default, the "require function" is only implemented in NodeJS, not in the browser.
Also, note that to add to the confusion, for the browser, there is RequireJS, which, despite the name containing the characters "require", RequireJS absolutely does NOT implement require/CommonJS - instead RequireJS implements AMD, which is something similar, but not the same (aka incompatible).
That last one is just one important thing you have to realize on your way to understanding require.
Now, as such, to answer the question "what is require", we "simply" need to know what this function does.
This is perhaps best explained with code.
Here's a simple implementation by Michele Nasti, the code you can find on his github page.
Let's call our minimalisc implementation of the require function "myRequire":
function myRequire(name)
{
console.log(`Evaluating file ${name}`);
if (!(name in myRequire.cache)) {
console.log(`${name} is not in cache; reading from disk`);
let code = fs.readFileSync(name, 'utf8');
let module = { exports: {} };
myRequire.cache[name] = module;
let wrapper = Function("require, exports, module", code);
wrapper(myRequire, module.exports, module);
}
console.log(`${name} is in cache. Returning it...`);
return myRequire.cache[name].exports;
}
myRequire.cache = Object.create(null);
window.require = myRequire;
const stuff = window.require('./main.js');
console.log(stuff);
Now you notice, the object "fs" is used here.
For simplicity's sake, Michele just imported the NodeJS fs module:
const fs = require('fs');
Which wouldn't be necessary.
So in the browser, you could make a simple implementation of require with a SYNCHRONOUS XmlHttpRequest:
const fs = {
file: `
// module.exports = \"Hello World\";
module.exports = function(){ return 5*3;};
`
, getFile(fileName: string, encoding: string): string
{
// https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Synchronous_and_Asynchronous_Requests
let client = new XMLHttpRequest();
// client.setRequestHeader("Content-Type", "text/plain;charset=UTF-8");
// open(method, url, async)
client.open("GET", fileName, false);
client.send();
if (client.status === 200)
return client.responseText;
return null;
}
, readFileSync: function (fileName: string, encoding: string): string
{
// this.getFile(fileName, encoding);
return this.file; // Example, getFile would fetch this file
}
};
Basically, what require thus does, is it downloads a JavaScript-file, evals it in an anonymous namespace (aka Function), with the parameters "require", "exports" and "module", and returns the exports, meaning an object's public functions and properties.
Note that this evaluation is recursive: you require files, which themselfs can require files.
This way, all "global" variables used in your module are variables in the require-wrapper-function namespace, and don't pollute the global scope with unwanted variables.
Also, this way, you can reuse code without depending on namespaces, so you get "modularity" in JavaScript. "modularity" in quotes, because this is not exactly true, though, because you can still write window.bla/global.bla, and hence still pollute the global scope... Also, this establishes a separation between private and public functions, the public functions being the exports.
Now instead of saying
module.exports = function(){ return 5*3;};
You can also say:
function privateSomething()
{
return 42:
}
function privateSomething2()
{
return 21:
}
module.exports = {
getRandomNumber: privateSomething
,getHalfRandomNumber: privateSomething2
};
and return an object.
Also, because your modules get evaluated in a function with parameters
"require", "exports" and "module", your modules can use the undeclared variables "require", "exports" and "module", which might be startling at first. The require parameter there is of course a pointer to the require function saved into a variable.
Cool, right ?
Seen this way, require looses its magic, and becomes simple.
Now, the real require-function will do a few more checks and quirks, of course, but this is the essence of what that boils down to.
Also, in 2020, you should use the ECMA implementations instead of require:
import defaultExport from "module-name";
import * as name from "module-name";
import { export1 } from "module-name";
import { export1 as alias1 } from "module-name";
import { export1 , export2 } from "module-name";
import { foo , bar } from "module-name/path/to/specific/un-exported/file";
import { export1 , export2 as alias2 , [...] } from "module-name";
import defaultExport, { export1 [ , [...] ] } from "module-name";
import defaultExport, * as name from "module-name";
import "module-name";
And if you need a dynamic non-static import (e.g. load a polyfill based on browser-type), there is the ECMA-import function/keyword:
var promise = import("module-name");
note that import is not synchronous like require.
Instead, import is a promise, so
var something = require("something");
becomes
var something = await import("something");
because import returns a promise (asynchronous).
So basically, unlike require, import replaces fs.readFileSync with fs.readFileAsync.
async readFileAsync(fileName, encoding)
{
const textDecoder = new TextDecoder(encoding);
// textDecoder.ignoreBOM = true;
const response = await fetch(fileName);
console.log(response.ok);
console.log(response.status);
console.log(response.statusText);
// let json = await response.json();
// let txt = await response.text();
// let blo:Blob = response.blob();
// let ab:ArrayBuffer = await response.arrayBuffer();
// let fd = await response.formData()
// Read file almost by line
// https://developer.mozilla.org/en-US/docs/Web/API/ReadableStreamDefaultReader/read#Example_2_-_handling_text_line_by_line
let buffer = await response.arrayBuffer();
let file = textDecoder.decode(buffer);
return file;
} // End Function readFileAsync
This of course requires the import-function to be async as well.
"use strict";
async function myRequireAsync(name) {
console.log(`Evaluating file ${name}`);
if (!(name in myRequireAsync.cache)) {
console.log(`${name} is not in cache; reading from disk`);
let code = await fs.readFileAsync(name, 'utf8');
let module = { exports: {} };
myRequireAsync.cache[name] = module;
let wrapper = Function("asyncRequire, exports, module", code);
await wrapper(myRequireAsync, module.exports, module);
}
console.log(`${name} is in cache. Returning it...`);
return myRequireAsync.cache[name].exports;
}
myRequireAsync.cache = Object.create(null);
window.asyncRequire = myRequireAsync;
async () => {
const asyncStuff = await window.asyncRequire('./main.js');
console.log(asyncStuff);
};
Even better, right ?
Well yea, except that there is no ECMA-way to dynamically import synchronously (without promise).
Now, to understand the repercussions, you absolutely might want to read up on promises/async-await here, if you don't know what that is.
But very simply put, if a function returns a promise, it can be "awaited":
"use strict";
function sleep(interval)
{
return new Promise(
function (resolve, reject)
{
let wait = setTimeout(function () {
clearTimeout(wait);
//reject(new Error(`Promise timed out ! (timeout = ${timeout})`));
resolve();
}, interval);
});
}
The promise would then normally be used like this:
function testSleep()
{
sleep(3000).then(function ()
{
console.log("Waited for 3 seconds");
});
}
But when you return a promise, you can also use await, which means we get rid of the callback (sort of - actually, it is being replaced with a state-machine in the compiler/interpreter).
This way, we make asynchronous code feel like synchronous, so we now can use try-catch for error-handling.
Note that if you want to use await in a function, that function must be declared async (hence async-await).
async function testSleep()
{
await sleep(5000);
console.log("i waited 5 seconds");
}
And also please note that in JavaScript, there is no way to call an async function (blockingly) from a synchronous one (the ones you know). So if you want to use await (aka ECMA-import), all your code needs to be async, which most likely is a problem, if everything isn't already async...
An example of where this simplified implementation of require fails, is when you require a file that is not valid JavaScript, e.g. when you require css, html, txt, svg and images or other binary files.
And it's easy to see why:
If you e.g. put HTML into a JavaScript function body, you of course rightfully get
SyntaxError: Unexpected token '<'
because of Function("bla", "<doctype...")
Now, if you wanted to extend this to for example include non-modules, you could just check the downloaded file-contents for code.indexOf("module.exports") == -1, and then e.g. eval("jquery content") instead of Func (which works fine as long as you're in the browser). Since downloads with Fetch/XmlHttpRequests are subject to the same-origin-policy, and integrity is ensured by SSL/TLS, the use of eval here is rather harmless, provided you checked the JS files before you added them to your site, but that much should be standard-operating-procedure.
Note that there are several implementations of require-like functionality:
the CommonJS (CJS) format, used in Node.js, uses a require function and module.exports to define dependencies and modules. The npm ecosystem is built upon this format. (this is what is implemented above)
the Asynchronous Module Definition (AMD) format, used in browsers, uses a define function to define modules. (basically, this is overcomplicated archaic crap that you wouldn't ever want to use). Also, AMD is the format that is implemented by RequireJS (note that despite the name containing the characters "require", AMD absolutely is NOT CommonJS).
the ES Module (ESM) format. As of ES6 (ES2015), JavaScript supports a native module format. It uses an export keyword to export a module’s public API and an import keyword to import it. This is the one you should use if you don't give a flying f*ck about archaic browsers, such as Safari and IE/EdgeHTML.
the System.register format, designed to support ES6 modules within ES5. (the one you should use, if you need support for older browsers (Safari & IE & old versions of Chrome on mobile phones/tablets), because it can load all formats [for some, plugins are required], can handle cyclic-dependencies, and CSS and HTML - don't define your modules as system.register, though - the format is rather complicated, and remember, it can read the other easier formats)
the Universal Module Definition (UMD) format, compatible to all the above mentioned formats (except ECMA), used both in the browser and in Node.js. It’s especially useful if you write modules that can be used in both NodeJS and the browser. It's somewhat flawed, as it doesn't support the latest ECMA modules, though (maybe this will get fixed) - use System.register instead.
Important sidenote on the function argument "exports":
JavaScript uses call-by-value-sharing - meaning objects are passed as a pointer, but the pointer-value itselfs is passed BY VALUE, not by reference. So you can't override exports by assigning it a new object. Instead, if you want to override exports, you need to assign the new object to module.exports - because hey, module is the pointer passed by value, but exports in module.exports is the reference to the original exports pointer.
Important sidenote on module-Scope:
Modules are evaluated ONCE, and then cached by require.
That means all your modules have a Singleton scope.
If you want a non-singleton scope, you have to do something like:
var x = require("foo.js").createInstance();
or simply
var x = require("foo.js")();
with appropriate code returned by your module.
If you need CommonJS-support for the browser (IE5+, Chrome, Firefox),
check out my code in my comment on Michele Nasti's project
You know how when you are running JavaScript in the browser, you have access to variables like "window" or Math? You do not have to declare these variables, they have been written for you to use whenever you want.
Well, when you are running a file in the Node.js environment, there is a variable that you can use. It is called "module" It is an object. It has a property called "exports." And it works like this:
In a file that we will name example.js, you write:
example.js
module.exports = "some code";
Now, you want this string "some code" in another file.
We will name the other file otherFile.js
In this file, you write:
otherFile.js
let str = require('./example.js')
That require() statement goes to the file that you put inside of it, finds whatever data is stored on the module.exports property. The let str = ... part of your code means that whatever that require statement returns is stored to the str variable.
So, in this example, the end-result is that in otherFile.js you now have this:
let string = "some code";
or -
let str = ('./example.js').module.exports
Note:
the file-name that is written inside of the require statement: If it is a local file, it should be the file-path to example.js. Also, the .js extension is added by default, so I didn't have to write it.
You do something similar when requiring node.js libraries, such as Express. In the express.js file, there is an object named 'module', with a property named 'exports'.
So, it looks something like along these lines, under the hood (I am somewhat of a beginner so some of these details might not be exact, but it's to show the concept:
express.js
module.exports = function() {
//It returns an object with all of the server methods
return {
listen: function(port){},
get: function(route, function(req, res){}){}
}
}
If you are requiring a module, it looks like this:
const moduleName = require("module-name");
If you are requiring a local file, it looks like this:
const localFile = require("./path/to/local-file");
(notice the ./ at the beginning of the file name)
Also note that by default, the export is an object .. eg module.exports = {} So, you can write module.exports.myfunction = () => {} before assigning a value to the module.exports. But you can also replace the object by writing module.exports = "I am not an object anymore."
Two flavours of module.exports / require:
(see here)
Flavour 1
export file (misc.js):
var x = 5;
var addX = function(value) {
return value + x;
};
module.exports.x = x;
module.exports.addX = addX;
other file:
var misc = require('./misc');
console.log("Adding %d to 10 gives us %d", misc.x, misc.addX(10));
Flavour 2
export file (user.js):
var User = function(name, email) {
this.name = name;
this.email = email;
};
module.exports = User;
other file:
var user = require('./user');
var u = new user();

Read environment variables and then replace them in client-side JS when using gulp for building prod or dev code

So lets say I have some code in js
const myApiKey = 'id_0001'
But instead of harcoding it I want to put it in some bash script with other env vars and read from it and then replace it in the JS
So lets say for prod I would read from prod-env.sh or for dev I would read them from dev-env.sh and then gulp or some other tool does the magic and replaces MY_API_KEY based on whatever is established inside of prod-env.sh or dev-env.sh.
const myApiKey = MY_API_KEY
Update: I want to add I only care about unix OS, not concerned about windows. In golang there is way to read for example envVars.get('MY_API_KEY'), I'm looking for something similar but for JS in the client side.
If you're using gulp, it sounds like you could use any gulp string replacer, like gulp-replace.
As for writing the gulp task(s). If you are willing to import the environment into your shell first, before running node, you can access the environment via process.env
gulp.task('build', function(){
gulp.src(['example.js'])
.pipe(replace('MY_API_KEY', process.env.MY_API_KEY))
.pipe(gulp.dest('build/'));
});
If you don't want to import the environment files before running node, you can use a library like env2 to read shell environment files.
Another option would be to use js/json to define those environment files, and load them with require.
prod-env.js
{
"MY_API_KEY": "api_key"
}
gulpfile.js
const myEnv = require('./prod-env')
gulp.task('build', function(){
gulp.src(['example.js'])
.pipe(replace('MY_API_KEY', myEnv.MY_API_KEY))
.pipe(gulp.dest('build/'));
});
Also, for a more generic, loopy version of the replace you can do:
gulp.task('build', function () {
stream = gulp.src(['example.js']);
for (const key in process.env) {
stream.pipe('${' + key + '}', process.env[key]);
}
stream.pipe(gulp.dest('build/'));
});
In that last example I added ${} around the environment variable name to make it less prone to accidents. So the source file becomes:
const myApiKey = ${MY_API_KEY}
This answer is an easy way to do this for someone who doesn't want to touch the code they are managing. For example you are on the ops team but not the dev team and need to do what you are describing.
The environment variable NODE_OPTIONS can control many things about the node.js runtime - see https://nodejs.org/api/cli.html#cli_node_options_options
One such option we can set is --require which allows us to run code before anything else is even loaded.
So using this you can create a overwrite.js file to perform this replacement on any non-node_modules script files:
const fs = require('fs');
const original = fs.readFileSync;
// set some custom env variables
// API_KEY_ENV_VAR - the value to set
// API_KEY_TEMPLATE_TOKEN - the token to replace with the value
if (!process.env.API_KEY_TEMPLATE_TOKEN) {
console.error('Please set API_KEY_TEMPLATE_TOKEN');
process.exit(1);
}
if (!process.env.API_KEY_ENV_VAR) {
console.error('Please set API_KEY_ENV_VAR');
process.exit(1);
}
fs.readFileSync = (file, ...args) => {
if (file.includes('node_modules')) {
return original(file, ...args);
}
const fileContents = original(file, ...args).toString(
/* set encoding here, or let it default to utf-8 */
);
return fileContents
.split(process.env.API_KEY_TEMPLATE_TOKEN)
.join(process.env.API_KEY_ENV_VAR);
};
Then use it with a command like this:
export API_KEY_ENV_VAR=123;
export API_KEY_TEMPLATE_TOKEN=TOKEN;
NODE_OPTIONS="--require ./overwrite.js" node target.js
Supposing you had a script target.js
console.log('TOKEN');
It would log 123. You can use this pretty much universally with node, so it should work fine with gulp, grunt, or any others.

node.js configure submodules

[EDIT]
Thanks to Stafano that formalized my question in a better way:
You have a module
-) There are several files in this module
-) All these files depend on a configuration whose path is unknown to the module itself
-) This module does not do much on its own, and is meant to be used by other applications
-) These applications should inject a configuration path into the module before it can be used
So i have this module, used from another application. It's composed of other submodules and i want to configure it using a configuration object.
I already tried to inject the configuration in my submodels but i had the same problem exposed in the original question.
For example my module use mongoDB (with mongoose) as a store.
// app.js
// in the config object i have the URI to the mongo instance (in order to create a connection).
var myModule = require('myModule')(config);
// myModule.js
// files
// myModule/index.js expose the module's functionalities
// is the entry point so I create the mongoose connection
var mongoose = require('mongoose');
module.exports = function(config){
var connection = mongoose.createConnection(config.store.URL);
// I need to expose this connection to the others submodules.
}
// myModule/storeController.js contains the business logic that use the store (createItem, deleteItem, get...) and requrie mongoose and my Models (store in the models folder)
var mongoose = require('mongoose');
var Item = require('./models/item.js');
exports.createItem = function(item){
Item.save(item, function(err, item){
if (err) throw
...
});
}
// myModule/models/item.js
// In this module i need to use the connection application in the configuration.
var mongoose = require('mongoose');
var connection = // i don't know how to get it
var ItemSchema = new mongoose.Schema({
name: String
});
module.exports = mongoose.model('item', ItemSchema);
If I inject the configuration obj to the item.js i can't do the module.exports of my model.
I hope that this example can clarify my question, but the problem is the simple, expose an object after get it as a parameter.
[PREVIOUS]
I have a node.js application that require a module. This module accept the coniguration file path (a JSON file).
I need to load that configuration on require and expose it to the module.
How can I achieve this behavior?
Something like:
// app.js
var myModule = require('myModule')(__dirname + '/config/myModuleCnfig.json');
// myModule.js
module.exports = function(configPath){
var config = require(configPath);
module.exports = config; // This is wrong
}
Is there another way to get the configuration path, configure the module and share the configuration??
With "share the configuration" i mean that i want to give the possibility to other files of my module to use that configuration.
Thanks for any suggestions!
FINAL EDIT:
After many misunderstandings, your problem is finally clear to me. To summarise what's in the comments, here is the situation:
You have a module
There are several files in this module
All these files depend on a configuration whose path is unknown to the module
itself
This module does not do much on its own, and is meant to be
used by other applications
These applications should inject a
configuration path into the module before it can be used
Since you cannot modify dynamically what a module exports, you should use another approach. As with most situations that you encounter in programming, there is not one way which is always right, as much pedends on your requirements and limitations.
The easiest way to do this (which I don't recommend) is to use a global variable, which you set in your myModule.js file and will be used by the other files in your module. The biggest drawback of this approach is that you wouldn't be able to use multiple instances of the module at the same time with different configurations. Also, any other module could easily modify (deliberately or not) you configuration at any time, by simply changing the value of the global variable, so it's also a security risk.
A much better way, which will probably require more work on your part - depending on how many files you have - is to implement some kind of Inversion of Control (IoC). In your case, you could turn all your exports into functions that accept a config, and then initialise them by passing the active configuration after you require the module. I don't know the specifics of your implementation, so here is some sample code:
// submodule1.js
module.exports = function(config) {
// return something that uses the configuration
}
// myModule.js
var fs = require('fs');
var submodule1 = require('./submodule1');
var submodule2 = require('./submodule2');
// ...
module.exports = function(configPath){
var config = JSON.parse(fs.readFileSync(configPath));
var sm1 = submodule1(config);
var sm2 = submodule2(config);
return /* an object that uses sm1 and sm2 */;
}
If your module is quite complex, you can use some IoC library that does the binding for you. An good one could be Electrolite.
Hope this helps.
PREVIOUS ANSWER:
You can use a library called jsop:
var jsop = require('jsop');
var config = jsop('./config/myModuleCnfig.json');
If you don't want to add a dependency to this module, the linked GitHub page also has a snippet that you can use to load the json config using only native methods.
EDIT: I just realised that this module is only for node 0.11, which you are probably not using. Since you don't probably need the writing functionality, you can use the following snippet instead:
var fs = require('fs')
var config = JSON.parse(fs.readFileSync('./config/myModuleCnfig.json'))
EDIT 2:
Now I think I understand your problem better. To pass the path to the required configuration, you can do something like this:
// myModule.js
var fs = require('fs')
module.exports = function(configPath){
var config = JSON.parse(fs.readFileSync(configPath))
return config;
}

In Node.js, how can I load my modules once and then use them throughout the app?

I want to create one global module file, and then have all my files require that global module file. Inside that file, I would load all the modules once and export a dictionary of loaded modules.
How can I do that?
I actually tried creating this file...and every time I require('global_modules'), all the modules kept reloading. It's O(n).
I want the file to be something like this (but it doesn't work):
//global_modules.js - only load these one time
var modules = {
account_controller: '/account/controller.js',
account_middleware: '/account/middleware.js',
products_controller: '/products/controller.js',
...
}
exports.modules = modules;
1. Using a magic variable (declared without var)
Use magic global variables, without var.
Example:
fs = require("fs");
instead of
var fs = require("fs");
If you don't put var when declaring the variable, the variable will be a magic global one.
I do not recommend this. Especially, if you are in the strict mode ("use strict") that's not going to work at all.
2. Using global.yourVariable = ...
Fields attached to global object become global variables that can be accessed from anywhere in your application.
So, you can do:
global.fs = require("fs");
This is not that bad like 1., but still avoid it when possible.
For your example:
Let's say you have two files: server.js (the main file) and the global_modules.js file.
In server.js you will do this:
require("./global_modules");
and in global_modules.js you will have:
_modules = {
account_controller: require('/account/controller.js'),
account_middleware: require('/account/middleware.js'),
products_controller: require('/products/controller.js'),
...
}
or
global._modules = {...}
In server.js you will be able to do:
_modules.account_controller // returns require('/account/controller.js'),
require already does it. Try loading a module, modify it and then load it another time in another place or file:
var fs = require('fs'):
console.log(fs.hey);
fs.hey = 'HEY TIMEX, WHATS UP?';
//another place of the same process
var fs = require('fs');
console.log(fs.hey);

NodeJS and Javascript (requirejs) dependency injection

I am currently using requirejs to manage module js/css dependencies.
I'd like to discover the possibilities of having node do this via a centralized config file.
So instead of manually doing something like
define([
'jquery'
'lib/somelib'
'views/someview']
within each module.
I'd have node inject the dependencies ie
require('moduleA').setDeps('jquery','lib/somelib','views/someview')
Anyway, I'm interested in any projects looking at dependency injection for node.
thanks
I've come up with a solution for dependency injection. It's called injectr, and it uses node's vm library and replaces the default functionality of require when including a file.
So in your tests, instead of require('libToTest'), use injectr('libToTest' { 'libToMock' : myMock });. I wanted to make the interface as straightforward as possible, with no need to alter the code being tested. I think it works quite well.
It's just worth noting that injectr files are relative to the working directory, unlike require which is relative to the current file, but that shouldn't matter because it's only used in tests.
I've previously toyed with the idea of providing an alternate require to make a form of dependency injection available in Node.js.
Module code
For example, suppose you have following statements in code.js:
fs = require('fs');
console.log(fs.readFileSync('text.txt', 'utf-8'));
If you run this code with node code.js, then it will print out the contents of text.txt.
Injector code
However, suppose you have a test module that wants to abstract away the file system.
Your test file test.js could then look like this:
var origRequire = global.require;
global.require = dependencyLookup;
require('./code.js');
function dependencyLookup (file) {
switch (file) {
case 'fs': return { readFileSync: function () { return "test contents"; } };
default: return origRequire(file);
}
}
If you now run node test.js, it will print out "test contents", even though it includes code.js.
I've also written a module to accomplish this, it's called rewire. Just use npm install rewire and then:
var rewire = require("rewire"),
myModule = rewire("./path/to/myModule.js"); // exactly like require()
// Your module will now export a special setter and getter for private variables.
myModule.__set__("myPrivateVar", 123);
myModule.__get__("myPrivateVar"); // = 123
// This allows you to mock almost everything within the module e.g. the fs-module.
// Just pass the variable name as first parameter and your mock as second.
myModule.__set__("fs", {
readFile: function (path, encoding, cb) {
cb(null, "Success!");
}
});
myModule.readSomethingFromFileSystem(function (err, data) {
console.log(data); // = Success!
});
I've been inspired by Nathan MacInnes's injectr but used a different approach. I don't use vm to eval the test-module, in fact I use node's own require. This way your module behaves exactly like using require() (except your modifications). Also debugging is fully supported.

Categories