3

I'm fairly new to Node.js and am having trouble understanding the way to go about loading libraries or files, in runtime. Apparently, it is a bad idea to load files in runtime using Node.js's native "require" function because it is blocking i/o, and therefore should not be used from within request handlers. So, I'm assuming something like this is to be avoided:

var http = require('http').createServer(function(req, res) { 
  var file = require('./pages/'+req.url);
  res.end();
}).listen(8080);

So then is there a way to require files in runtime, in a non-blocking/asynchronous way?

I don't think it would always be possible to load files in "boot time" rather than runtime because like in the example above, the only way to know what file to load/require is by getting the name through the req.url property.

So that seems like the only option. Unless, all the files in the folder are preloaded and then called upon by name, in the callback (By using fs.readdirSync or something to iterate through all the files in the folder and compare the gotten files' names to the req.url property), but that seems wasteful. "Preloading" all the files in the folder (maybe around 50 files) and then only using 1 of them, doesn't seem like a good idea. Am I wrong?

Either way, I would just like to know if there is a way to require files in runtime in a better, non-blocking/asynchronous way.

Thank you!

1 Answer 1

7

The function require() is generally used for caching modules or configuration files before most of your application runs. You can think of using require() somewhat like this:

var file = fs.readFileSync('/path');

// depending on the file type
eval(file);
JSON.parse(file);

The reason it is done this way is so that dependencies are loaded in order. If you want to read a file after initializing the application, you should use a asynchronous read, and respond in the callback like this:

var http = require('http');
http.createServer(function(req, res) {
  fs.readFile('./pages/' + req.url, function(err, data) {
    res.end(data);
  });
}).listen(8080);

If you needed to check if a file existed, then you could use fs.stat() to check the existence of a file, rather than querying the directory.

var http = require('http');
http.createServer(function(req, res) {
  var file = './pages/' + req.url;
  fs.stat(file, (err, stats) {
    if (err || !stats.isFile()) {
      res.writeHead(404);
      res.send();

      return;
    }

    fs.readFile(file, function(err, data) {
      res.writeHead(200);
      res.end(data);
    });
  });
}).listen(8080);
Sign up to request clarification or add additional context in comments.

8 Comments

Thank you! This works great for files like static HTML files, CSS files etc. But what if it's a Javascript file? How should I evaluate the Javascript code that I get from the file? eval isn't really a good idea so how should I do it?
But isn't that considered bad practice? I mean since require() is blocking?
I deleted my previous comment because it is misleading. I meant, if you have anything to execute, then you should require() it at the beginning of the application. That is how require() is and should be used. You shouldn't load functions into your application after it has started.
Oh I see. But that is really the problem, that I can't use require() inside the request handler, but that's where I need to include the file from. I can only know which file to require by getting the name through req.url. But the req.url is only accessible inside the request handler. I can't use require() anywhere before that because I won't know the name of the file until I get it through req.url.
If that's what you're looking for, then it isn't really possible. There once was an asynchronous require(), but it was seldom used and eventually removed. However, you could fork the main process and run code in another process. There are also modules which do similar things to eval(), such as the vm module, vm.runInNewContext() and vm.runInThisContext().
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.