npm link + steroids = npmy


Думаю многие из вас уже сталкивались с локальной разработкой npm-пакетов. Обычно никаких трудностей это не вызывает: создаём папку, запускаем npm init, пишем тесты, дальше используем npm link (либо просто симлинк) и «шлифуем» api до полной готовности.


Звучит просто… только если вы не используете Babel, Rollup, Webpack и т.п. Иными словами, всё хорошо, пока проект не нужно собрать перед публикацией, да ещё с модификацией исходного кода. Кроме того, одновременно разрабатываемых пакетов может быть больше чем один, что в разы усложняет «жизнь». Чтобы исправить эту ситуацию, пришлось сделать маленькую утилиту npmy, под катом небольшая статья с описанием тех. процесса работы и пример использования.


Итак, как я уже говорил, основная проблема локальной разработки — это использование scripts/хуков (prepublish, prepublishOnly и т.д.), именно по этой причине npm link не подходит, ведь по сути — это банальный симлинк, да ещё по завершению разработки нужно не забывать про npm unlink.


Поэтому я принялся за свое решение, которое:


  1. Имеет простую настройку.
  2. Эмулирует полный цикл публикации.
  3. Создает симлинк на псевдо-опубликованную версию (далее ПОВ).
  4. Следит за изменениями и обновляет ПОВ.


Настройка проекта


Первой мыслью было добавить правила прямо в package.json, но это неправильно, ведь это именно локальная разработка, поэтому правила было решено размещать в .npmyrc, который без труда можно добавить в .gitignore.


Сам файл — ни что иное, как простой JSON-объект, у которого:


  • key — название зависимости из package.json;
  • value — локальный путь до разрабатываемого пакета (относительный или абсолютный).

Всё, на этом конфигурация закончена.



Запуск


Заходим в папку с .npmyrc и запускаем npmy, который:


  1. Читает .npmyrc.
  2. Фильтруем список зависимостей на два списка для:
    • установки из NPM;
    • локальной установки.
  3. Установка зависимостей из NPM.
  4. Псевдо-публикация пакетов из .npmyrc.
  5. Создание симлинка на ПОВ.
  6. Запуск отслеживания изменений (watch).


Процесс псевдо-публикации


Это самое интересное, ради чего всё и затевалось. Для начала вспомним, как это работает в оригинальном npm.


npm install && npm publish


Как видите, тут нас ждет сюрприз, prepublish и prepare выполняются как на npm publish, так и на npm install (без аргументов). Поэтому если вам нужна сборка проекта перед публикацией, используйте prepublishOnly, но только начиная с 5 версии. Хоть этот хук и добавили в 4, работает он неправильно, и вместо собранного пакета уедет не пойми что, увы.


В моём процессе перед запуском всех хуков есть ещё одно звено, а именно создание копии проекта (вместе с node_modules):


  1. Копия создается через rsync в темповую папку.
  2. Модифицируется package.json, из которого убирается npm test, чтобы не тормозить процесс псевдо-публикации.
  3. Затем для копии запускаются все хуки соответствующие процессу публикации.
  4. И в финальный штрих: удаление всего, что не соответствует секции files.
  5. Profit.

Вуаля, теперь мы имеем версию пакета, которую бы вы получили при установки из npm. Также при каждом изменении исходников, ПОВ будет обновлена автоматом.


Кроме этого, npmy не забывает про секцию bin в package.json и корректно создаёт симлинки на объявленные там скрипты.



Итого


  • npm install -g npmy
  • Создаем .npmyrc в проекте
  • Запускаем npmy

Спасибо за внимание, надеюсь утилита будет полезна не только мне. :]



P.S. Инструмент новый, так что не стесняйтесь писать о проблемах.

Поделиться с друзьями
-->

