Привет! Меня зовут Света, я фронтенд-разработчик отдела спецпроектов в KTS.
Наш отдел разрабатывает и запускает около 100 проектов в год. При такой загрузке мы постоянно ищем новые способы ускорить и автоматизировать работу.
У нас много библиотек: с общими утилитами и хуками, стилями, классами базовых сторов, с утилитами для ВК- и ОК-приложений. Во всех этих библиотеках нужно постоянно дополнять и заменять какие-то элементы, а после этого тестировать библиотеки на работоспособность.
Подключение библиотеки к проекту не такой простой процесс — особенно для новичков. В первый раз нам потребовались пять статей и десять часов времени на ошибки, проверку и сбор наработок для команды. После этого мы решили написать статью-подсказку, чтобы сделать жизнь других разработчиков проще, а работу — быстрее.
Оглавление
В чём сложность работы с библиотеками и чем удобен наш способ подключения
В обычной жизни разработчик получает задачи по разработке библиотек реже, чем задачи по проекту. Если человек занимается библиотеками впервые, ему помогут две вещи: знания и помощь более опытных коллег и понятная инструкция.
Тестировать библиотеку нужно после каждого изменения: фикса багов, добавления новой логики или изменения старой, замены версии пакета одной из зависимостей. Для теста мы используем ручное тестирование и автотесты.
Мы постепенно покрываем автотестами все свои внутренние библиотеки, но на их написание и проверку нужно потратить много времени. А npm/yarn link позволяет видеть эффект от изменений в коде библиотеки сразу же в проекте, к которому она подключена. Поэтому этот способ облегчает тестирование в реальном времени, но и не исключает важность автотестов.
Подключение и тестирование библиотеки по шагам
Вам потребуется сама библиотека и подопытный проект, на котором она будет тестироваться. Оба проекта в качестве пакетного менеджера должны использовать yarn одной версии. Ниже в статье будет также рассмотрен более частный случай, когда в зависимостях библиотеки и проекта есть React. Если у вас нет библиотеки для теста, можно взять react-testing-library. Тестовый проект можно создать с помощью одного из шаблонов Vite. Установите библиотеку в проект.
Для подключения библиотеки к проекту в большинстве случаев достаточно команды yarn link. Но бывает, что функционала yarn для линковки недостаточно, и тогда на помощь приходит npm link.
В этом примере использовалось следующее окружение:
npm 10.2.3, yarn 1.22.21, node 20.10.0, терминал bash внутри VS Code 1.84.2, macOS Sonoma 14.1.1
Для некоторых команд могут потребоваться права администратора. В этих случаях на MacOS и Linux вы получите ошибку вида “Permission denied”, а на Windows такую: “Access is denied. You do not have sufficient privileges”. Для решения припишите sudo
перед командой на macOS и Linux или откройте терминал с правами администратора на Windows.
Давайте представим, что тестируемая библиотека — @ktsstudio/test-library, это имя можно найти в поле "name" в package.json в проекте с библиотекой. Она склонирована в папку test-library, а тестовый проект лежит, соответственно, в папке test-project. Предполагается, что в тестовом проекте эта библиотека уже установлена.
Структура папок проектов примерно следующая:
Смотреть
Перейдите на ветку библиотеки с изменениями, которые нужно проверить. После этого идите по шагам ниже.
1 — Установка зависимостей и сборка библиотеки
Для этого есть два способа.
Короткий способ — внутри проекта с библиотекой выполните команду:
yarn install && yarn build
В начале раздела мы указали окружение, которое использовалось при проверке:
npm 10.2.3, yarn 1.22.21, node 20.10.0, терминал bash внутри VS Code 1.84.2, macOS Sonoma 14.1.1.
В этом окружении работают оба способа. Если после выполнения всех последующих пунктов первый работает некорректно, сначала попробуйте удалить изменения в yarn.lock и переустановите зависимости в используемых проектах. Для этого можно использовать следующие команды, а затем снова выполнить шаги 1-4 текущего раздела:
root-folder $ cd test-project
test-project $ git restore yarn.lock && rm -rf node_modules/ && yarn install
test-project $ cd ../test-library
test-library $ git restore yarn.lock && rm -rf node_modules/ && yarn install
Если этот способ всё равно не работает или работает некорректно, воспользуйтесь следующим вариантом.
Длинный способ:
внутри проекта с библиотекой выполните команду:
yarn install && yarn build
-
Скопируйте сформировавшуюся папку dist и package.json в любой другой каталог вне каталога с тестовым проектом. Это понадобится по двум причинам:
во избежание возможных проблем с созданием ссылок на библиотеки
чтобы файл и папка соответствовали структуре библиотеки в node_modules тестируемого проекта
Смотреть
-
Когда вы скопировали папку dist и package.json в другой каталог, нужно выполнить команду
yarn install
из этого каталога, чтобы установить в нём зависимости. Например, в папке long-way вы создали папку test-library-like, чтобы протестировать библиотеку @ktsstudio/test-library.Так может выглядеть структура каталога после выполнения шагов выше:
Смотреть
После этого все команды, относящиеся к проекту с разрабатываемой библиотекой, нужно будет выполнять из этого же каталога. В нашем примере — из test-library-like.
Теперь нужно подключить библиотеку к тестовому проекту, а после завершения работ — отключить.
2 — Создание ссылки на экземпляры пакетов React
Если библиотека @ktsstudio/test-library под капотом использует библиотеку React, нужно учесть один нюанс.
При обычной установке библиотеки в проект с помощью yarn add
проект и библиотека без проблем могут использовать одну и ту же библиотеку под капотом. При такой установке зависимости проекта разрешаются корректно — пакетный менеджер анализирует зависимости и подбирает наиболее актуальные версии библиотек.
Но при использовании yarn link
в проекте создается символическая ссылка, указывающая на локальное местоположение библиотеки в файловой системе. В этом случае зависимости библиотеки могут быть связаны некорректно, и дублирование пакетов React и его типов при запуске проекта вызовет ошибки, причина которых может быть неочевидна. Поэтому собранная библиотека должна ссылаться на один экземпляр React, который используется в тестовом проекте.
Для этого выполните команду npm link для react (название пакета в node_modules) и для @types/react, если они используются в библиотеке.
❗Перед выполнением следующих команд убедитесь, что в тестовом проекте и в библиотеке нет незакоммиченных изменений в yarn.lock, так как при использовании npm link
этот файл модифицируется.
Внутри проекта с разрабатываемой библиотекой выполните команды:
npm link <путь до тестового проекта>/node_modules/react
npm link <путь до тестового проекта>/node_modules/@types/react
Например, в нашем случае команды для короткого пути будут выглядеть так:
npm link ../test-project/node_modules/react
npm link ../test-project/node_modules/@types/react
Это создаст символические ссылки в глобальном окружении npm и свяжет библиотеку с пакетом в node_modules тестового проекта. Если требуется протестировать несколько библиотек, повторите этот шаг для них всех.
Чтобы убедиться, что ссылки на экземпляры пакетов созданы, пропишите команду:
npm list -g --depth=0
Найдите в списке экземпляр react и экземпляр его типов @types/react, где путь указывает на пакеты в составе вашего тестового проекта. На примере нашего тестового проекта это может выглядеть так:
$ npm list -g --depth=0
/Users/user/.npm-global/lib
├── @types/react@18.2.4 -> ./../../projects/test-project/node_modules/@types/react
└── react@18.2.0 -> ./../../projects/test-project/node_modules/react
В файловой системе или в интерфейсе IDE связанные экземпляры пакетов в папке node_modules тестируемой библиотеки будут иметь иконку ярлыка. Если на шаге установки зависимостей и сборки вы выбрали длинный способ, вот как может выглядеть папка node_modules:
Примечания:
❗В некоторых случаях использование
npm link
не нужно.
Это зависит от того, какие именно функции библиотеки используются в проекте. Например, если тестируется библиотека, которая использует react, но в тестовом проекте используются только те методы из библиотеки, в которых ничего не импортируется из react —npm link
не обязателен.❗Версия node должна быть одинаковая в библиотеке и в тестовом проекте, иначе тестовый проект не увидит библиотеку по
npm link
.
Проверить версию можно в package.json в поле engines.node. Если такого поля нет, в проекте будет использоваться глобально установленная версия node на вашем компьютере. Узнать глобальную версию можно с помощью командыnode -v
. Если глобально установленная версия node отличается от той, что указана в package.json, ее можно легко изменить с помощью менеджера версий, например NVM. Переключиться на другую версию node, которая указана в IDE или в файле .nvmrc в проекте, можно с помощью командыnvm use
(предварительно потребуется установить nvm). Эта команда устанавливает нужную версию только для текущего терминала.
3 — Создание глобальной ссылки на библиотеку
Внутри каталога с библиотекой выполните команду yarn link
. Так вы создадите глобальную ссылку, которую можно будет использовать в тестовом проекте.
Убедиться, что ссылка на библиотеку создана, можно через команды:
Для macOS —
ls ~/.config/yarn/link/<имя библиотеки>
Для Windows —
ls ~/AppData/Local/Yarn/Data/link/<имя библиотеки>
В отобразившемся каталоге должны быть такие же файлы, которые вы подготовили в каталоге с разрабатываемой библиотекой. Например, если для нашей библиотеки на шаге установки зависимостей и сборки использовать первый способ сборки, файлы могут быть следующими:
$ ls ~/.config/yarn/link/@ktsstudio/test-library
dist node_modules package.json src tsconfig.json yarn.lock
Точное название библиотеки можно найти — или задать для новосозданной библиотеки — в package.json в поле "name".
4 — Подключение тестируемой библиотеки к проекту
Для этого внутри тестового проекта выполните команду: yarn link "@ktsstudio/test-library"
. Так вы заставите yarn смотреть именно в разрабатываемую библиотеку с нужными изменениями.
❗Примечание: при внесении новых изменений в код библиотеки потребуется ее пересобрать — это снова шаг установки зависимостей и сборки библиотеки.
Если после этого IDE/линтер отказывается видеть ее в тестовом проекте, повторить текущий шаг.
5 — Тестирование
Подключение библиотеки к проекту — первый шаг тестирования. Он считается пройденным, если библиотека подключилась и ее изменения применились к проекту без ошибок. Например, если в библиотеке были изменены стили кнопки, то в проекте, в котором она используется, эти стили должны отображаться измененными.
В этой статье мы рассматриваем только ручное тестирование, поэтому остальные этапы тестирования зависят от библиотеки и ваших запросов.
Ошибки
В этом разделе мы разберём некоторые неочевидные ошибки, которые могут выпадать в процессе подключения библиотеки.
-
Can't resolve 'react' / Cannot read properties of null (reading 'useCallback') и другие похожие. Для решения в терминале библиотеки выполните:
npm link <путь до тестового проекта>/node_modules/react
Подробнее об этой ошибке можно узнать в документации React.
Смотреть ошибку
'ErrorBoundary' cannot be used as a JSX component и другие похожие. Подобная ошибка возникает из-за несоответствия версий пакета @types/react в тестовом проекте и в библиотеке. Для решения в терминале библиотеки выполните:
npm link <путь до тестового проекта>/node_modules/@types/react
-
It looks like there are several instances of "styled-components". Такого вида предупреждение может возникать в консоли при тестировании библиотеки, которая под капотом использует styled-components. Для решения попробуйте:
Внутри проекта с библиотекой выполните команду npm link <путь до тестового проекта>/node_modules/styled-components/
Перезапустите тестовый проект. Возможно, переустановите зависимости
-
При завершении тестирования не забудьте отвязать ссылку:
npm uninstall -g styled-components
Подробнее об ошибке в документации Styled Components.
-
В качестве общего решения, если что-то не работает, в тестовом проекте и библиотеке попробуйте эти шаги:
Удалите изменения в yarn.lock:
git restore yarn.lock
Переустановите зависимости:
rm -rf node_modules && yarn install
Как отвязать ссылку на разрабатываемую библиотеку
Вернемся к примеру с разрабатываемой библиотекой @ktsstudio/test-library. После окончания тестирования необходимо удалить созданные ссылки на библиотеки, чтобы при работе над другим проектом эти ссылки не привели к путанице и потенциальным конфликтам с зависимостями.
Для очищения ссылок нужно выполнить следующие шаги:
Если вы создавали ссылки на экземпляры пакетов React — внутри каталога с собранной библиотекой или внутри тестового проекта выполните команду
npm uninstall -g react @types/react
. Так вы отвяжете React и его типы от собранной библиотеки. Если вы тестируете несколько библиотек, достаточно прописать это один раз.Если внутри проекта с библиотекой вы вызывали
npm link
, удалите оттуда изменения в yarn.lock.Внутри тестового проекта выполните команду
yarn unlink "@ktsstudio/test-library"
❗Примечание: это нужно на всякий случай — чтобы убрать ссылку на ранее собранную библиотеку.-
Внутри каталога с библиотекой выполните
yarn unlink
Так вы удалите глобальную ссылку на пакет с разрабатываемой библиотекой. Убедиться, что ссылка удалена, можно, выполнив:Для macOS —
ls ~/.config/yarn/link
Для Windows —
ls ~/AppData/Local/Yarn/Data/link
Посмотрите содержимое корневого каталога по соответствующему пути. В каталоге может присутствовать папка "@ktsstudio" (или другой префикс в зависимости от вашей тестируемой библиотеки), но папки с конкретной разрабатываемой/тестируемой библиотекой ("test-library" в нашем случае) быть не должно.
Внутри тестового проекта выполните
yarn install --force
, чтобы восстановить зависимости.
Заключение
Мы рассмотрели простой и эффективный способ тестирования библиотек в ваших проектах. Надеюсь, наше решение поможет улучшить ваш опыт разработки библиотек и позволит легче ориентироваться в сложностях зависимостей.
Сталкивались ли вы с какими-нибудь проблемами при использовании npm/yarn link? Поделитесь в комментариях своим опытом и идеями.
Другие статьи про React:
• Собираем свою библиотеку для SSR на React
• Создаем текстовый редактор на React.js
• Игра с голосовым управлением на React и Phaser
• Что нового в react-router v6
• React Drag & Drop: «Игра в бутылки»
Другие статьи про JavaScript:
• Как сверстать письмо, чтобы оно дошло до получателя таким, как задумано
• Роадмэп по современному фронтенду от KTS / Хабр (habr.com)
• Кастомизируем VS Code для веб-разработки / Хабр (habr.com)
• Чек-лист фронтендера при разработке рекламного спецпроекта / Хабр (habr.com)
• Как yarn v3 и философия Zero Installs помогли нам сократить длительность ci/cd пайплайна в 3 раза / Хабр (habr.com)
Комментарии (12)
Psychosynthesis
17.06.2024 15:11Эточё, гайд по использованию символических ссылок?
А зачем тут yarn?
kurakina Автор
17.06.2024 15:11+1yarn, а не дефолтный симлинк, как минимум потому, что это кроссплатформенно и более удобно, так как создается глобальная ссылка, которую можно подключить в любом другом проекте
stayacid
17.06.2024 15:11Не совсем понял, для чего создавать и удалять глобальную ссылку на библиотеку, если можно просто указать путь до папки с библиотекой относительно папки текущего проекта.
kurakina Автор
17.06.2024 15:11+1Если имеется в виду положить папку с библиотекой рядом с проектом и обращаться к ней без симлинка, то будет долго и неудобно во всех файлах проекта в импортах менять пути с обращения к установленной библиотеке на пути к папке с измененной библиотекой (условно,
import smth from "@lib"
заменять наimport smth from "../../../@lib"
). Кажется, что придется, например, вносить эту папку с либой в исключения для линтеров и тайпскриптаstayacid
17.06.2024 15:11Не, я про выполнение пункта 3 и линковку библиотеки через yarn link "@ktsstudio/test-library". Можно сделать "yarn add @ktsstudio/test-library@link:путь_до_папки_с_test_library_относительно_текущей_папки" и оно прекрасно будет работать, даже hot reload на изменения в test_library будет реагировать. Потом отменяете изменения в package.json и yarn.lock, указываете нужную версию библиотеки test_library, запускаете yarn install (или просто yarn), получаете ошибки из-за линковки, еще раз запускаете yarn install и библиотека нормально встает из пакета
JSmitty
Используйте npm link, и бесплатно получите тонны секса с неправильными версиями зависимостей. Особенно восхитительно, когда при разработке фичи не хватает компонента в библиотеке UI кита, и в библиотеку бизнес-логики требуется докинуть новый серверный апи. Что может пойти не так? Почему эти ПМы требуют еще переключиться срочно на крит с продакшена?
Охх, как вспомню - так вздрогну. Кмк единственный маршрут, которым в 2024 идут практически все - использовать монорепо. Более-менее безболезненно, и отлично решает проблемы синхронизации версий зависимостей. По решению "кто куда ходит, кто нет" - отлично работает CODEOWNERS.
kurakina Автор
Если вы имеете в виду хранить библиотеки с проектом в составе монорепы, то, например, в нашем случае, когда проекты небольшие и за год их делается по несколько десятков, не очень удобно собирать монорепу для каждого из них, проще всё же подключать библиотеки. Плюс удобнее вносить изменения сразу в несколько разных проектов, просто подтянув новую версию либы. Для одного большого проекта с разными либами, да, монорепа будет удобнее
JSmitty
тогда я не очень понимаю ваш кейс, зачем бы линковать либы? Можно же сделать инстанс нексуса, и свои кастомные библиотеки паблишить в него, и зависимости тянуть оттуда же
kurakina Автор
В проектах либы подтягиваются из нексуса, но если стоит задача изменить код самой библиотеки, то линкуем к какому-нибудь проекту, чтобы можно было сразу проверить изменения в нем без необходимости лишних публикаций