Node.JS Get rid of require () forever

    Analyzing the source codes of past projects, the popularity rating of direct function calls showed that a direct call require()is found in node-module code almost as often as Array#forEach(). The most annoying thing is that most often we plug in modules "util", "fs"and "path", a little less often "url". The presence of other connected modules depends on the task of the module. Moreover, speaking of the module "util", it is loaded into the memory of the node process, even if you have never connected it.

    In a previous Node.JS article Downloading Modules on DemandI talked about the possibility of automatically loading a module the first time I access its named link. To be honest, at the time of writing that article, I was not sure that this approach would not cause strange behavior of the node process. But, today I can proudly guarantee that it demandLoad()has been working for half a year in production. As we just did not drive it ... This is a load testing of a specific process, and work demandLoad()in the worker processes of clusters, and the work of the process under a small load for a long time. Results were compared using demandLoad()and using require(). No significant deviations in comparison were observed.

    Today it’s not about stability anymore.demandLoad(). If anyone is interested, ask questions in the comments, take screenshots, I can talk about test methods and tools, other possibilities of using the approach. Today, as follows from the title of the article, we will get rid of those who have already got tired of it require()in the caps of each node-module.

    I note in advance, in no case do I agitate to use the proposed method in production. The practice is presented for familiarization and does not claim to be a “true practice”. A loud headline is just to get attention.

    Suppose we are working on a project with the name "mytestsite.com", and we have it here:

    ~/projects/mytestsite.com

    Create an executable file of our project, for example, at:

    ~/projects/mytestsite.com/lib/bin/server.js

    Inside we will try to call the connected modules without preliminary require():

    console.log(util.inspect(url.parse('https://habrahabr.ru/')));

    Now create a file "require-all.js"somewhere, outside of all projects.
    For example, here:

    ~/projects/general/require-all.js

    According to the documentation , all the predefined variables and constants of each node module are properties global. Accordingly, we can define our global objects. So we must do with all the modules we use.

    Fill the require-all.jslist of all used modules in all projects:

    // нет смысла оставлять неподгруженным модуль "util",
    // т.к. его все равно до загрузки подгружает модуль "console".
    // А console.log(), если ему передать объект единственным параметром,
    // в свою очередь вызывает util.inspect()
    global.util = require('util');
    // так выглядит подключение других стандартных модулей, например:
    demandLoad(global, 'fs', 'fs');
    demandLoad(global, 'path', 'path');
    demandLoad(global, 'url', 'url');
    // абсолютно так же выглядит подключение npm-модулей, например:
    demandLoad(global, 'express', 'express');
    // а, вот, например, так можно подключить локальный модуль:
    demandLoad(global, 'routes', './../mytestsite.com/lib/routes');
    // определение demandLoad
    function demandLoad(obj, name, modPath){
    // тело вырезано для простоты схемы
    // необходимо взять из статьи по ссылке выше.
    }
    

    You can present the list of modules in the form of an array or a map ( Map), and, for example, go through it / it in a loop so as not to repeat a line of code with a call demandLoad(). You can, for example, read the list of used npm modules from package.json. If, for example, the number of modules used is very high, and you do not want to clog the global scope, you can define, for example, an empty object m( let m = {}), define it min global( global['m'] = m), and mapply it to it already demandLoad(). As they say, to whom it is more convenient.

    Now, it remains only to launch this economy. Add the key --requireto launch node (version> = 4.x):

    node    --require ~/projects/general/require-all.js \
            ~/projects/mytestsite.com/lib/bin/server.js
    

    There are no errors. The script worked as it should:

    Url {
      protocol: 'https:',
      slashes: true,
      auth: null,
      host: 'habrahabr.ru',
      port: null,
      hostname: 'habrahabr.ru',
      hash: null,
      search: null,
      query: null,
      pathname: '/',
      path: '/',
      href: 'https://habrahabr.ru/' }

    If you have many projects, for the convenience of project deployment, you can create your own require-all.jsinside each project individually.

    node    --require ~/projects/mytestsite.com/lib/require-all.js \
            ~/projects/mytestsite.com/lib/bin/server.js

    Expanding the last case, I note that you can even use several of these require-all.jsat the same time:

    node    --require ~/projects/general/require-all.js \
            --require ~/projects/mytestsite.com/lib/require-all.js \
            ~/projects/mytestsite.com/lib/bin/server.js

    As noted in a comment below , the --require+ bundle globalcan also be used to extend / overload the standard features of node.

    Finally, I repeat from the last article: If it is demandLoad()defined not in our file (1) (where we call it from demandLoad()), but in some file (2), moreover, file (1) and file (2) are in different directories, the last parameter must be transferred full path to the module, for example:

    demandLoad(global, 'routes', path.join(__dirname, './../mytestsite.com/lib/routes'));

    Otherwise, the one require()that is called from demandLoad()will search for the module relative to the folder where the same file (2) with the description is located demandLoad(), instead of looking for the module relative to the file (1) from where we call demandLoad().

    Thanks for attention. Successful refactoring to everyone!

    Also popular now: