Трудно решить, использовать ли поле package.json # files или файлы .npmignore. Может есть альтернатива.
ПРИМЕЧАНИЕ. Этот пост содержит информацию, которая не является на 100% точной, как мне указал добрый читатель. Я опубликовал новый рассказ об исправлении моей ошибки. Вы можете прочитать это здесь.
on Очень важно контролировать, что публикуется внутри пакета. Вы же не хотите публиковать временные файлы и заставлять ваш пакет весить 300 тонн гигабайт или, что еще хуже, помещать туда личные файлы.
Был там, сделал это.
С npm всегда неплохо запустить команду npm pack, чтобы точно увидеть, что находится внутри вашего пакета:
npm pack --dry-run
Новые версии npm также поддерживают --dry-run в команде npm publish. Кроме того, эти более новые версии достаточно любезны, чтобы выводить содержимое пакета во время публикации. Запомните мои слова: вы не хотите обнаруживать, что ваш пакет неправильно настроен во время публикации. Вы должны взять под свой контроль содержимое пакета с самого начала.
package.json # files field и файлы .npmignore
Итак, как npm знает, что упаковать? Согласно документам здесь:
- Вы можете использовать поле
filesдля определения шаблонов включаемых файлов. - Вы можете пропустить
files, чтобы включить все, и использовать.npmignoreдля определения шаблонов файлов, которые не следует включать. Вы можете поместить.npmignoreв корневую папку или в любой подкаталог. - Если
.npmignoreнет, npm будет искать.gitignoreфайл. - Одни файлы всегда включаются (
package.json,…), а другие всегда игнорируются (node_modules,…) независимо от того, что вы говорите сfilesи.npmignore.
В документации также говорится о том, что вызывает недоумение:
Файлы, включенные в поле «package.json # files», нельзя исключить через .npmignore или .gitignore.
Постичь эти правила непросто, а критические случаи плохо документированы. Лично мне такой подход не нравится. Я не могу открыть package.json и сразу увидеть, что будет включено. Если я хочу быть точным, я должен отредактировать свои files или разбросать несколько .npmignore файлов. Отсутствие возможности исключить то, что было добавлено через files, просто раздражает.
Взгляните на следующий пример: библиотека React с размещенными файлами.
. ├── component │ ├── component.js │ └── component.test.js └── package.json
Я хочу опубликовать component, но исключить тесты, мои варианты:
- Напишите исчерпывающее
filesполе, в котором перечислены все файлы, которые я хочу добавить (в данном случае толькоcomponent/component.js). - Напишите
.npmignore, игнорирующее**/*.test.js.
Обычно кто угодно выбирает второе, но первое - это решение, которое дает мне гарантию, что я просто упаковываю то, что хочу.
Если бы можно было комбинировать files и .npmignore, было бы лучше, но реальность сурова. Итак, у меня есть два предложения, как это исправить.
Предложение 1: поддержка включает и исключает через поле файлов
Поле files может поддерживать как включения, так и исключения с четкой семантикой: определите, что включено, если вы хотите сделать исключение, используйте исключения.
"files": {
"include": ["component"],
"exclude": ["**/*.sample.js"]
}
Это может нарушить работу Интернета, но я думаю, мы можем использовать альтернативное имя свойства на этапе миграции или другой флаг, чтобы указать, что мы используем более новую модель.
Предложение 2: поддержка файлов package.js
Вы когда-нибудь видели спецификацию драгоценного камня рубиновый камень? Если нет, вот один (для краткости я опустил некоторые части):
Обратите внимание на строки с 10 по 12. Эта спецификация gem определяет файлы, которые должны быть включены, с помощью исполняемой инструкции: получить все исходные файлы, контролируемые git, и исключить все виды тестов. Спецификации Gem - это просто рубиновый код, поэтому код расширит этот код до исчерпывающего списка файлов. Это действительно гибко и позволяет нам точно определить включаемый файл. Красивый.
Итак, почему у нас не может быть package.js вместо утомительного package.json? Большинство инструментов JavaScript перемещается в файлы конфигурации JavaScript вместо файлов JSON. Файлы JavaScript можно компоновать, создавать линки и тестировать, и это очень полезно.
Я понимаю, что npm использует JSON как способ предоставления метаданных из пакета без необходимости запускать сам пакет. Я понимаю логику этого рассуждения, но можно было бы использовать JavaScript в нашем коде и упаковать сгенерированную информацию о пакете в формате JSON во время публикации, имея лучшее из обоих миров.
Я не думаю, что это произойдет в ближайшее время 😔.
Что мы можем сделать сегодня?
Используйте обходной путь: подделайте поддержку включения / исключения в файлах с помощью специального инструмента.
Мы делаем это в наших проектах. Мы пишем пользовательское свойство filesGlob в package.json, используя синтаксис, поддерживаемый библиотекой fast-glob:
"filesGlob": {
"include": ["component/*"],
"exclude": ["**/*.test.js"]
}
А затем expand-files скрипт преобразует наши выражения в исчерпывающий files список с помощью библиотеки. Мы можем увидеть расширенные поля перед публикацией, если мы запустим npm pack:
expand-files npm pack --dry-run
Сценарий изменяет package.json и выполняет предоставленную команду. После этого восстанавливается исходный файл. Мы используем другое имя свойства, чтобы избежать проблем с другими инструментами, которые могут ожидать свойство files, соответствующее спецификации. Это не идеально, но работает.
Вот полный сценарий:
Подводя итоги
Я не думаю, что модель npm в корне ошибочна. Это работает в подавляющем большинстве случаев, и когда мы опубликовали пакет с большим или меньшим количеством файлов, чем следовало бы, это произошло из-за нашего собственного невнимания 😅. Однако, имея дело с размещенными в одном месте файлами, мы хотим, чтобы у нас было что-то другое.
В настоящее время мы продолжим использовать наш обходной путь, надеясь, что однажды люди в npm дадут нам то, что нам нужно. Это проблема программного обеспечения, управляемого сообществом, в частности сообщества JavaScript, иногда оно движется со скоростью света, иногда придерживается старых правил и практик. Вы никогда не узнаете, что будет завтра.