Node js & Подключение модулей без явного использования require или аналог namespace: различия между версиями
imported>Vix Нет описания правки |
imported>Vix Нет описания правки |
||
Строка 1: | Строка 1: | ||
При работе с node.js часто приходится подключать файлы, расположенные не в текущей директории, и даже не в поддереве текущего каталога. Поэтому часто в модулях можно наблюдать что-то вроде | При работе с node.js часто приходится подключать файлы, расположенные не в | ||
текущей директории, и даже не в поддереве текущего каталога. Поэтому часто в | |||
модулях можно наблюдать что-то вроде | |||
var obj = require('../../../a/b/c/someModule'); | var obj = require('../../../a/b/c/someModule'); | ||
Для меня гораздо удобнее подключать файлы относительно корня проекта (модуля), например | Для меня гораздо удобнее подключать файлы относительно корня проекта (модуля), | ||
например | |||
var obj = require(base_dir + '/a/b/c/someModule'); | var obj = require(base_dir + '/a/b/c/someModule'); | ||
Однако и в этом случае довольно много писанины и необходимо откуда-то получать base_dir. | Однако и в этом случае довольно много писанины и необходимо откуда-то получать | ||
Для себя я нашел решение проблемы, позволяющее больше не писать require и не узнавать base_dir: | base_dir. | ||
Для себя я нашел решение проблемы, позволяющее больше не писать require и не | |||
узнавать base_dir: | |||
var obj = lib.a.b.c.someModule; | var obj = lib.a.b.c.someModule; | ||
Строка 19: | Строка 24: | ||
Решение проблемы — создание хитрого «класса» (да простят меня гуру javascript за такое слово), свойствами которого являются директории и файлы указанной при создании класса директории. Если свойство-директория не является модулем, то данное свойство также является объектом нашего класса, свойствами которого являются директории и файлы этой директории. | Решение проблемы — создание хитрого «класса» (да простят меня гуру javascript за | ||
такое слово), свойствами которого являются директории и файлы указанной при | |||
создании класса директории. Если свойство-директория не является модулем, то | |||
данное свойство также является объектом нашего класса, свойствами которого | |||
являются директории и файлы этой директории. | |||
Чтобы стало понятнее — приведу пример. Предположим у нас имеется следующая структура проекта: | Чтобы стало понятнее — приведу пример. Предположим у нас имеется следующая | ||
структура проекта: | |||
Строка 29: | Строка 39: | ||
\a\index.js | \a\index.js | ||
var LazyLoader = require('./LazyLoader'); global.lib = new LazyLoader(__dirname); var foo = new lib.a.b.Foo(); console.log(foo.name); console.log(foo.bar.name); | var LazyLoader = require('./LazyLoader'); global.lib = new | ||
LazyLoader(__dirname); var foo = new lib.a.b.Foo(); console.log(foo.name); | |||
console.log(foo.bar.name); | |||
Строка 35: | Строка 47: | ||
Foo.js | Foo.js | ||
module.exports = function () { this.name = 'Foo'; this.bar = new lib.a.c.Bar(); }; | module.exports = function () { this.name = 'Foo'; this.bar = new | ||
lib.a.c.Bar(); }; | |||
Строка 47: | Строка 60: | ||
LazyLoader.js | LazyLoader.js | ||
var fs = require('fs'); var path = require('path'); function getter(key, dir, file) { delete this[key]; var fullPath = path.join(dir, file); try { require.resolve(fullPath); } catch (e) { if (fs.existsSync(fullPath)) { this[key] = new LazyLoader(path.join(dir, file)); } return this[key]; } | var fs = require('fs'); var path = require('path'); function getter(key, dir, | ||
file) { delete this[key]; var fullPath = path.join(dir, file); try | |||
{ require.resolve(fullPath); } catch (e) { if | |||
(fs.existsSync(fullPath)) { this[key] = new | |||
LazyLoader(path.join(dir, file)); } return this[key]; } | |||
this[key] = require(fullPath); return this[key]; } function LazyLoader(dir) | |||
{ var loader = this; if (!fs.existsSync(dir)) { return; } | |||
fs.readdirSync(dir).forEach(function(file) { var key = | |||
file.replace(/\.js$/, ''); loader.__defineGetter__(key, | |||
getter.bind(loader, key, dir, file)) }); } module.exports = LazyLoader; | |||
Строка 57: | Строка 79: | ||
В данном примере я использовал глобальную переменную lib. Если вы противник глобальных переменных (или вы просто разрабатываете отдельный публичный модуль) — то можно отказаться от глобальной переменной — в Foo.js придется написать, например, так: | В данном примере я использовал глобальную переменную lib. Если вы противник | ||
глобальных переменных (или вы просто разрабатываете отдельный публичный модуль) | |||
— то можно отказаться от глобальной переменной — в Foo.js придется написать, | |||
например, так: | |||
var path = require('path'); var LazyLoader = require('../../LazyLoader'); var lib = new LazyLoader(path.join(__dirname, '../../')); module.exports = function () { this.name = 'Foo'; this.bar = new lib.a.c.Bar(); }; | var path = require('path'); var LazyLoader = require('../../LazyLoader'); var | ||
lib = new LazyLoader(path.join(__dirname, '../../')); module.exports = function | |||
() { this.name = 'Foo'; this.bar = new lib.a.c.Bar(); }; | |||
И если у вас всего 1-2 подключаемых файла, то возможно данный подход покажется вам неуместным, но при большем количестве — вы должны ощутить существенное облегчение. | И если у вас всего 1-2 подключаемых файла, то возможно данный подход покажется | ||
Кроме того вы можете сохранять ссылки на директории для сокрашения записи, например: | вам неуместным, но при большем количестве — вы должны ощутить существенное | ||
облегчение. | |||
Кроме того вы можете сохранять ссылки на директории для сокрашения записи, | |||
например: | |||
var lib = new LazyLoader(__dirname); var logLig = lib.dir1.dir2.dir3.log; var f1 = new logLib.ConsoleLogger(); var f2 = new logLib.FileLogger(); // вместо // var f1 = new lib.dir1.dir2.dir3.log.ConsoleLogger(); // var f2 = new lib.dir1.dir2.dir3.log.FileLogger(); // и вместо // var f1 = new require(__dirname + '/dir1/dir2/dir3/log/ConsoleLogger)(); // var f2 = new require(__dirname + '/dir1/dir2/dir3/log/FileLogger)(); | var lib = new LazyLoader(__dirname); var logLig = lib.dir1.dir2.dir3.log; var | ||
f1 = new logLib.ConsoleLogger(); var f2 = new logLib.FileLogger(); // вместо // | |||
var f1 = new lib.dir1.dir2.dir3.log.ConsoleLogger(); // var f2 = new | |||
lib.dir1.dir2.dir3.log.FileLogger(); // и вместо // var f1 = new | |||
require(__dirname + '/dir1/dir2/dir3/log/ConsoleLogger)(); // var f2 = new | |||
require(__dirname + '/dir1/dir2/dir3/log/FileLogger)(); | |||
Строка 75: | Строка 110: | ||
1. Указанный подход позволяет имитировать аналог namespace в других языках. | 1. Указанный подход позволяет имитировать аналог namespace в других языках. | ||
2. Приведенный в примере LazyLoader легко расширить для работы с несколькими директориями, например, для смешвания или переопределения модулей: | 2. Приведенный в примере LazyLoader легко расширить для работы с несколькими | ||
директориями, например, для смешвания или переопределения модулей: | |||
var lib = new LazyLoader('globalLibDir', 'applicationSpecificLibDir'); | var lib = new LazyLoader('globalLibDir', 'applicationSpecificLibDir'); | ||
Строка 81: | Строка 117: | ||
3. Если Вы нашли неточности, опечатки или у вас есть альтернативные решения подключения модулей — пишите в ЛС. | 3. Если Вы нашли неточности, опечатки или у вас есть альтернативные решения | ||
подключения модулей — пишите в ЛС. | |||
ссылка на оригинал статьи http://habrahabr.ru/post/164665/ | ссылка на оригинал статьи http://habrahabr.ru/post/164665/ |
Версия от 14:55, 13 июня 2014
При работе с node.js часто приходится подключать файлы, расположенные не в
текущей директории, и даже не в поддереве текущего каталога. Поэтому часто в модулях можно наблюдать что-то вроде
var obj = require('../../../a/b/c/someModule');
Для меня гораздо удобнее подключать файлы относительно корня проекта (модуля),
например
var obj = require(base_dir + '/a/b/c/someModule');
Однако и в этом случае довольно много писанины и необходимо откуда-то получать
base_dir.
Для себя я нашел решение проблемы, позволяющее больше не писать require и не
узнавать base_dir:
var obj = lib.a.b.c.someModule;
Идея решения
Решение проблемы — создание хитрого «класса» (да простят меня гуру javascript за
такое слово), свойствами которого являются директории и файлы указанной при
создании класса директории. Если свойство-директория не является модулем, то
данное свойство также является объектом нашего класса, свойствами которого
являются директории и файлы этой директории.
Чтобы стало понятнее — приведу пример. Предположим у нас имеется следующая структура проекта:
Содержимое файлов:
\a\b\Foo.js \a\c\Bar.js \a\index.js
var LazyLoader = require('./LazyLoader'); global.lib = new
LazyLoader(__dirname); var foo = new lib.a.b.Foo(); console.log(foo.name); console.log(foo.bar.name);
Foo.js
module.exports = function () { this.name = 'Foo'; this.bar = new
lib.a.c.Bar(); };
Bar.js
module.exports = function () { this.name = 'Bar'; };
LazyLoader.js
var fs = require('fs'); var path = require('path'); function getter(key, dir,
file) { delete this[key]; var fullPath = path.join(dir, file); try { require.resolve(fullPath); } catch (e) { if (fs.existsSync(fullPath)) { this[key] = new LazyLoader(path.join(dir, file)); } return this[key]; } this[key] = require(fullPath); return this[key]; } function LazyLoader(dir) { var loader = this; if (!fs.existsSync(dir)) { return; }
fs.readdirSync(dir).forEach(function(file) { var key =
file.replace(/\.js$/, ); loader.__defineGetter__(key, getter.bind(loader, key, dir, file)) }); } module.exports = LazyLoader;
При запуске node index.js в консоли распечатается (как и ожидалось)
Foo Bar
В данном примере я использовал глобальную переменную lib. Если вы противник глобальных переменных (или вы просто разрабатываете отдельный публичный модуль) — то можно отказаться от глобальной переменной — в Foo.js придется написать, например, так:
var path = require('path'); var LazyLoader = require('../../LazyLoader'); var
lib = new LazyLoader(path.join(__dirname, '../../')); module.exports = function () { this.name = 'Foo'; this.bar = new lib.a.c.Bar(); };
И если у вас всего 1-2 подключаемых файла, то возможно данный подход покажется
вам неуместным, но при большем количестве — вы должны ощутить существенное
облегчение.
Кроме того вы можете сохранять ссылки на директории для сокрашения записи,
например:
var lib = new LazyLoader(__dirname); var logLig = lib.dir1.dir2.dir3.log; var
f1 = new logLib.ConsoleLogger(); var f2 = new logLib.FileLogger(); // вместо // var f1 = new lib.dir1.dir2.dir3.log.ConsoleLogger(); // var f2 = new lib.dir1.dir2.dir3.log.FileLogger(); // и вместо // var f1 = new require(__dirname + '/dir1/dir2/dir3/log/ConsoleLogger)(); // var f2 = new require(__dirname + '/dir1/dir2/dir3/log/FileLogger)();
Заключение
1. Указанный подход позволяет имитировать аналог namespace в других языках.
2. Приведенный в примере LazyLoader легко расширить для работы с несколькими директориями, например, для смешвания или переопределения модулей:
var lib = new LazyLoader('globalLibDir', 'applicationSpecificLibDir');
3. Если Вы нашли неточности, опечатки или у вас есть альтернативные решения подключения модулей — пишите в ЛС.
ссылка на оригинал статьи http://habrahabr.ru/post/164665/