Думаю многие из вас уже сталкивались с локальной разработкой npm-пакетов. Обычно никаких трудностей это не вызывает: создаём папку, запускаем npm init
, пишем тесты, дальше используем npm link (либо просто симлинк) и «шлифуем» api до полной готовности.
Звучит просто… только если вы не используете Babel, Rollup, Webpack и т.п. Иными словами, всё хорошо, пока проект не нужно собрать перед публикацией, да ещё с модификацией исходного кода. Кроме того, одновременно разрабатываемых пакетов может быть больше чем один, что в разы усложняет «жизнь». Чтобы исправить эту ситуацию, пришлось сделать маленькую утилиту npmy, под катом небольшая статья с описанием тех. процесса работы и пример использования.
Итак, как я уже говорил, основная проблема локальной разработки — это использование scripts/хуков (prepublish, prepublishOnly и т.д.), именно по этой причине npm link
не подходит, ведь по сути — это банальный симлинк, да ещё по завершению разработки нужно не забывать про npm unlink
.
Поэтому я принялся за свое решение, которое:
- Имеет простую настройку.
- Эмулирует полный цикл публикации.
- Создает симлинк на псевдо-опубликованную версию (далее ПОВ).
- Следит за изменениями и обновляет ПОВ.
Настройка проекта
Первой мыслью было добавить правила прямо в package.json, но это неправильно, ведь это именно локальная разработка, поэтому правила было решено размещать в .npmyrc
, который без труда можно добавить в .gitignore
.
Сам файл — ни что иное, как простой JSON-объект, у которого:
key
— название зависимости изpackage.json
;value
— локальный путь до разрабатываемого пакета (относительный или абсолютный).
Всё, на этом конфигурация закончена.
Запуск
Заходим в папку с .npmyrc
и запускаем npmy
, который:
- Читает
.npmyrc
. - Фильтруем список зависимостей на два списка для:
- установки из NPM;
- локальной установки.
- Установка зависимостей из NPM.
- Псевдо-публикация пакетов из
.npmyrc
. - Создание симлинка на ПОВ.
- Запуск отслеживания изменений (watch).
Процесс псевдо-публикации
Это самое интересное, ради чего всё и затевалось. Для начала вспомним, как это работает в оригинальном npm.
Как видите, тут нас ждет сюрприз, prepublish
и prepare
выполняются как на npm publish
, так и на npm install
(без аргументов). Поэтому если вам нужна сборка проекта перед публикацией, используйте prepublishOnly
, но только начиная с 5 версии. Хоть этот хук и добавили в 4, работает он неправильно, и вместо собранного пакета уедет не пойми что, увы.
В моём процессе перед запуском всех хуков есть ещё одно звено, а именно создание копии проекта (вместе с node_modules):
- Копия создается через
rsync
в темповую папку. - Модифицируется
package.json
, из которого убираетсяnpm test
, чтобы не тормозить процесс псевдо-публикации. - Затем для копии запускаются все хуки соответствующие процессу публикации.
- И в финальный штрих: удаление всего, что не соответствует секции
files
. - Profit.
Вуаля, теперь мы имеем версию пакета, которую бы вы получили при установки из npm
. Также при каждом изменении исходников, ПОВ будет обновлена автоматом.
Кроме этого, npmy
не забывает про секцию bin в package.json
и корректно создаёт симлинки на объявленные там скрипты.
Итого
npm install -g npmy
- Создаем
.npmyrc
в проекте - Запускаем
npmy
Спасибо за внимание, надеюсь утилита будет полезна не только мне. :]
P.S. Инструмент новый, так что не стесняйтесь писать о проблемах.
Комментарии (20)
Delagen
19.07.2017 20:14Какие только костыли люди не придумают для своего псевдо удобства
RubaXa
19.07.2017 20:15+1А в чём костыльность, если не секрет?
Delagen
20.07.2017 11:19-1Разрабатываю около 20 пакетов… все стоит тупо и работает
причем есть несколько корневых. Разрабатывается и на TS и на JS.и бекэнд и фронт
node_modules просто симлинк на папку с зависимостями
Все правится на живую и тестируется. Для тестирование сборки есть CI
Всякими псевдоскриптами потом только усложняется развертывание места разработчика.RubaXa
20.07.2017 11:27+1node_modules просто симлинк на папку с зависимостями
Я в начале написал, что симлинки не спасают, если у вас есть цикл публикации, например esnext в es5, никакой симлинк не спасёт, потому что
./index.js
, нужно перезаписать в тот же./index.js
.
Всякими псевдоскриптами потом только усложняется развертывание места разработчика.
Они усложняют ровно так же, как и создание симлинка, только в отличии от вашего способа, мне не нужно делать это руками, достаточно запустить
npmy
и он сделает это за меня, да так, что результат будет идентичен работеnpm install
.
Кроме этого, как я и написал, если у вас нет сложного цикла публикации, симлинк вполне решение, хотя у него есть ограничения, например с
dependencies
, которые должны быть установлены неnode_modules
разрабатываемого пакета, а именно в пакет, который использует эту зависимость. При симлинке такие манипуляции приходиться делать руками.
KIlLXXXVI
20.07.2017 09:22+1Какое счастье, что мне достаточно просто симлинка. Статья весёлая и хуки интересные)
RubaXa
20.07.2017 09:49А если учесть все проблемы с «на какой же хук собрать проект», то совсем хорошо :]
npm-разработчики те ещё молодцы, будем надеяться, что в следующей версии они ничего не сломают ;]comerc
20.07.2017 10:29Интересно, а вместе с Yarn полетит, или npm-only?
RubaXa
20.07.2017 11:00Ни я, ни в компании, мы не используем Yarn, поэтому, да, npm-only.
Delagen
20.07.2017 11:22Это правильно, прыгание по разным пакетным менеджерам создает больше проблем.
Вообще Yarn с своим приростом скоростью (которая уже не значительна для NPM 5) был просто хайп.
Он был еще более менее адекватен для систем сборки, чтобы ускорить установку зависимостей.
Но для места разработчика и прочих применений профит дутого яйца не стоит. Как будто я сижу каждые пять минут обновляют зависимости. Разработчик это делает ну раз в день, а то и в неделю. И подождать 1-3 минуты как бы не особо проблема. Можно чай попить )RubaXa
20.07.2017 11:32Больше скажу, мы проблему решили ещё до появления Yarn, прикрутив локальный registry и спец кэширование, которое запускается
npm install
и достаёт пакеты из локального кеша. Т.е. не нужно изобретать целый пакетный менеджер, чтобы заставить NPM работать быстро, а теперь и подавно ;]Delagen
20.07.2017 11:47Ну у меня тоже локальный registry есть и кэш на CI не чистится, поэтому все довольно шустро.
А самый тяжелый сборочный модуль, вообще не ставится а просто линкуется из глобальных.
Поэтому таких проблем вообще не испытывал. Хотя npm 5 все равно немного поломал… Но в принципе все решаемо и довольно несложно. Сейчас все и на npm 5.3 прекрасно работает, единственное бесит что он с линкованными пакетами пока очень плохо работает https://github.com/npm/npm/issues/16788RubaXa
20.07.2017 11:53+2Вот и я об этом, Yarn в целом не про скорость был, хоть это и была одна из фитч, но главное для них было быстрый
shrinkwrap
иlock
-файл, зачем это обычным разрабам, для меня загадка.comerc
21.07.2017 12:58Ну очень привык к yarn upgrade-interactive. Есть ли подобное для npm? Нашёл npm-upgrade — почти, но оно пошаговое.
RubaXa
21.07.2017 13:00Эээ, но вот почему-то в моей работе нет такого кейса, как массовое обновление, обычно это очень обдуманный и точечный процесс на конкретную версию, а не просто up до последней.
SaitoNakamura
21.07.2017 20:34+1В свежем проекте где на ходу принимаются решения и устанавливаются и удаляются пакеты это очень критично
Плюс это позволяет приятно экспериментировать, создал папку, быстро поставил что нужно, попробовал, удалил
npm v5 решил эту проблемы, но последние полгода до его выхода pnpm и yarn решали
SaitoNakamura
20.07.2017 22:27Добавить поддержку будет очень легко в силу того что они практически совместимы
comerc
Lerna? Не, не слышал.
RubaXa
Слышал, но она про монорепозиторий с кучей пакетов и управление им, это частный случай, а я решал общий. Да и в целом, она про цикл выпуска монорепозитория.
RubaXa
Дополню.
Lerna — это про монорепозиторий, притом ещё с определёнными ограничениями, результат её работы банальный симлинк на папку в проекте, а это значит, что prepublish у таких пакетов использовать нельзя, код должен работать «как есть».
Кроме этого, lerna не позволяет залинковать произвольный пакет в зависимостях, она работает только со «своими».
npmy же в свою очередь позволяет подменить любую зависимость и направить её в любое место на диске, но не просто на исходники, а именно на псевдо-опубликованную версию.