Modify NodeJS core programs - javascript

I tried to add some custom functions into the FS module of NodeJS, this module is part of NodeJS' core programs. I found the corresponding file (fs.js) in the following location: /usr/lib/nodejs. The problem was that the changes that I've made seemed to not affect anything when the corresponding module and function was called.
What I did was I added a function like this in /usr/lib/nodejs/fs.js:
fs.someRandomFunc = function(){return 'Yeah!'}
However, when I called the function, it replied :
var fs = require('fs')
console.log(fs.someRandomFunc())
// Error Message
TypeError: Object #<Object> has no method 'someRandomFunc'
By the way, this also happens to the other core modules, such as module.js and path.js. Does this happen because NodeJS caches the core JS program instead of loading it from /usr/lib/nodejs?
Any idea to resolve this issue would be appreciated.
Thanks!

fs is part of NodeJS' Core Modules. As such, it is compiled into binary and distributed. So modifying the source is not going to take effect unless you recompile them.
It is anyway not a good idea to modify Node's source files directly. What you can/should instead is extend the existing fs module with your own functions, like graceful-fs does, or replace it entirely with your version, like fs-extra does.

Related

Sharing global between JavaScript files without using modules/exports

I have a self contained JavaScript function in one file, and some Mocha BDD tests in another file that reference it using [nodejs] require(). So in my function under test I export using module.exports. That's all well and good, in the IDE/build.
Now my function under test is actually an external virtual endpoint, which when deployed into a cloud instance, runs standalone inside a JSVM sandbox (Otto) which has no support for exports or modules, and is ES5 based (it does however embed a version of the Underscore library). If I leave the nodejs module definition in there when I deploy to cloud, it kicks off an error at runtime (as Otto doesn't recognise modules). So I want to remove it, and use some vanilla JS mechanism for the linkage back to the Mocha tests and test runner.
So my question is, if I can't use nodejs or requirejs modules, how can I link my Mocha tests in one file to a JS function in another? I had a play with placing a function closure (which most module implementations use) in the file under test, and Otto is happy with this, as its vanilla JS, but any variable with global scope in the file is still not visible from my test file, so there is no linkage.
Any thoughts?
From a quick look at the Otto docs, it looks like Otto only wants whole files and (as you've said) doesn't recogise commonjs modules from node.
If you've got many files I would recommend bundling them into a single file with webpack/browserify/etc, which is how most people convert modules for use in the browser, which similarily doesn't recognise commonjs modules without tooling.
Alternatively, you could convert all the module.exports to simple var declarations, concatenate the files together and hope you don't have a naming collision.
I don't see anything in the docs about having access to a window or global object to hang globals onto, which limits your options
One of my colleague came up with a suggestion to use closure in the file under test which gets deployed into the cloud instance, if you are running under Nodejs, and conditionally do the export. I added the small anonymous closure below to do this, and Otto doesn't complain.
(function () {
if (typeof module != 'undefined') {
module.exports = pdp_virtual_endpoint;
}
}());
Not sure why I didn't think about this earlier :)

How to make sure a module is loaded in NodeJS

This is a problem I faced more than one. Here is an example file structure:
app.js
folder
-- index.js
-- module1.js
-- module2.js
From app.js, the entry point of my application, I require folder/index.js. This file itself is just a loader who requires all the other files in the directory. module1.js and module2.js both define some methods I want to use eventually. They are never directly required by app.js since index.js takes care of that and adds common helper utilities and applies some transformations to these modules.
All works well if I then use some methods defined in those files from app.js after I required them. But the problem comes when a method defined in module2.js wants to use a method defined in method1.js (or vice-versa). Sometimes it will work, sometimes not (in folders with multiple files I didn't get to find out when precisely it works and when it doesn't yet).
If, from module2.js I require ./index.js and then use methods in it defined by module1.js, I sometimes get Cannot read property 'myMethod' of undefined. I assume it has to do with the order the modules are required by index.js, but I can't seem to find a solution to this common problem (other than duplicating code or not using methods of these other modules).
Is there a common solution to this problem? I tried doing something like this :
var modules = require(./index.js);
exports.myMethod = function() {
if(!modules.module1 || !modules.module1.myOtherMethod) {
modules = require('./index.js');
}
modules.module1.myOtherMethod();
};
But it doesn't to do anything, modules.module1 is still undefined.
It just sounds like module should require module2. That's the solution to module1 needing to call methods in module2.
If you're worried about many calls to require, don't. That's standard practice in every programming language I've used (in particular look at the import statements in any Java program. Java is verbose, I know, but this is correct practice.)
It's definitely bad practice to look at code in one module and have no idea where anything comes from, because the require statements are missing.
You have a circular dependency problem. Try moving some of the common functions to a third file and have module1 and module2 require it, or make sure that one of them requires the other in one way only.
Never ever require a file that requires the current file back.

Node JS fs module inside browser

I have a scenario where I want to export data to CSV from the client-side. I will have a textbox/area or whatever where the user can input data and then ideally with one click, a local CSV file will be updated with that data.
This is easily achievable with NodeJS with server interaction, and its core modules (specifically fs module), but apparently not so much from a browser.
I found out that certain node modules (for example underscore), support RequireJS's method of making a particular module work in the browser. So for underscore I did this:
methods.js
define(['underscore'],function(_) {
var Methods = {
doSomething: function() {
var x = _.size({one: 1, two: 2, three: 3, xuz: 3});
alert(x);
}
};
return Methods;
});
common.js
requirejs.config({
baseURL: 'node_modules',
paths: {
underscore: 'underscore/underscore',
}
});
require(['methods'], function(y){
y.doSomething();
});
index.html
<script data-main="common" src="require.js"></script>
<script>
require(['common'], function() {
require(['methods.js']);
});
</script>
The above works fine and will show an alert: 4.
But when I try the same with the fs module it won't work. It will show this error:
Module name "util" has not been loaded yet for context: _. Use require([])
As far as I can understand, this is because fs requires several other modules, one of them being util.
So I proceeded to add all these modules to the RequireJS config. But still no luck, so I specifically tested util module by itself as this doesn't seem to require other modules to work.
And now I am stuck on this error: Uncaught ReferenceError: exports is not defined
I tried modularizing this util module by encapsulating the whole module source code in this:
define([], function() {})
But it didn't work either... I've also tried copying underscore's model but still no luck.
So I was wondering if anyone managed to use util & fs modules (or any other core NodeJS modules) within the browser with libraries such as RequireJS or Browserify.
That's right, exports is node-specific JS (used to make part of your module available outside the module) and isn't supported by web-browsers. Even though NodeJS is technically JS, there are client specific properties (like the window property for browsers, and exports for NodeJS apps) that can't be interchanged.
That said, here's a client side JS answer to the CSV problem.
Your best bet (and probably only one) is to use HTML5 FileSystem API. I am not aware of any other browser feature that would allow to work with files on client computer except maybe Flash and similar solution.
I am bit confused by your browserify tag since you are not obviously using Browserify. That would fix your issue with "exports is not defined".

Basic requirejs concept needed to make work musicjson package

I'd like to use the musicjson.js package that helps to convert musicXML files into json notation, looking if it's a good way to import for example exported musicXML Finale scores into a browser playing with the Fermata/VexFlow class.
https://github.com/saebekassebil/musicjson
The thing is that this module works with require (calling for
nodes packages like fs) and I'm just a newbee in requirejs...Even if I spent few time in understanding the tutorial in the website, I don't still get how to solve this kind of basic problem when the dependencies of my musicjson.js need to be called like :
var xmldom = require('flat-xmldom'),
fs = require('fs'),
path = require('path'),
util = require('util');
My index.php page does the classic require call:
<!DOCTYPE html>
<head>
<!-- javascript head -->
<!-- REQUIRE -->
<script data-main="scripts/main" src="bower_components/requirejs/require.js"></script>
</head>
<body>
</body>
</html>
In my scripts/main.js, I'd like to do simply what it is told from musicjon :
var music = require('musicjson');
music.musicJSON(xml, function(err, json) {
// Do something with the MusicJSON data
});
I putted also, in the same directory scripts/, the flat-xmldom folder, fs.js, path.js, util.js
When I do this, I've just obtain this classic error of :
*Error: Module name "musicjson" has not been loaded yet for context: _. Use require([])*
...That looks like a common error referenced in the requirejs website,
but if I try things that I guess it should be written, I get a bit lost to determine where is the fundamental conceptual mistake here :
require.config({
baseUrl: '/scripts/',
paths: {
flatxmldom:'./flat-xmldom/__package__',
fs: 'fs',
path:'path',
util:'util',
musicjson: 'musicjson'
}
});
require(['flatxmldom','fs','path','util','musicjson'],function(flatxmldom,fs,path,util,musicjson){})
Error returned in this case for example :
*Module name "fs" has not been loaded yet for context: _. Use require([])*
Thanks a lot for your attention.
So, this is not a RequireJS problem per-se. The package you want to use is a Node.js package. It is intended to run in node (a server/desktop execution environment for JavaScript). It cannot/will not run in web page in a browser.
The packages it is trying to use (fs in particular) provide access to system resources such as the file system. Node provides these packages as part of its core libraries to any package that runs in node. A browser is specifically designed for security reasons never to allow direct access to such resources to any code that run in the browser because who knows where it came from or might try to do.
I haven't really tried to do this myself, but browserify (alternative to requirejs) claims that it will allow you to use any node package in your application.
If musicjson is at the heart of what your app should achieve and requirejs is a small step on the way to getting there, you could try your luck with browserify instead.

compile order of node.js modules

The problem is that I have a number of separate modules which I export using module.exports and are inter dependent. Say-
mongohelper
transaction
server
conhandlr
appmin
Now, the server module contains a common object that is required by the other four modules. However, when compiling the node app, some of these modules are compiled before the server module for example by using console output I found that the order was -
Compile order-
mongohelper
transaction
server (..the upper modules have undefined common object now)
conhandlr
appmin
So, is there a way by which I can make sure that the server module compiles first so that any dependent modules dont have undefined objects?
Without any actual code, it's hard to understand what you really want to know, but I'll try to give you a basic understanding of how node modules work.
require("module") is a synchronous call. The complete module is evaluated/"compiled" before the parser goes on with the next line of code. This means, that all dependencies are executed in the order they were specified. They are also only executed once per process. That means, that if you're requiring the same module multiple times, it is only executed at the first time and its module.exports is cached.
I suggest reading the docs.

Categories

Resources