Автоматическое создание модуля NPM при установке из Github

Учитывая, что проект lib/ dir не должен быть зарегистрирован в Git, потому что содержащиеся в нем файлы являются производными файлами (из процесса сборки). При установке пакета из проекта github (например, во время разработки) lib/ dir не будет существовать, поэтому, если main поле package package.json указывает (например, на lib/index.js, пакет не может быть скомпилирован при импорте потому что эти файлы не существуют в хранилище и, следовательно, в пакете, установленном в node_modules. Это означает, что пакет должен быть собран (так же, как это было бы до выпуска), только на этот раз локально, чтобы каталог lib (или любые другие файлы, созданные в процессе сборки) были добавлены в каталог модуля.

Предполагая, что в поле scripts файла package.json есть сценарий build, можно ли настроить пакет на автоматический запуск в ситуации, когда он установлен только с github? Если нет, каков наилучший подход к обеспечению его сборки при установке с github?

В настоящее время существуют prepublish, prepublishOnly и prepare ловушек жизненного цикла, но ни одна из них не дает ответа на эту проблему, поскольку они не позволяют разграничить источник установки. Короче говоря, да, они позволяют вам строить на установке, но они не позволяют вам строить только с github. Существует не только причина для принудительной сборки, когда люди устанавливают из npm, но, что более важно, зависимости для разработки не будут установлены (например, babel который имеет решающее значение для сборки).

Я знаю одну стратегию для решения этой проблемы:

  • Форк/филиал репо
  • строить локально
  • удалите lib/ dir из .gitignore и проверьте его.
  • установить модуль с вашего форка/ветки
  • Когда вы будете готовы к PR/rebase, добавьте lib/ dir в .gitignore и удалите dir из git.

Но это далеко от идеала. Я думаю, что это может быть автоматизировано с помощью Githook, хотя. Таким образом, каждое нажатие на освоение проекта также создает и переносит в отдельную ветку.

На NPM Github есть закрытая проблема без разрешения - просто много людей, которые хотят найти решение. Из этого вопроса ясно, что использование prepare не является ответом.

Мой пример использования заключается в том, что я разрабатываю модуль, который используется в ряде других проектов. Я хочу использовать последнюю версию модуля без необходимости выпускать релиз для NPM всякий раз, когда я обновляю кодовую базу - я бы предпочел выдавать меньшее количество релизов, когда я буду готов, но мне все равно нужно использовать любую последнюю версию библиотеки. находится на Github.

Примечание: я также обратился в службу поддержки NPM по этому вопросу, и я добавлю их ответ, если я его получу.

Ответы

Ответ 1

Редактировать: обнаружение установки пакета из git repo

Я не правильно понял вопрос. Ниже приведены вещи, которые я написал, но немного не по теме. Пока, если вы хотите запускать build.js только при установке из репозитория:

Файлы в репо:

 .gitignore
 .npmignore
 ThisIsNpmPackage
 build.js
 package.json

.gitginore:

ThisIsNpmPackage

.npmignore:

!ThisIsNpmPackage

В package.json:

"scripts": {
    "install": "( [ ! -f ./ThisIsNpmPackage ] && [ ! -f ./AlreadyInstalled ] && echo \"\" > ./AlreadyInstalled && npm install . && node ./build.js ) || echo \"SKIP: NON GIT SOURCE\""
}

Идея состоит в том, чтобы сделать файл ThisIsNpmPackage доступным в репозитории, но не в пакете npm.

Установите hook, это всего лишь кусок скрипта, чтобы проверить, существует ли ThisIsNpmPackage. Если да, тогда мы выполняем npm install . (это гарантирует, что у нас есть devDependencies. Файл AlreadyInstalled генерируется, чтобы предотвратить бесконечный цикл (npm install будет рекурсивно вызывать установочный хук)

При публикации я делаю git push и npm publish
Обратите внимание, что публикация npm может быть автоматизирована с помощью инструментов CI - githooks

Этот небольшой взлом файла ThisIsNpmPackage делает доступным обнаружение источника.

Результаты вызова npm install dumb-package:

"SKIP: NON-GIT SOURCE"

И выполнение npm install https://github.com/styczynski/dumb-package

Файлы будут построены

Проблемы

Вот основные проблемы, с которыми мы сталкиваемся:

  • Нужно делать npm publish ... каждый раз

    Иногда бывает слишком сложно исправить небольшую ошибку, затем нажать на репо и забыть опубликовать на npm. Когда я работал с проектом на основе микросервисов, в котором около 5 отдельных подпроектов были разделены на модули, проблема, в которой я обнаружил проблему, устранила ее и забыла публиковать в каждом месте, где должен был, действительно раздражала.

  • Не хочу вставлять lib в репозиторий, потому что он взят из источников

  • Перебазировка и слияние еще более раздражают.

  • Не связывайтесь с .gitgnore

    Черт, я знаю эту проблему, когда у вас есть проблемные файлы, которые вы должны включить в репозиторий, но никогда не изменяете их или иногда удаляете? Это просто тошнит.

Изменение: крючки npm

Как упомянул @Roy Tinker, существует возможность, что пакет может выполнить команду после установки.
Это может быть достигнуто через npm-хуки.

"install": "npm run build"

И мы выполняем:

npm install https://github.com/<user>/<package>

Изменить:
ОП вопрос из комментариев:

Но это запустит установку для всех, кто скачивает модуль с npm, верно? Это чрезвычайно проблематично, учитывая, что dev-зависимости не будут установлены для тех, кто скачивает модуль с npm. Библиотеки, используемые для сборки приложения - babel и т.д. Не будут установлены.

Примечание. Но , если вам нужна конкретная версия пакета (production/dev) с зависимостями dev или без, вы можете установить ее с помощью:

npm install --only=dev

Аргумент --only = {prod [uction] | dev [elopment]} вызовет установку только devDependencies или только non-devDependencies независимо от NODE_ENV.

На мой взгляд, лучшим решением является использование:

npm install <git remote url>

А затем внутри package.json укажите:

"scripts": {
    "prepare": "npm run build"
}

Если устанавливаемый пакет содержит сценарий подготовки, будут установлены его зависимости и devDependencies, а сценарий подготовки будет запущен до упаковки и установки пакета.

Пример:

npm install git+https://[email protected]/npm/npm.git

Прочитайте документы npm там: npm install

Изменение: прокси-модуль (продвинутая техника)

Это плохая практика, но полезно знать.

Иногда (как в случае с платформой Electron вам необходимо установить другие внешние пакеты или ресурсы/модули в зависимости от различных условий).

В этих случаях используется идея прокси:

  • Вы делаете модуль, который ведет себя как установщик и устанавливает все, что вам нужно

В вашем случае подготовить сценарий будет достаточно, но я оставляю эту опцию, потому что это может быть иногда полезно.

Идея состоит в том, что вы пишете модуль и пишете для него установочный kook:

"scripts": {
    "install": "<do the install>"
}

В этом сценарии вы можете разместить там:

npm install . && npm run build

Которые в любом случае устанавливают все devDependencies (как и в случае с подготовленным кейсом), но это немного взлом.

Если вы хотите сделать настоящий взлом там:

 "scripts": {
    "install": "curl -L -J -O \"<some_url>\""
 }

который вручную загружает файлы с помощью команды -nix curl

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

Как и в случае с Electron, где вы скомпилировали двоичные файлы (каждый для отдельной платформы)

Итак, вы хотите, чтобы люди сделали install package не install package-linux или package-window и т.д.

Таким образом, вы предоставляете собственный скрипт install в package.json

{
  ...
  "scripts": {
     "install": "node ./install_platform_dep.js"
  }
}

Затем при установке module будет выполнен скрипт install_platform_dep.js. Внутри install_platform_dep.js вы размещаете:

// For Windows...
if(process.platform === 'win32') {
    // Trigger Windows module installation
    exec('npm install fancy-module-windows', (err, stdout, stderr) => {
         // Some error handling...
    }
} else if ... // Process other OS'es

И этот чисто ручным способом устанавливает все.

Примечание: Еще раз этот подход можно использовать с зависящими от платформы модулями, и если вы его используете, он, вероятно, создает проблемы с вашим кодом.

Построить на CI

Что мне приходит в голову, так это решение, которое я действительно использовал в течение долгого времени (автоматическое создание с помощью служб CI).

Основная цель большинства служб CI - это тестирование/сборка/публикация кода при отправке в ветку или выполнении других действий с репо.

Идея состоит в том, что вы предоставляете файл настроек (например, travis.yml или .gitlab-ci.yml), а все остальное заботятся инструменты.

Если вы действительно не хотите включать библиотеку в проект, просто доверьтесь CI делать все:

  • Githook запустит сборку на коммите (на ветке или любой другой - это всего лишь вопрос настроек)
  • CI создаст ваши файлы, затем передаст их на фазу тестирования и опубликует

Сейчас я работаю над Gitlab над своим собственным проектом и создаю (как часть хобби) некоторую веб-страницу. Конфигурация Gitlab, которая создает проект, выглядит следующим образом:

image: tetraweb/php

cache:
  untracked: true
  paths:
    - public_html/
    - node_modules/

before_script:
  - apt-get update

stages:
  - build
  - test
  - deploy

build_product:
  stage: build
  script:
    - npm run test

build_product:
  stage: build
  script:
    - npm run build

deploy_product:
  stage: deploy
  script:
    - npm run deploy

При слиянии с основной веткой происходят следующие события:

  • КИ работает на этапе build
  • Если сборка прошла успешно, запускается этап test
  • Если фаза test в порядке, то, наконец, активируется стадия deploy

Сценарий - это список команд Unix, которые нужно выполнить.

Вы можете указать любой образ Docker в конфигурации, так что фактически используйте любую версию Unix, которую вы хотите, с некоторыми (или нет) предустановленными инструментами.

Существует пакет deploy-to-git, который развертывает артефакты в нужной ветке репо.

Или здесь (для Travis CI) фрагмент конфигурации, который публикует артефакты в репозитории:

Трэвис публикация к мерзавцу

(Я использовал это сам)

Тогда, конечно, вы можете позволить CI работать:

npm publish .

Поскольку CI выполняет команды Unix, он может (по крайней мере, несколько поставщиков CI):

  • Опубликовать теги (возможно, освободить тег?)
  • Сценарий запуска для обновления версии проекта во всех файлах README и везде
  • Отправьте вам уведомление, если все этапы выполнены успешно

Итак, что я делаю:
Я фиксирую, нажимаю и позволяю инструментам делать все, что я хочу.
Тем временем я делаю другие изменения и через одну-десять минут получаю отчет об обновлениях по почте.

Там много провайдеров CI:

Здесь я прилагаю другой пример моего другого проекта (.travis.yml):

language: generic
install:
    - npm install
script:
    - chmod u+x ./utest.sh 
    - chmod u+x ./self_test/autodetection_cli/someprogram.sh
    - cd self_test && bash ../utest.sh --ttools stime --tno-spinner

Если вы настроили CI для отправки и публикации своего пакета, вы всегда можете использовать последнюю передовую версию своего кода, не беспокоясь о да, мне нужно запустить и эту команду сейчас... проблема.

Я рекомендую вам выбрать одного из провайдеров CI.
Лучшие из них предлагают вам сотни способностей!

Когда вы привыкнете автоматически выполнять этапы публикации, тестирования и сборки, вы увидите, как это помогает наслаждаться жизнью!
Затем, чтобы запустить другой проект с автоматическими скриптами, просто скопируйте конфиги!

Резюме

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

Каждый из описанных методов имеет свои недостатки и может использоваться в зависимости от того, чего вы хотите достичь.
Я просто хочу предоставить некоторые альтернативы, надеюсь, что некоторые из них будут соответствовать вашей проблеме!

Ответ 2

Предполагая, что в поле сценариев package.json есть build script, можно ли настроить пакет для автоматического запуска в этой ситуации?

Да. Вам нужно сделать 2 вещи:

  • Убедитесь, что ваша система использует npm или yarn для установки пакета из GitHub. Если этот пакет является зависимым от другого пакета, вы можете использовать URL-адрес GitHub вместо номера версии в package.json. В противном случае будет работать следующая команда:

    npm install https://github.com/YourUser/your-package
    

    Вы можете добавить /tags/v1.0.0 или что угодно до конца URL-адреса, если после определенного тега или ветки.

  • Добавьте в модуль scripts следующее в package.json:

    "install": "npm run build"
    

install - это крючок, который менеджер пакетов выполняет после установки модуля. (preinstall и postinstall также - см. документацию).

Документация: https://docs.npmjs.com/misc/scripts

Ответ 3

prepare - правильный путь

Если у вас есть хранилище с исходными файлами, но для его использования необходим шаг "сборки", prepare делает именно то, что вам нужно во всех случаях (начиная с npm 4).

prepare: запускать оба ПО ДО того, как пакет будет упакован и опубликован, на локальном npm install без каких-либо аргументов и при установке git-зависимостей.

Вы даже можете поместить свои зависимости сборки в devDependencies, и они будут установлены до выполнения prepare.

Вот пример моего пакета, который использует этот метод.


Проблемы с .gitignore

Есть одна проблема с этой опцией, которая получает много людей. При подготовке зависимости Npm и Yarn будут только сохранять файлы, перечисленные в разделе files package.json.

Кто-то может увидеть, что files по умолчанию включает все файлы, включенные, и подумать, что все готово. Что легко упустить, так это то, что .npmignore в основном переопределяет директиву files и, если .npmignore не существует, вместо него используется .gitignore.

Итак, если ваши встроенные файлы перечислены в .gitignore как здравомыслящий человек, не перечисляйте ваши встроенные файлы в files и не используйте файл .npmignore, prepare будет выглядеть испорченным.

Если вы исправите files, чтобы он включал только встроенные файлы, или добавили пустой .npmignore, все готово.

Ответ 4

Отредактированный 2

Это отличный вопрос. Жаль, что нет признанного надежного решения, но, похоже, работает следующее.

Создайте .buildme маркера .buildme и .buildme в git.

В package.json:

  "files": ["lib"],
  "scripts": {
    "build": "echo DO WHAT YOU NEED TO BUILD",
    "prepack": "[ ! -f .buildme ] || npm run build",
    "preinstall": "[ ! -f .buildme ] || npm run build"
  },

Вот что стоит отметить.

  1. Специальный .buildme маркера .buildme должен быть исключен из пакета npm либо с помощью .npmignore "files", либо с помощью .npmignore.

  2. В prepack крюк работает, когда вы публикуете (prepublishOnly может также работать, но это хорошо, что с prepack, npm pack будет производить правильный тарболл).

  3. При установке из npm, preinstall запускается, но ничего не делает, потому что отсутствует .buildme (благодаря предложению [ ! -f.buildme ]).

  4. При установке из github .buildme существует. На npm6, prepack крюк запускает сборку (и производит упаковку без .buildme), и preinstall ничего не делает. На пряжи 1.12, preinstall делает сборку.

  5. Если вы установите обновленную версию из github, preinstall снова запустится и соберется снова.

ПРИМЕЧАНИЕ. При установке из github это зависит от того, кто установил, достаточно devDependencies уже установленных devDependencies вашего пакета для работы сборки. (Это решение не пытается автоматически установить devDependencies.)

Это. Кажется, для работы с вариациями комбинаций npm 6 и пряжи 1.12.