company_banner

npm link на стероидах

    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. Инструмент новый, так что не стесняйтесь писать о проблемах.

    Mail.ru Group
    1,024.47
    Строим Интернет
    Share post

    Comments 25

      0

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

        +2

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

          +1

          Дополню.


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


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


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

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

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

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

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


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

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


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

                  0
                  Как раз цикл публикации не прост. Просто цикл публикации никак не мешает работать в симлинках.
                  Есть пакеты, которые используют одновременно разные версии одного пакета, все решаемо и все работает. А вот npmy вопрос не взбрыкнет ли где-нибудь на неучтенной конфигурации. Для всех разработчиков не сделаешь универсальный инструмент, я это понял когда стал разбираться с angular/cli. Для быстрого старта очень даже решение, но чуть в сторону начинаются танцы с бубном. Поэтому лучше разобраться с процессом и написать свой велосипед, благо это не так сложно
                    0
                    Просто цикл публикации никак не мешает работать в симлинках.

                    Если только вам надо esnext в es3 или другой сложной генерации с подменой исходников.


                    Для всех разработчиков не сделаешь универсальный инструмент

                    Ну я же сделал :]


                    P.S. Вы можете не верить, но этот инструмент, создан именно по причине его отсутствия. Для простых пойдёт обычный симлинк, npm link для более сложных (если нужны dependencies), Lerna поможет с монорепозиторием, а для всего остального npmy ;]

            +1

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

              0

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

                0

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

                  0

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

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

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

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

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

                            0

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

                              0

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

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

                          Вот и всё, что мне нужно для щастья:


                          yarn add --dev file:path/to/your/custom/package

                            0

                            А в чём счастье? Это даже не link, а просто установка из локальной папки, прикольно, но бесполезно.

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

                      Спасибо, как раз искал такой инструмент, который локально имитирует публикацию ("публикует" в локальную папку, из которой можно затем "установить" собранный пакет).

                      Only users with full accounts can post comments. Log in, please.