Могу ли я загрузить несколько файлов с одним требованием?
Может быть, этот вопрос немного глуп, но возможно ли загрузить несколько файлов.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);