Что такое node modules
Использование модулей Node.js с приложениями Azure
Этот документ содержит указания по использованию модулей Node.js с приложениями, размещенными в Azure. В нем описывается, как обеспечить использование конкретной версии модуля приложением и использовать собственные модули в Azure.
Возможно, вы уже знакомы с использованием модулей Node.js, файлов package.json и npm-shrinkwrap.json. Ниже приводится краткая сводка по тем вопросам, которые рассматриваются в этой статье.
Служба приложений Azure может считывать файлы package.json и npm-shrinkwrap.json и устанавливать модули на основании записей в этих файлах.
Облачные службы Azure предполагают, что все модули будут установлены в среде разработки, а node_modules каталог будет включен в состав пакета развертывания. Можно включить поддержку установки модулей с помощью файлов package.json или npm-shrinkwrap.json в облачных службах, однако для такой конфигурации требуется настройка сценариев по умолчанию, используемых проектами облачных служб. Пример того, как настроить эту среду, см. в записи блога Azure Startup task to run npm install to avoid deploying node modules (Задача запуска Azure для выполнения установки npm во избежание развертывания модулей узла).
В данной статье не рассматриваются виртуальные машины Azure, так как процедура развертывания на виртуальной машине зависит от операционной системы, размещенной в этой виртуальной машине.
Модули Node.js
Модули — это загружаемые пакеты JavaScript, предоставляющие вашему приложению определенные функциональные возможности. Модули обычно устанавливаются с помощью программы командной строки npm, однако некоторые из них (например, HTTP-модуль) предоставляются в составе основного пакета Node.js.
При установке модулей они хранятся в каталоге node_modules в корне структуры каталогов приложения. Каждый модуль в каталоге node_modules обслуживает собственный каталог, который содержит все модули, от которых он зависит, и это поведение повторяется для всех модулей в цепочке зависимостей. Эта среда позволяет каждому установленному модулю иметь собственные требования к версиям модулей, от которых он зависит, однако это может привести к слишком большому размеру структуры каталогов.
Развертывание каталога node_modules в составе приложения увеличивает размер развертывания по сравнению с использованием файла Package. JSON или NPM-shrinkwrap. JSON ; Однако это гарантирует, что версии модулей, используемых в рабочей среде, будут такими же, как и модули, используемые при разработке.
Собственные модули
Служба приложений Azure не поддерживает все собственные модули и может сообщать об ошибках при компиляции модулей со специфическими предварительными требованиями. Хотя у некоторых популярных модулей, например MongoDB, имеются дополнительные собственные зависимости, и они прекрасно работают без них, было найдено два обходных решения, подходящих почти для всех собственных модулей, доступных в настоящее время:
Выполните npm install на компьютере под управлением Windows, на котором установлены все необходимые компоненты собственного модуля. Затем разверните созданную папку node_modules как часть приложения в службе приложений Azure.
Использование файла package.json
Файл Package. JSON — это способ указать зависимости верхнего уровня, необходимые вашему приложению, чтобы платформа размещения могла установить зависимости, а не требовать включения папки node_modules в составе развертывания. После развертывания приложения используется команда npm install, чтобы проанализировать файл package.json и установить все указанные зависимости.
Во время разработки можно использовать параметры —save, —save-dev или —save-optional при установке модулей, чтобы автоматически добавить запись для модуля в файл package.json. Дополнительные сведения см. в разделе с описанием npm-install.
Одна потенциальная проблема с файлом package.json заключается в том, что он указывает версию только для зависимостей верхнего уровня. Каждый установленный модуль может указать или не указывать версию модулей, от которых он зависит, поэтому в результате вы можете получить иную цепочку зависимостей, чем в среде разработки.
Если при развертывании приложения в службе приложений Azure ваш файл package.json ссылается на собственный модуль, то может отобразиться ошибка, аналогичная той, что возникает при публикации приложения с помощью Git:
npm ERR! модуль-name@0.6.0 install: «node-gyp Configure Build»
npm ERR! ‘cmd «/c» «node-gyp configure build»‘ failed with 1
Использование файла NPM-shrinkwrap. JSON
Файл npm-shrinkwrap.json представляет собой попытку устранения ограничений управления версиями модуля для файла package.json. Хотя файл package.json содержит только версии модулей верхнего уровня, файл npm-shrinkwrap.json содержит требования к версиям для всей цепочки зависимостей модулей.
Если при развертывании приложения в службе приложений Azure ваш файл npm-shrinkwrap.json ссылается на собственный модуль, то может отобразиться ошибка, аналогичная той, что возникает при публикации приложения с помощью Git:
npm ERR! модуль-name@0.6.0 install: «node-gyp Configure Build»
npm ERR! ‘cmd «/c» «node-gyp configure build»‘ failed with 1
Модули¶
Node.js использует модульную систему. То есть вся встроенная функциональность разбита на отдельные пакеты или модули. Модуль представляет блок кода, который может использоваться повторно в других модулях.
При необходимости мы можем подключать нужные нам модули. Какие встроенные модули есть в node.js и какую функциональность они предоставляют, можно узнать из документации.
После получения модуля мы сможем использовать весь определенный в нем функционал, который опять же можно посмотреть в документации.
В файле app.js подключим наш модуль:
В отличие от встроенных модулей для подключения своих модулей надо передать в функцию require относительный путь с именем файла (расширение файла необязательно):
Теперь изменим файл greeting.js :
Вообще объект module представляет ссылку на текущий модуль, а его свойство exports определяет все свойства и методы модуля, которые могут быть экспортированы и использованы в других модулях. Подробнее определение загрузки модуля и все его функции можно посмотреть на странице https://github.com/nodejs/node/blob/master/lib/module.js.
Далее изменим файл app.js :
Определение конструкторов и объектов в модуле¶
Кроме определения простейших функций или свойств в модуле могут определяться сложные объекты или функции конструкторов, которые затем используются для создания объектов. Так, добавим в папку проекта новый файл user.js :
Что такое node modules
Вместе с Node поставляется несколько стандартных встроенных модулей, большинство из которых описано ниже.
Стандартные модули можно найти в папке lib/ исходного кода node.
Загрузка из папок node_modules
Если по этому пути модуль не будет найден, то node переходит к родительской папке и так далее, пока не будет достигнут корень файловой системы.
Это позволяет программам локализовывать их зависимости, чтобы они не конфликтовали.
Этим ограничивается осведомлённость node о файлах package.json.
Если файла package.json в папке нет, то node будет пытаться загрузить index.js или index.node в этой папке. При этом require(‘./some-library’) попробует загрузить:
Модули кешируются при первой загрузке. Это, кроме остального, означает, что каждый вызов require(‘foo’) возвращает точно тотже объект, если модуль разрешается в тоже самое имя файла.
Множественные вызовы require(‘foo’) не вызывают повторной компиляции кода. Это очень важно. С помощью этого можно возвращать «частично готовые» объекты, позволяя транзитивным зависимостям загружаться даже если в нормальной ситуации это вызовет цикл зависимостей.
Если вы хотите выполнять код модуля несколько раз, то вам следует экспортировать из него функцию и исполнять её в вашем коде.
Будьте осторожны с кешированием модулей
Модули кешируются в зависимости от имён файлов, в которые они разрешаются. Так как один и тот же модуль может разрешаться в разные файлы в зависимости от того, из какого модуля он вызывается (например при загрузке из папки node_modules ), ничто не гарантирует, что require(‘foo’) всегда будет возвращать один и тот же объект.
Тогда в другом модуле вы можете использовать его следующим образом:
Нужно иметь в виду, что присваивание module.exports должно происходить в основном коде модуля, а не в каких-либо коллбеках. Следующий код работать не будет:
Собирая всё вместе.
Учитывая всё вышесказанное, можно составить следующий высокоуровневый псевдокод для require() :
Загрузка из папок require.paths
Тогда вызов require(‘bar/baz.js’) будет проверять следующие файлы:
Массив require.paths может быть изменён во время выполнения программы.
Примечание: Пожалуйста, избегайте использования require.paths
Переменная require.paths будет поддерживаться только в стабильной ветке v0.4. Она удалена в ветке v0.5 и не будет присутствовать в стабильной ветке v0.6.
На данный момент это выглядит разумно и представляет простор для экспериментов. Но на практике изменение require.paths часто является причиной проблем и головной боли.
Присвоение require.paths другой переменной ничего не изменяет.
Этот код делает не то, что ожидается:
На практике некоторые используют это при включении зависимостей в модуль, но это хрупкая техника.
В результате, если один модуль полагается на это поведение, оно может быть изменено другими модулями, загруженными в этом процессе node. Как только приложение становится большим, труднопредсказуемое поведение может стать большой проблемой.
Доступ к главному модулю.
Дополнение: Советы для пакетных менеджеров
Прим. пер.: Эффективные менеджеры могут не читать этот раздел.
Ниже мы приводим предлагаемую структуру каталогов, которая должна быть.
Таким образом, даже если встретится цикл или другой конфликт зависимостей, каждый модуль сможет получить ту пакета, от которой он зависит.
Модули: модули CommonJS¶
В модульной системе Node.js каждый файл рассматривается как отдельный модуль. Например, рассмотрим файл с именем foo.js :
Вот содержание circle.js :
В module.exports свойству может быть присвоено новое значение (например, функция или объект).
Ниже, bar.js использует square модуль, который экспортирует класс Square:
В square модуль определен в square.js :
Модульная система реализована в require(‘module’) модуль.
Доступ к основному модулю¶
Советы менеджера пакетов¶
Ниже мы приводим предлагаемую структуру каталогов, которая может работать:
Допустим, мы хотели, чтобы папка находилась по адресу /usr/lib/node/ / хранить содержимое конкретной версии пакета.
Поскольку Node.js ищет realpath любых загружаемых модулей (то есть разрешает символические ссылки), а затем ищет их зависимости в node_modules папки, эту ситуацию можно разрешить с помощью следующей архитектуры:
Таким образом, даже если встречается цикл или если есть конфликты зависимостей, каждый модуль сможет получить версию своей зависимости, которую он может использовать.
Все вместе. ¶
Чтобы получить точное имя файла, которое будет загружено при require() называется, используйте require.resolve() функция.
Объединив все вышеперечисленное, вот высокоуровневый алгоритм в псевдокоде того, что require() делает:
Кеширование¶
Модули кэшируются после первой загрузки. Это означает (среди прочего), что каждый вызов require(‘foo’) вернет точно такой же объект, если он разрешится в тот же файл.
Предоставлена require.cache не модифицируется, многократные вызовы require(‘foo’) не приведет к многократному выполнению кода модуля. Это важная особенность. С его помощью можно возвращать «частично выполненные» объекты, что позволяет загружать транзитивные зависимости, даже если они вызывают циклы.
Чтобы модуль выполнял код несколько раз, экспортируйте функцию и вызовите эту функцию.
Предупреждения о кешировании модулей¶
Модули кэшируются на основе их разрешенного имени файла. Поскольку модули могут преобразовываться в другое имя файла в зависимости от местоположения вызывающего модуля (загрузка из node_modules папки), это не гарантия что require(‘foo’) всегда будет возвращать один и тот же объект, если он разрешается в разные файлы.
Основные модули¶
В Node.js есть несколько модулей, скомпилированных в двоичный файл. Эти модули более подробно описаны в других разделах этой документации.
Основные модули определены в исходном коде Node.js и расположены в lib/ папка.
Основные модули также можно идентифицировать с помощью node: префикс, и в этом случае он обходит require кеш. Например, require(‘node:http’) всегда будет возвращать встроенный HTTP-модуль, даже если есть require.cache запись с этим именем.
Циклы¶
Когда есть круговые require() вызовы, модуль мог не завершить выполнение, когда он был возвращен.
Рассмотрим эту ситуацию:
К тому времени main.js загрузил оба модуля, они оба готовы. Таким образом, результат этой программы будет:
Для правильной работы циклических зависимостей модулей в приложении требуется тщательное планирование.
Файловые модули¶
Папки как модули¶
Удобно организовать программы и библиотеки в автономные каталоги, а затем предоставить единую точку входа в эти каталоги. Существует три способа передачи папки в require() как аргумент.
Это степень осознания package.json файлы в Node.js.
Если нет package.json файл присутствует в каталоге, или если «main» запись отсутствует или не может быть разрешена, тогда Node.js попытается загрузить index.js или index.node файл из этого каталога. Например, если не было package.json файл в предыдущем примере, затем require(‘./some-library’) попытается загрузить:
Если эти попытки не удастся, Node.js сообщит об отсутствии всего модуля с ошибкой по умолчанию:
Загрузка из node_modules папки¶
Если его там нет, он перемещается в родительский каталог и так далее, пока не будет достигнут корень файловой системы.
Это позволяет программам локализовать свои зависимости, чтобы они не конфликтовали.
Можно потребовать определенные файлы или подмодули, распространяемые вместе с модулем, путем включения суффикса пути после имени модуля. Например require(‘example-module/path/to/file’) разрешит path/to/file относительно того, где example-module расположен. Путь с суффиксом следует той же семантике разрешения модуля.
Загрузка из глобальных папок¶
Если NODE_PATH Переменная среды установлена в список абсолютных путей, разделенных двоеточиями, тогда Node.js будет искать по этим путям модули, если они не найдены где-либо еще.
В Windows NODE_PATH разделяется точкой с запятой ( ; ) вместо двоеточия.
NODE_PATH изначально был создан для поддержки загрузки модулей с разных путей до текущего разрешение модуля алгоритм был определен.
NODE_PATH все еще поддерживается, но теперь он менее необходим, когда экосистема Node.js установила соглашение о размещении зависимых модулей. Иногда развертывания, основанные на NODE_PATH проявлять удивительное поведение, когда люди не знают, что NODE_PATH должен быть установлен. Иногда зависимости модуля меняются, в результате чего другая версия (или даже другой модуль) загружается как NODE_PATH ищется.
Кроме того, Node.js будет искать в следующем списке GLOBAL_FOLDERS:
Это в основном по историческим причинам.
Настоятельно рекомендуется размещать зависимости в локальном node_modules папка. Они будут загружаться быстрее и надежнее.
Оболочка модуля¶
Перед выполнением кода модуля Node.js обернет его оболочкой функции, которая выглядит следующим образом:
Таким образом Node.js достигает нескольких целей:
Объем модуля¶
__dirname ¶
Пример: бег node example.js из /Users/mjr
__filename ¶
Имя файла текущего модуля. Это абсолютный путь к текущему файлу модуля с разрешенными символическими ссылками.
Для основной программы это не обязательно то же самое, что имя файла, используемое в командной строке.
Видеть __dirname для имени каталога текущего модуля.
Бег node example.js из /Users/mjr
exports ¶
module ¶
require(id) ¶
require.cache ¶
Модули кэшируются в этом объекте, когда они требуются. Удалив значение ключа из этого объекта, следующий require перезагрузит модуль. Это не относится к нативные дополнения, для которых перезагрузка приведет к ошибке.
require.extensions ¶
Инструктировать require о том, как обрабатывать определенные расширения файлов.
Устарело. Раньше этот список использовался для загрузки модулей, отличных от JavaScript, в Node.js путем их компиляции по запросу. Однако на практике есть гораздо лучшие способы сделать это, например, загрузить модули через какую-нибудь другую программу Node.js или заранее скомпилировать их в JavaScript.
require.main ¶
В Module объект, представляющий сценарий входа, загружаемый при запуске процесса Node.js. Видеть «Доступ к основному модулю».
В entry.js сценарий:
require.resolve(request[, options]) ¶
Используйте внутренний require() машины для поиска местоположения модуля, но вместо загрузки модуля просто верните разрешенное имя файла.
Если модуль не может быть найден, MODULE_NOT_FOUND выдается ошибка.
require.resolve.paths(request) ¶
В module объект¶
module.children ¶
Объекты модуля, необходимые для этого впервые.
module.exports ¶
Например, предположим, что мы создаем модуль с именем a.js :
Затем в другом файле мы могли бы сделать:
Присвоение module.exports нужно сделать немедленно. Это невозможно сделать ни в каких обратных вызовах. Это не работает:
exports ярлык¶
В exports переменная доступна в пределах области файлового уровня модуля, и ей присваивается значение module.exports перед оценкой модуля.
Когда module.exports свойство полностью заменяется новым объектом, обычно также переназначается exports :
module.filename ¶
Полностью разрешенное имя файла модуля.
module.id ¶
Идентификатор модуля. Обычно это полностью разрешенное имя файла.
module.isPreloading ¶
module.loaded ¶
Независимо от того, загружается ли модуль или находится в процессе загрузки.
module.parent ¶
Модуль, который первым требовал этого, или null если текущий модуль является точкой входа текущего процесса, или undefined если модуль был загружен чем-то, что не является модулем CommonJS (например: REPL или import ).
Основы работы с модулями в Node.js
Любой проект посложнее «Hello World» состоит из некоторого количества файлов, по которым разносят код. Это дает возможность структурировать проект, вынести независимые части, которые можно будет использовать в других проектах и вообще сделать код нагляднее.
Вместе с Node.js поставляется несколько встроенных модулей, для подключения которых нужно просто указать название модуля.
Чтобы подключить модуль который находится в node_modules достаточно указать его название.
Поэтому нет необходимости указывать файл с расширением, так как require(‘./lib/users.js’) и require(‘./lib/users’) подключит один и тот же модуль.
Представим, что у нас есть модули и один и них logger представлен в виде папки с файлами:
Подключение модуля logger заключается в том, что мы просто передадим путь к этой папки:
Дальше Node.js сам попытается определить какой из файлов папки представляет собой точку входа для модуля. Для начала будет проверено или существует в папке файл package.json в котором будет указано в поле main имя файла, который нужно подключить.
С подключением модулей закончили, теперь рассмотрим несколько интересных моментов, связанных с ними. Независимо от того как вы подключаете модуль, он кэшируется сразу после подключения. Это означает, что сколько бы раз не подключался модуль, его код исполнится только один раз.
Это поведение можно изменить, если после каждого вызова модуля удалять его из кэша.
module — это параметр, который вы передавали функции require для подключения модуля.
Так что если вам нужно, чтобы ваш модуль каждый раз когда его подключают что-то выполнял — для этого нужно или чистить кэш, или возвращать функцию, которую нужно будет вызвать, что выполнить работу.
Эту функцию можно использовать, если у вас так случилось, что установлены модули разных версий в нескольких местах и нужно удостоверится, что подключается нужная версия. Нужно зайти в папку где лежит файл, в котором происходит подключение, запустить Node.js в режиме работы из командной строки и вызвать функцию с нужным модулем. Конечно, такая ситуация означает, что нужно пересмотреть структуру проекта и лучше вынести все подключаемые модули в корневую папку проекта.
Эту функцию также можно использовать если вы хотите подключить один из файлов модуля, который установлен через NPM.
Так как вы не знаете где находится папка node_modules с нужным модулем, можно воспользоваться тем, что Node.js сам пройдется по всем возможным местам расположения модуля.
В объекта module есть свойство exports и ему нужно присваивать все что вы хотите вернуть из модуля. Именно module.exports вернется как результат подключения модуля.
После подключения модуля с данным кодом, в ответе будет объект с данным методом.