Комментарии (20)


  1. comerc
    19.07.2017 19:58

    Lerna? Не, не слышал.


    1. RubaXa
      19.07.2017 20:14
      +2

      Слышал, но она про монорепозиторий с кучей пакетов и управление им, это частный случай, а я решал общий. Да и в целом, она про цикл выпуска монорепозитория.


    1. RubaXa
      20.07.2017 00:36
      +1

      Дополню.


      Lerna — это про монорепозиторий, притом ещё с определёнными ограничениями, результат её работы банальный симлинк на папку в проекте, а это значит, что prepublish у таких пакетов использовать нельзя, код должен работать «как есть».


      Кроме этого, lerna не позволяет залинковать произвольный пакет в зависимостях, она работает только со «своими».


      npmy же в свою очередь позволяет подменить любую зависимость и направить её в любое место на диске, но не просто на исходники, а именно на псевдо-опубликованную версию.


  1. Delagen
    19.07.2017 20:14

    Какие только костыли люди не придумают для своего псевдо удобства


    1. RubaXa
      19.07.2017 20:15
      +1

      А в чём костыльность, если не секрет?


      1. Delagen
        20.07.2017 11:19
        -1

        Разрабатываю около 20 пакетов… все стоит тупо и работает
        причем есть несколько корневых. Разрабатывается и на TS и на JS.и бекэнд и фронт
        node_modules просто симлинк на папку с зависимостями
        Все правится на живую и тестируется. Для тестирование сборки есть CI
        Всякими псевдоскриптами потом только усложняется развертывание места разработчика.


        1. RubaXa
          20.07.2017 11:27
          +1

          node_modules просто симлинк на папку с зависимостями

          Я в начале написал, что симлинки не спасают, если у вас есть цикл публикации, например esnext в es5, никакой симлинк не спасёт, потому что ./index.js, нужно перезаписать в тот же ./index.js.


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

          Они усложняют ровно так же, как и создание симлинка, только в отличии от вашего способа, мне не нужно делать это руками, достаточно запустить npmy и он сделает это за меня, да так, что результат будет идентичен работе npm install.


          Кроме этого, как я и написал, если у вас нет сложного цикла публикации, симлинк вполне решение, хотя у него есть ограничения, например с dependencies, которые должны быть установлены не node_modules разрабатываемого пакета, а именно в пакет, который использует эту зависимость. При симлинке такие манипуляции приходиться делать руками.


  1. KIlLXXXVI
    20.07.2017 09:22
    +1

    Какое счастье, что мне достаточно просто симлинка. Статья весёлая и хуки интересные)


    1. RubaXa
      20.07.2017 09:49

      А если учесть все проблемы с «на какой же хук собрать проект», то совсем хорошо :]
      npm-разработчики те ещё молодцы, будем надеяться, что в следующей версии они ничего не сломают ;]


      1. comerc
        20.07.2017 10:29

        Интересно, а вместе с Yarn полетит, или npm-only?


        1. RubaXa
          20.07.2017 11:00

          Ни я, ни в компании, мы не используем Yarn, поэтому, да, npm-only.


          1. Delagen
            20.07.2017 11:22

            Это правильно, прыгание по разным пакетным менеджерам создает больше проблем.
            Вообще Yarn с своим приростом скоростью (которая уже не значительна для NPM 5) был просто хайп.
            Он был еще более менее адекватен для систем сборки, чтобы ускорить установку зависимостей.
            Но для места разработчика и прочих применений профит дутого яйца не стоит. Как будто я сижу каждые пять минут обновляют зависимости. Разработчик это делает ну раз в день, а то и в неделю. И подождать 1-3 минуты как бы не особо проблема. Можно чай попить )


            1. RubaXa
              20.07.2017 11:32

              Больше скажу, мы проблему решили ещё до появления Yarn, прикрутив локальный registry и спец кэширование, которое запускается npm install и достаёт пакеты из локального кеша. Т.е. не нужно изобретать целый пакетный менеджер, чтобы заставить NPM работать быстро, а теперь и подавно ;]


              1. Delagen
                20.07.2017 11:47

                Ну у меня тоже локальный registry есть и кэш на CI не чистится, поэтому все довольно шустро.
                А самый тяжелый сборочный модуль, вообще не ставится а просто линкуется из глобальных.
                Поэтому таких проблем вообще не испытывал. Хотя npm 5 все равно немного поломал… Но в принципе все решаемо и довольно несложно. Сейчас все и на npm 5.3 прекрасно работает, единственное бесит что он с линкованными пакетами пока очень плохо работает https://github.com/npm/npm/issues/16788


                1. RubaXa
                  20.07.2017 11:53
                  +2

                  Вот и я об этом, Yarn в целом не про скорость был, хоть это и была одна из фитч, но главное для них было быстрый shrinkwrap и lock-файл, зачем это обычным разрабам, для меня загадка.


                  1. comerc
                    21.07.2017 12:58

                    Ну очень привык к yarn upgrade-interactive. Есть ли подобное для npm? Нашёл npm-upgrade — почти, но оно пошаговое.


                    1. RubaXa
                      21.07.2017 13:00

                      Эээ, но вот почему-то в моей работе нет такого кейса, как массовое обновление, обычно это очень обдуманный и точечный процесс на конкретную версию, а не просто up до последней.



            1. SaitoNakamura
              21.07.2017 20:34
              +1

              В свежем проекте где на ходу принимаются решения и устанавливаются и удаляются пакеты это очень критично
              Плюс это позволяет приятно экспериментировать, создал папку, быстро поставил что нужно, попробовал, удалил
              npm v5 решил эту проблемы, но последние полгода до его выхода pnpm и yarn решали


        1. SaitoNakamura
          20.07.2017 22:27

          Добавить поддержку будет очень легко в силу того что они практически совместимы