152

Is it easy/possible to do a simple include('./path/to/file') type of command in node.js?

All I want to do is have access to local variables and run a script. How do people typically organize node.js projects that are bigger than a simple hello world? (A fully functional dynamic website)

For example I'd like to have directories like:

/models

/views

... etc

blissini
  • 545
  • 1
  • 7
  • 18
Travis
  • 7,391
  • 12
  • 43
  • 52
  • It's also possible to include a script from an external URL (instead of a local file). See here: http://pastebin.com/WkvHjGsG – Anderson Green Jan 03 '13 at 07:06
  • The script above only works correctly if you create a folder called `downloadedModules` in the same directory as the script. – Anderson Green Jan 03 '13 at 07:12

6 Answers6

150

Just do a require('./yourfile.js');

Declare all the variables that you want outside access as global variables. So instead of

var a = "hello" it will be

GLOBAL.a="hello" or just

a = "hello"

This is obviously bad. You don't want to be polluting the global scope. Instead the suggest method is to export your functions/variables.

If you want the MVC pattern take a look at Geddy.

JJJ
  • 32,902
  • 20
  • 89
  • 102
Shripad Krishna
  • 10,463
  • 4
  • 52
  • 65
100

You need to understand CommonJS, which is a pattern to define modules. You shouldn't abuse GLOBAL scope that's always a bad thing to do, instead you can use the 'exports' token, like this:

// circle.js

var PI = 3.14; // PI will not be accessible from outside this module

exports.area = function (r) {
  return PI * r * r;
};

exports.circumference = function (r) {
  return 2 * PI * r;
};

And the client code that will use our module:

// client.js

var circle = require('./circle');
console.log( 'The area of a circle of radius 4 is '
           + circle.area(4));

This code was extracted from node.js documentation API:

http://nodejs.org/docs/v0.3.2/api/modules.html

Also, if you want to use something like Rails or Sinatra, I recommend Express (I couldn't post the URL, shame on Stack Overflow!)

Ivan Torres
  • 1,661
  • 1
  • 10
  • 14
66

If you are writing code for Node, using Node modules as described by Ivan is without a doubt the way to go.

However, if you need to load JavaScript that has already been written and isn't aware of node, the vm module is the way to go (and definitely preferable to eval).

For example, here is my execfile module, which evaluates the script at path in either context or the global context:

var vm = require("vm");
var fs = require("fs");
module.exports = function(path, context) {
  var data = fs.readFileSync(path);
  vm.runInNewContext(data, context, path);
}

Also note: modules loaded with require(…) don't have access to the global context.

David Wolever
  • 148,955
  • 89
  • 346
  • 502
  • 1
    Thank you for this tip. The real use case is when you need to load modules adhoc. Say like a registration patterns where you would have a 1000 modules which register in a central service. It is much cleaner and better design to scan for modules and load them one by one rather than doing 1000 require statements in your service... – Assaf Moldavsky Aug 16 '16 at 22:42
  • Node supports dynamic requires, so there's no reason to use this pattern when dynamically loading Node-aware modules. In fact, it's actively harmful to use there, since it bypasses Node's `require.cache`, so a single file may be loaded multiple times. – David Wolever Aug 17 '16 at 13:49
  • Ok, so to solve the case that I presented where you have a 1000 modules where each is registering into a registry service, how do you use what you have proposed without having a 1000 require statements in the registry service? – Assaf Moldavsky Aug 18 '16 at 18:20
  • 1
    Just `require` like normal: `function loadService(name) { return require('./services/' + name); }` then list the services however makes sense for the application. – David Wolever Aug 18 '16 at 19:27
  • Right, but that implies you have to know all of the 1000 modules in the registry service. Which is no better than having a 1000 require statements. The whole idea is that the registry service does not know all of the modules and in fact it does care about them. Modules register ad hoc into the registry service. Does that make sense? – Assaf Moldavsky Aug 18 '16 at 19:58
  • If you are just saying doing require vs runInNewContext in the for loop i agree 100% and that is exactly what I am doing in my version of the code. – Assaf Moldavsky Aug 18 '16 at 19:59
  • Sorry, I'm not understanding. `runInNewContext` still requires that you know the path to the module… and provided the module is a valid Node module, that path can be passed to `require`. The only time you need `runInNewContext` is when the module isn't Node-aware. – David Wolever Aug 18 '16 at 21:04
  • Thank you, this approach is perfect for loading third-party code outside of our control, written without Node compatibility in mind. For ease of use, `require.resolve` comes in handy, too - it does the same magic that `require` would do under the hood to convert the identifier it's given to a file path to load. – ksadowski Oct 14 '20 at 11:47
11

If you are planning to load an external javascript file's functions or objects, load on this context using the following code – note the runInThisContext method:

var vm = require("vm");
var fs = require("fs");

var data = fs.readFileSync('./externalfile.js');
const script = new vm.Script(data);
script.runInThisContext();

// here you can use externalfile's functions or objects as if they were instantiated here. They have been added to this context. 
Rox
  • 327
  • 4
  • 7
  • 2
    After a lot of searching and frobbing, this technique worked for me. My files are written for the browser to use directly and declare a variable eg: const aVar = { thing: 'a' } – lucsan May 26 '19 at 13:36
6

Expanding on @Shripad's and @Ivan's answer, I would recommend that you use Node.js's standard module.export functionality.

In your file for constants (e.g. constants.js), you'd write constants like this:

const CONST1 = 1;
module.exports.CONST1 = CONST1;

const CONST2 = 2;
module.exports.CONST2 = CONST2;

Then in the file in which you want to use those constants, write the following code:

const {CONST1 , CONST2} = require('./constants.js');

If you've never seen the const { ... } syntax before: that's destructuring assignment.

Jonathan Benn
  • 2,908
  • 4
  • 24
  • 28
2

Sorry for resurrection. You could use child_process module to execute external js files in node.js

var child_process = require('child_process');

//EXECUTE yourExternalJsFile.js
child_process.exec('node yourExternalJsFile.js', (error, stdout, stderr) => {
    console.log(`${stdout}`);
    console.log(`${stderr}`);
    if (error !== null) {
        console.log(`exec error: ${error}`);
    }
});