Необязательные зависимости в npm?

23

У меня есть похожий вопрос к этому , но не совсем то же самое.

Я хотел бы, чтобы пользователь моего приложения установил его с любыми зависимостями, необходимыми для его использования. Так, например, если они хотят сохранить в MongoDB, будут установлены только библиотеки, связанные с Mongo, но если они хотят сохранить в Redis, будут установлены только библиотеки, связанные с Redis. Я не хочу заставлять их загружать и устанавливать библиотеки, которые они не будут использовать.

Я знаю, что могу сделать это для целей разработки devDependencies, но это идет еще дальше. Как говорится в ответе на вопрос выше, это более тесно связано с профилями Python setuptools extras_requireи Clojure leiningen. Что-нибудь подобное в npm? Я действительно чувствую, что devDependenciesдолжен быть devпрофиль более универсального способа определения зависимостей.

imiric
источник
Просто мысль, но вы могли бы пойти с несколькими пакетами. MyPackage-Core MyPackage-Db-Mongo MyPackage-Db-Redisи т. д. во многом люди делают модули, предназначенные для расширения angularjs .
Майк
@Mike: Хм спасибо, я рассмотрю это. Я все еще думаю, что это ограничение package.json, которое было решено в других менеджерах пакетов.
Имирик
1
Это отличный вопрос, но я думаю, что это не по теме, потому что речь идет об использовании какого-либо инструмента. Такие вопросы обсуждаются только в том случае, если они охватывают, как инструмент интегрируется в некоторый процесс разработки - в конце концов, этот сайт посвящен программной инженерии. Смотрите наш справочный центр для деталей. Пожалуйста, прочитайте: Куда идет мой инструментальный вопрос? Использование инструментов разработки, таких как NPM, будет посвящено теме переполнения стека.
Амон

Ответы:

9

codependency может быть тем, что вы ищете, или всем, что делает что-то похожее на:

  • объявить необязательные зависимости в package.jsonэтом которые не устанавливаются автоматически npm install, скажем,optionalPeerDependencies
  • пользовательская requireфункция стиля, которая знает о optionalPeerDependenciesправильных вещах и делает их правильно, включая выдачу / предупреждение, когда ничего не найдено, что соответствует требуемому классу модулей (например, ниredis , ни mongo, ни mysql, и т.д. не установлены).
  • задокументировать ожидание того, что потребители этого модуля установят как минимум 1 из дополнительных одноранговых модулей

Один из вариантов будет, если основные функциональные возможности модуля работают без каких-либо необязательных зависимостей (например, шаблон плагина), без ошибок / предупреждений, когда не найдено ничего, что соответствует зависимости от однорангового узла.

Другим вариантом является приведенный выше список с учетом зависимости производства от развития, то есть аналог dependencies и devDependencies.

Возможно в сочетании с требованием по требованию , так что дополнительные модули требуются лениво, например:

exports = {
    Core : require('./core'),
    get redis(){ return require('./redis'); },
    get mongo(){ return require('./mongo'); }
}
toolbear
источник
Я не нуждался в этом некоторое время, но я думаю, что это решает проблему, которую я имел. Благодарность!
Имирик
2
Да, я считал, что это месяцы, вы, наверное, поняли это или пошли дальше. Я нашел твой вопрос во время поиска ответов сам, так что это было в основном для потомков. Не раз я ходил в поисках, только чтобы найти ответ от себя, написанный несколько лет назад. Так что рассмотрите этот просвещенный личный интерес. Кроме того, обновлен ответ, чтобы в общих чертах описать, что codependencyпредоставляет модуль в случае, если модуль испаряется из NPM и потому что ссылки без выдержек имеют плохую форму SO.
toolbear
9

Если вам нужны простые необязательные зависимости, такие как плагины, например, если вы установите foo, вы запустите его красочно, но если он не установлен, у вас нет проблем и вы увидите его серым, тогда вы можете использовать необязательные атрибутыDependecies в package.json :

{
  "name": "watchit",
  "version": "1.2.3",
  "optionalDependencies": {
    "foo": "^2.0.0"
  }
}

И в коде:

try {
  var foo = require('foo')
  var fooVersion = require('foo/package.json').version
} catch (er) {
  foo = null
}
if ( notGoodFooVersion(fooVersion) ) {
  foo = null
}

// .. then later in your program ..

if (foo) {
  foo.doFooThings()
}

Извлечено из документации package.json .

PhoneixS
источник
1

Что я делаю, так это настраиваю скрипт установки в моем package.json внутри scripts, вот так:

"install": "node ./my-tools/my-install.js",

Он запустится сразу после npm installфиниша. Я использую его в основном для автоматического создания.env файла со значениями по умолчанию.

my-install.jsСценарий может выполнять различные команды, создавать файлы, задать для ввода данных пользователя, так что вы могли бы сказать : «Хочет Redis или Монго?»:

const exec = require('child_process').exec;
const readline = require('readline');

// Insert "Ask question script" here
// using readline core module

if ( option == 'mongo' )
  exec('npm install mongoose');

if ( option == 'redis' )
  exec('npm install redis');

Это очень быстрый ответ, проверьте readline для правильного чтения пользовательского ввода и дочернего процесса для запуска команд и обработки вывода и т. Д.

Также обратите внимание, что скрипт установки может быть любым, что вы пожелаете (python, bash и т. Д.)

aesede
источник
2
Запрашиваемая для ввода пользователя испортит автоматические сборки. Повторный npm installзапуск внутри сценария установки также может вызвать непреднамеренное поведение. Я не рекомендую это решение.
Лямбда Фея
1

npm действительно не был разработан для этого, так как одна из самых сложных частей управления зависимостями - обеспечение быстрых, воспроизводимых сборок, которые просты и относительно безопасны. Но я считаю, что есть вариант использования, и, безусловно, был для меня. Поэтому я написал пакет, чтобы сделать именно то, что вы просите.

Мой пакет есть install-subsetи может быть установлен глобально сnpm install -g install-subset

https://www.npmjs.com/package/install-subset

Во-первых, вы создаете белые и черные списки для именованных поднаборов установки в вашем package.json следующим образом:

"subsets": {
    "build": {
        "whitelist": [
            "babel-cli",
            "dotenv"
        ]
    },
    "test": {
        "blacklist": [
            "eslint",
            "lint-rules",
            "prettier"
        ]
    }
}

Затем назовите это, например, install-subset test

Это временно перезапишет ваш package.json, чтобы не устанавливать эти пакеты в черный список, а затем восстановить его, что в зависимости от пакетов может сэкономить много времени и пропускную способность.

Также работает с пряжей, с открытым исходным кодом и вопросы / PR приветствуются.

Во многих случаях я использую это на нашем ci-сервере, чтобы сократить время сборки, а в нашем последнем проекте React Native наша обычная установка для нового разработчика заняла от 72 до примерно 20 секунд.

tabrindle
источник