Анализируя исходные коды прошлых проектов, рейтинг популярности прямых вызовов функций показал, что прямой вызов
В прошлой статье Node.JS Загрузка модулей по требованию я поведал о возможности автоматической загрузкой модуля при первом обращении к его именованной ссылке. Если честно, на момент написания той статьи, я не был уверен в том, что такой подход не станет причиной странного поведения node-процесса. Но, уже сегодня с гордостью могу ручаться, что
Сегодня речь пойдет уже не о стабильности
Заранее отмечу, ни в коем случае не агитирую использовать предложенный метод в продакшене. Практика изложена для ознакомления и не претендует на статус «true-практики». Громкий заголовок только для привлечения внимания.
Предположим, мы работаем над проектом с названием
Создадим исполняемый файл нашего проекта, например, по адресу:
Внутри попробуем вызвать подключенные модули без предварительных
Теперь создадим файл
Например, здесь:
Согласно документации, все предопределенные переменные и константы каждого node-модуля являются свойствами
Наполним
Можно представить список модулей в виде массива или карты (
Теперь, осталось лишь запустить это хозяйство. Добавим ключ
Ошибок нет. Скрипт отработал как надо:
Если у вас много проектов, для удобства разворачивания проектов, можно создать по своему
Расширяя последний случай, отмечу, можно даже использовать несколько таких
Как отмечено в комментарии ниже, связка
Напоследок, повторюсь из прошлой статьи: Если
Иначе, тот
Спасибо за внимание. Всем удачного рефакторинга!
require()
встречается в коде node-модулей почти так же часто, как Array#forEach()
. Самое обидное, что чаще всего мы подключаем модули "util"
, "fs"
и "path"
, чуть реже "url"
. Наличие других подключенных модулей зависит уже от задачи модуля. Причем, говоря о модуле "util"
, загружается в память node-процесса даже если вы ни разу его не подключали.В прошлой статье Node.JS Загрузка модулей по требованию я поведал о возможности автоматической загрузкой модуля при первом обращении к его именованной ссылке. Если честно, на момент написания той статьи, я не был уверен в том, что такой подход не станет причиной странного поведения node-процесса. Но, уже сегодня с гордостью могу ручаться, что
demandLoad()
работает уже пол года в продакшене. Как мы его только не гоняли… Это и нагрузочное тестирование конкретного процесса, и работа demandLoad()
в worker-процессах кластеров, и работа процесса под небольшой нагрузкой в течении долгого времени. Результаты сравнивались с использованием demandLoad()
и с использованием require()
. Никаких существенных отклонений в сравнении не было замечено.Сегодня речь пойдет уже не о стабильности
demandLoad()
. Если кому интересно, задавайте вопросы в комментариях, сделаю скриншоты, могу рассказать о методах и инструментах тестирования, других возможностях использования подхода. Сегодня, как следует из заголовка статьи, мы будем избавляться от успевших уже надоесть require()
в шапках каждого node-модуля.Заранее отмечу, ни в коем случае не агитирую использовать предложенный метод в продакшене. Практика изложена для ознакомления и не претендует на статус «true-практики». Громкий заголовок только для привлечения внимания.
Предположим, мы работаем над проектом с названием
"mytestsite.com"
, и находится он у нас здесь:~/projects/mytestsite.com
Создадим исполняемый файл нашего проекта, например, по адресу:
~/projects/mytestsite.com/lib/bin/server.js
Внутри попробуем вызвать подключенные модули без предварительных
require()
:console.log(util.inspect(url.parse('https://habrahabr.ru/')));
Теперь создадим файл
"require-all.js"
где-нибудь, вне всех проектов.Например, здесь:
~/projects/general/require-all.js
Согласно документации, все предопределенные переменные и константы каждого node-модуля являются свойствами
global
. Соответственно, мы можем определять и свои глобальные объекты. Так мы должны поступить со всеми используемыми нами модулями.Наполним
require-all.js
списком всех используемых модулей во всех проектах:// нет смысла оставлять неподгруженным модуль "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){
// тело вырезано для простоты схемы
// необходимо взять из статьи по ссылке выше.
}
Можно представить список модулей в виде массива или карты (
Map
), и, например, пройтись по нему/ней циклом, чтобы не повторять строчку кода с вызовом demandLoad()
. Можно, например, прочитать список используемых npm-модулей из package.json
. Если, например, количество используемых модулей очень высокое, и не хочется засорять глобальный скоуп, можно определить, например, пустой объект m
(let m = {}
), определить m
в global
(global['m'] = m
), и уже к m
применять demandLoad()
. Как говорится, кому как удобнее.Теперь, осталось лишь запустить это хозяйство. Добавим ключ
--require
к запуску node (версии >= 4.x):node --require ~/projects/general/require-all.js \
~/projects/mytestsite.com/lib/bin/server.js
Ошибок нет. Скрипт отработал как надо:
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/' }
Если у вас много проектов, для удобства разворачивания проектов, можно создать по своему
require-all.js
внутри каждого проекта по отдельности.node --require ~/projects/mytestsite.com/lib/require-all.js \
~/projects/mytestsite.com/lib/bin/server.js
Расширяя последний случай, отмечу, можно даже использовать несколько таких
require-all.js
одновременно:node --require ~/projects/general/require-all.js \
--require ~/projects/mytestsite.com/lib/require-all.js \
~/projects/mytestsite.com/lib/bin/server.js
Как отмечено в комментарии ниже, связка
--require
+global
также может быть использована для расширения/перегрузки стандартных возможностей node.Напоследок, повторюсь из прошлой статьи: Если
demandLoad()
определена не в нашем файле(1) (откуда вызываем demandLoad()
), а в каком-нибудь файле(2), причем файл(1) и файл(2) находятся в разных директориях, последним параметром необходимо передавать полный путь до модуля, например:demandLoad(global, 'routes', path.join(__dirname, './../mytestsite.com/lib/routes'));
Иначе, тот
require()
, что вызывается из demandLoad()
будет искать модуль относительно папки, где расположили тот самый файл(2) с описанием demandLoad()
, вместо того, чтобы искать модуль относительно файла(1), откуда мы вызываем demandLoad()
.Спасибо за внимание. Всем удачного рефакторинга!