Могу ли я загрузить несколько файлов с одним требованием?

Может быть, этот вопрос немного глуп, но возможно ли загрузить несколько файлов.js одним оператором require? как это:

var mylib = require('./lib/mylibfiles');

и использовать:

mylib.foo(); //return "hello from one"

mylib.bar(): //return "hello from two"

А в папке mylibfiles будет два файла:

One.js

exports.foo= function(){return "hello from one";}

Two.js

exports.bar= function(){return "hello from two";}

Я думал положить файл package.json в папку с надписью загрузить все файлы, но я не знаю как. Другой подход, о котором я думал, - это иметь index.js, который снова экспортирует все, но я буду дублировать работу.

Спасибо!!

PD: я работаю с nodejs v0.611 на машине с Windows 7

3 ответа

Решение

Прежде всего с помощью require ничего не дублирует. Он загружает модуль и кэширует его, вызывая require снова получит его из памяти (таким образом, вы можете модифицировать модуль на лету, не взаимодействуя с его исходным кодом - это иногда желательно, например, когда вы хотите сохранить соединение БД внутри модуля).

Также package.json ничего не загружает и вообще не взаимодействует с вашим приложением. Он используется только для npm,

Теперь вы не можете требовать нескольких модулей одновременно. Например, что произойдет, если оба One.js а также Two.js определили функцию с тем же именем?? Есть еще проблемы.

Но что вы можете сделать, это написать дополнительный файл, скажем, modules.js со следующим содержанием

module.exports = {
   one : require('./one.js'),
   two : require('./two.js'),
   /* some other modules you want */
}

и тогда вы можете просто использовать

var modules = require('./modules.js');
modules.one.foo();
modules.two.bar();

У меня есть фрагмент кода, который требует более одного модуля, но он не объединяет их вместе, как предлагает ваш пост. Однако это можно преодолеть с помощью хитрости, которую я нашел.

function requireMany () {
    return Array.prototype.slice.call(arguments).map(function (value) {
        try {
            return require(value)
        }
        catch (event) {
            return console.log(event)
        }
    })
}

И вы используете его как таковой

requireMany("fs", "socket.io", "path")

Который вернется

[ fs {}, socketio {}, path {} ]

Если модуль не найден, на консоль будет отправлено сообщение об ошибке. Это не сломает программу. Ошибка будет показана в массиве как неопределенная. Массив не будет короче, потому что один из модулей не удалось загрузить.

Затем вы можете привязать каждый из этих элементов массива к имени переменной, например, так:

var [fs, socketio, path] = requireMany("fs", "socket.io", "path")

По сути, он работает как объект, но назначает ключи и их значения глобальному пространству имен. Итак, в вашем случае вы можете сделать:

var [foo, bar] = requireMany("./foo.js", "./bar.js")
foo() //return "hello from one"
bar() //return "hello from two"

И если вы действительно хотите, чтобы программа сломалась при ошибке, просто используйте эту модифицированную версию, которая меньше

function requireMany () {
    return Array.prototype.slice.call(arguments).map(require)
}

Вы можете использовать назначение деструктуризации для отображения массива экспортированных модулей из require заявления в одну строку:

const requires = (...modules) => modules.map(module => require(module));
const [fs, path] = requires('fs', 'path');

Да, вам может потребоваться папка в качестве модуля, в соответствии с документами узла. Допустим, вы хотите потребовать () папку с именем ./mypack/,

внутри ./mypack/, создать package.json файл с name папки и main файл JavaScript с тем же именем, внутри ./lib/ каталог.

{
  "name" : "mypack",
  "main" : "./lib/mypack.js"
}

Теперь вы можете использовать require('./mypack') и узел загрузит ./mypack/lib/mypack.js,

Однако, если вы не включите это package.json файл, он все еще может работать. Без файла узел будет пытаться загрузить ./mypack/index.jsили если этого нет, ./mypack/index.node,

Насколько я понимаю, это может быть полезно, если вы разбили свою программу на множество файлов javascript, но не хотите объединять их для развертывания.

Я делал что-то похожее на то, что предлагает @freakish в своем ответе, с проектом, в котором у меня есть список тестовых скриптов, которые втянуты в настройку тестирования Puppeteer + Jest. Мои тестовые файлы следуют соглашению об именах testname1.js - testnameN.js, и я смог использовать функцию генератора, чтобы потребовать N файлов из определенного каталога с помощью следующего подхода:

const fs = require('fs');
const path = require('path');

module.exports = class FilesInDirectory {

    constructor(directory) {

        this.fid = fs.readdirSync(path.resolve(directory));
        this.requiredFiles = (this.fid.map((fileId) => {
            let resolvedPath = path.resolve(directory, fileId);
            return require(resolvedPath);
        })).filter(file => !!file);

    }

    printRetrievedFiles() {
        console.log(this.requiredFiles);
    }

    nextFileGenerator() {

        const parent = this;
        const fidLength = parent.requiredFiles.length;

        function* iterate(index) {
            while (index < fidLength) {
                yield parent.requiredFiles[index++];
            }
        }
        return iterate(0);
    }

}

Затем используйте так:

//Use in test
const FilesInDirectory = require('./utilities/getfilesindirectory');
const StepsCollection = new FilesInDirectory('./test-steps');
const StepsGenerator = StepsCollection.nextFileGenerator();

//Assuming we're in an async function
await StepsGenerator.next().value.FUNCTION_REQUIRED_FROM_FILE(someArg);
Другие вопросы по тегам