Некоторое время назад я создал библиотеку на NodeJS, чтобы упростить рендеринг на стороне сервера и клиента. Он использует React и React Router для отображения соответствующего HTML на веб-сайте. Хотя рендеринг HTML на сервере и клиенте с помощью React прост, во время разработки обычно возникают различные специфические проблемы, например, как отправить состояние во внешний интерфейс или как внедрить React на веб-сайт. Цель моей библиотеки - решить их.

Структура проекта

Все модули npm, необходимые моей библиотеке для правильной работы, должны быть сначала загружены с помощью npm, а затем объединены с исходным кодом, написанным для конкретного проекта, в один файл JavaScript, используемый веб-браузером. Библиотека использует Browserify для объединения файлов JavaScript самостоятельно. На сервере NodeJS может напрямую читать модули CommonJS, поэтому такой процесс не требуется.

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

project:
-- react (for creating React components)
-- my library:
---- react (for rendering React components)

Обратите внимание, что React присутствует дважды. Моя библиотека должна использовать React, в частности, его метод renderToString для рендеринга на стороне сервера. Кроме того, при запуске Browserify он динамически заменяет вызовы require(‘moduleX’) ссылками на пользовательские модули, созданные для этого конкретного проекта, если это необходимо. Благодаря такому подходу библиотеку легко запускать с разумными значениями по умолчанию и при необходимости настраивать различными способами. Но есть и обратная сторона этого подхода. Если Browserify и React используются проектом напрямую, код на стороне клиента будет иметь две отдельные версии React. Что еще хуже, React загрузится дважды и начнет работать некорректно. Обнаружить такую ​​ситуацию непросто, поскольку React не предупредит об этом. Вместо этого он просто выдает ошибки там, где не должен. Например, в моих тестовых проектах в объекте this.props отсутствовали некоторые свойства, которые обычно были бы внедрены в него.

Описанная выше проблема связана с чем-то более общим в старых версиях npm — они создают иерархию папок node_modules. Таким образом, проект получает один node_modules, моя библиотека получает другой, и все связанные с ним модули получают node_modules, если они в этом нуждаются. Таким образом, просто поместив React в package.json в основном проекте, и моя библиотека создаст дубликат загрузки React и вызовет проблемы, но они оба должны иметь его. Browserify не виноват, потому что он не может легко понять, что нужно ссылаться на одну конкретную папку с React.

Решение

Вот где в игру вступают peerDepencencies. Его формат такой же, как для зависимостей или ключей devDependencies внутри package.json. Но если peerDependencies помещается в package.json для моей библиотеки и я выполняю установку npm в каталоге проекта, React будет добавлен только в одну папку node_modules. И если я нахожусь в процессе разработки библиотеки отдельно от проекта, я могу в этом случае npm установить peerDepencies и таким образом получить React с немного большей работой.

Теперь о том, почему npm3 лучше в этом случае. Npm3 полностью сглаживает иерархию. Выполнение npm install в npm 3 создает одну папку node_modules, в которой был найден ближайший package.json. С одной стороны, плоская иерархия сбрасывает все зависимости в одну папку, что затрудняет управление во время разработки. С другой:

  • Теперь Windows может обрабатывать сложные файлы package.json. В npm 1 и 2 при выполнении npm install в Windows создавалась длинная иерархия папок, которую система не могла правильно обработать. Разработчикам пришлось использовать что-то вроде rimraf, чтобы удалить его, потому что операционная система не могла этого сделать.
  • peerDependencies больше не нужен. npm3 предупреждает об отсутствии одноранговых зависимостей, но больше не будет устанавливать их с помощью старой доброй установки npm. Плоская иерархия папок эффективно устраняет мою проблему с наличием двух модулей React в двух отдельных папках node_modules. Многие другие библиотеки также имели эту проблему из-за того, как они работали.
  • Нет дублирования библиотек. Например, даже если несколько библиотек зависят от React, они будут существовать только в одной папке node_modules, если разработчик явно не загрузит их во многие.
  • У меня всегда были проблемы с объяснением разработчикам, как работает peerDependencies, потому что он пытался решить проблему, связанную с тем, как должны работать некоторые библиотеки.

Резюме

Используйте npm3, особенно если вы разрабатываете модули узлов. Я рад, что peerDependencies прекращают свое существование, я не пропущу этого. Хотя всегда установка последней версии npm может показаться легкой задачей, и в этом случае моя проблема решена лучше, знание того, почему проблема, с которой я столкнулся, возникла в первую очередь, и поиск способов ее решения дало мне лучшее понимание управления зависимостями. .

Этот пост был вдохновлен https://codingwithspike.wordpress.com/2016/01/21/dealing-with-the-deprecation-of-peerdependencies-in-npm-3/. Джефф объясняет другую проблему, которую решает peerDependencies, которую стоит прочитать.