что значит main version

Нумерация версий программы

У многих начинающих разработчиков возникает вопрос: как назначать версию своей программы?

Поделюсь своим опытом.

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

Приведу несколько примеров написания версии:

Разберем каждое значение.

Ревизия (Revision)

Номер ревизии (revision) в системе управления версиями (Version Control System, VCS или Revision Control System). Благодаря ему, можно легко получить исходный код конкретной версии, выгрузив его из хранилища. Как правило, данное значение начинается с 1 с последующим увеличением соответственно номеру ревизии и никогда не обнуляется. В силу того, что значение важно только для разработки, в нумерации программы его часто опускают.

Билд (build)

Иными словами, номер сборки программы. После изменения в коде программы, как правило, проводят сборку программы, т.е. полную компиляцию всех файлов проекта. Как правило, данное значение начинается с 1 с последующим увеличением соответственно номеру сборки. Обнуление сборки либо не проводят никогда, либо при смене мажорной (major) версии. В силу того, что это значение важно только для разработки, в нумерации программы его часто опускают.

Патч или заплатка (patch)

Значение изначально устанавливается в 0 и увеличивается по мере внесения незначительных изменений в программу, например исправление какой-либо ошибки. Обнуляется при смене мажорной или минорной версий.

Минорная версия (minor)

Значение изначально устанавливается в 0 и увеличивается по мере внесения существенных изменений в программу, например, добавления нового функционала в программу. Значение также может повышаться при накоплении мелких изменений (патчей). Обнуляется при смене мажорной версии.

Мажорная версия (major)

Собственно говоря, это и есть версия программы. Значение мажорной версии устанавливается равной 1. Увеличивается данное значение с выходом новой версии, когда происходят значительные переходы в функциональности, например, добавлены новые функции, существенно меняющие возможности программы, изменен интерфейс, переписаны основные алгоритмы и т.п. Значение также может повышаться при накоплении серьезных (минорных) изменений.

Для пред-релизных версий используют значение равное 0, получая номер вида 0.9.*.*

Год.Месяц.День (year.month.day)

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

Кроме указанных позиций, разработчики часто используют буквенные обозначения в номере версии:

alpha — как правило, первая публичная тестовая версия, перед выходом финальной версии. Служит для обкатки и тестирования.

beta — вторая публичная тестовая версия, перед выходом финальной версии. Также служит для тестирования.

RC, RC2 — релиз-кандидат (Relise Candidate) версия, почти готовая к релизу. Служит для окончательной проверки.

final — окончательная (финальная) версия программы. Используется крайне редко, обычно просто опускается.

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

Источник

Несколько подробностей о функции main

Однажды заинтересовался, содержимым стека функции main процесса в linux. Провел некоторые изыскания и теперь представляю вам результат.

Варианты описания функции main:
1. int main()
2. int main(int argc, char **argv)
3. int main(int argc, char **argv, char **env)
4. int main(int argc, char **argv, char **env, ElfW(auxv_t) auxv[])
5. int main(int argc, char **argv, char **env, char **apple)

argc — число параметров
argv — нуль-терминальный массив указателей на строки параметров командной строки
env — нуль-терминальный массив указателей на строки переменных окружения. Каждая строка в формате ИМЯ=ЗНАЧЕНИЕ
auxv — массив вспомогательных значение (доступно только для PowerPC [1])
apple — путь к исполняемому файлу (в MacOS и Darwin [2])
Вспомогательный вектор — массив с различной дополнительной информацией, такой как эффективный идентификатор пользователя, признак setuid бита, размер страницы памяти и т.п.

Далее о том как получить массив вспомогательных значений для i386 и x86_64, а также об остальном содержимом «сегмента» стека.

Размер сегмента стека можно глянуть в файле maps:
cat /proc/10918/maps

7ffffffa3000-7ffffffff000 rw-p 00000000 00:00 0 [stack]

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

1. 0x7ffffffff000 Верхняя точка сегмента стека. Обращение вызывает segfault
0x7ffffffff0f8 NULL void* 8 0x00′
2. filename[0] char 1+ «/tmp/a.out»
char 1 0x00
.
env[1][0] char 1 0x00
.
char 1 0x00
3. 0x7fffffffe5e0 env[0][0] char 1 ..
char 1 0x00
.
argv[1][0] char 1 0x00
.
char 1 0x00
4. 0x7fffffffe5be argv[0][0] char 1+ «/tmp/a.out»
5. Массив случайной длины
6. данные для auxv void*[] 48′
AT_NULL Elf64_auxv_t 16
.
auxv[1] Elf64_auxv_t 16
7. auxv[0] Elf64_auxv_t 16 Ex.:
NULL void* 8 0x00
.
env[1] char* 8
8. 0x7fffffffe308 env[0] char* 8 0x7fffffffe5e0
NULL void* 8 0x00
.
argv[1] char* 8
9. 0x7fffffffe2f8 argv[0] char* 8 0x7fffffffe5be
10. 0x7fffffffe2f0 argc long int 8′ число аргументов + 1
11. Локальные переменные и аргументы, функций вызываемых до main
12. Локальные переменные main
13. 0x7fffffffe1fc argc int 4 число аргументов + 1
0x7fffffffe1f0 argv char** 8 0x7fffffffe2f8
0x7fffffffe1e8 env char** 8 0x7fffffffe308
14. Переменные локальных функций

‘ — описания полей в документах не нашел, но в дампе явно видны.

Для 32 битов не проверял, но скорее всего достаточно только разделить размеры на два.

Вспомогательный вектор
Для i386 и x86_64 нельзя получить адрес первого элемента вспомогательного вектора, однако содержимое этого вектора можно получить другими способами. Один из них — обратиться к области памяти, лежащей сразу за массивом указателей на строки переменных окружения.
Это должно выглядеть примерно так:

Структуры Elf<32,64>_auxv_t описаны в /usr/include/elf.h. Функции заполнения структур в linux-kernel/fs/binfmt_elf.c

Второй способ получить содержимое вектора:
hexdump /proc/self/auxv

Самый удобочитаемое представление получается установкой переменной окружения LD_SHOW_AUXV.

LD_SHOW_AUXV=1 ls
AT_HWCAP: bfebfbff //возможности процессора
AT_PAGESZ: 4096 //размер страницы памяти
AT_CLKTCK: 100 //частота обновления times()
AT_PHDR: 0x400040 //информация о заголовке
AT_PHENT: 56
AT_PHNUM: 9
AT_BASE: 0x7fd00b5bc000 //адрес интерпретатора, то бишь ld.so
AT_FLAGS: 0x0
AT_ENTRY: 0x402490 //точка входа в программу
AT_UID: 1000 //идентификаторы пользователя и группы
AT_EUID: 1000 //номинальные и эффективные
AT_GID: 1000
AT_EGID: 1000
AT_SECURE: 0 //поднят ли setuid флаг
AT_RANDOM: 0x7fff30bdc809 //адрес 16 случайных байт,
генерируемых при запуске
AT_SYSINFO_EHDR: 0x7fff30bff000 //указатель на страницу, используемую для
//системных вызовов
AT_EXECFN: /bin/ls
AT_PLATFORM: x86_64
Слева — название переменной, справа значение. Все возможные названия переменных и их описание можно глянуть в файле elf.h. (константы с префиксом AT_)

Возвращение из main()
После инициализации контекста процесса управление передается не в main(), а в функцию _start().
main() вызывает уже из __libc_start_main. Эта последняя функция имеет интересную особенность — ей передается указатель на функцию, которая должна быть выполнена после main(). И указатель этот передается естественно через стек.
Вообще аргументы __libc_start_main имеют вид, согласно файла glibc-2.11/sysdeps/ia64/elf/start.S
/*
* Arguments for __libc_start_main:
* out0: main
* out1: argc
* out2: argv
* out3: init
* out4: fini //функция вызываемая после main
* out5: rtld_fini
* out6: stack_end
*/
Т.е. чтобы получить адрес указателя fini нужно сместиться на два машинных слова от последней локальной переменной main.
Вот что получилось(работоспособность зависит от версии компилятора):

Надеюсь, было интересно.
Удач.

Спасибо пользователю Xeor за полезную наводку.

Источник

Создание самодостаточных исполняемых JAR

Когда ваше программное приложение выходит за пределы десятка строк кода, вам, вероятно, следует разделить код на несколько классов. На этом этапе встает вопрос о том, как их распределить. В Java классическим форматом является Java-архив, более известный как JAR. Но реальные программы, вероятно, зависят от других JAR.

Что такое самодостаточный JAR?

У MainClass метод static main(String…​ args)

Работа с classpath

Новые проблемы возникают при дистрибуции JAR, которые зависят от других JAR:

Вам необходимо синхронизировать версии библиотек.

3. По этой причине вам необходимо поместить JAR в то же место, относительное или абсолютное, в целевую файловую систему в соответствии с манифестом. Это означает, что сначала нужно открыть JAR и прочитать манифест.

Одним из способов решения этих проблем является создание уникальной единицы развертывания, которая содержит классы из всех JAR и может быть распространена как один артефакт. Существует несколько вариантов создания таких JAR:

Плагин Spring Boot (Для проектов Spring Boot)

Плагин Apache Assembly

Assembly Plugin для Apache Maven позволяет разработчикам объединять результаты проекта в единый распространяемый архив, который также содержит зависимости, модули, документацию сайта и другие файлы.

Одним из принципов Maven является создание одного артефакта на проект. Хотя бывают исключения, например, Javadoc и исходный код, но в целом, если вам нужно несколько артефактов, нужно создавать один проект на каждый артефакт. Идея плагина Assembly заключается в том, чтобы обойти это правило.

Ссылайтесь на предварительно определенную самодостаточную конфигурацию JAR

Установите главный класс для исполнения

Привяжите к package после формирование исходного JAR

Запуск mvn package дает два артефакта:

Первый JAR имеет то же содержимое, что и тот, который был бы создан без плагина. Второй — это самодостаточный JAR. Вы можете выполнить его следующим образом:

В зависимости от проекта он может выполняться успешно. или нет. Например, в примере проекта Spring Boot он не работает со следующим сообщением:

Зачастую плагин следует стратегии «побеждает последний записавший». Порядок основывается на имени JAR.

С помощью Assembly вы можете нек. Если вам нужно объединить ресурсы, вы, вероятно, захотите использовать плагин Apache Shade.

Плагин Apache Shade

Плагин Assembly является общим; плагин Shade ориентирован исключительно на задачу создания самодостаточных JAR.

Этот плагин предоставляет возможность упаковать артефакт в uber-jar, включая его зависимости, и оттенить — т.е. переименовать — пакеты некоторых зависимостей.

Плагин основан на концепции преобразователей: каждый преобразователь отвечает за работу с одним типом ресурсов. Преобразователь может копировать ресурс как есть, добавлять статическое содержимое, объединять его с другими и т.д.

Хотя вы можете разработать свой преобразователь, плагин предоставляет набор готовых преобразователей:

Конфигурация плагина Shade к приведенному выше Assembly выглядит следующим образом:

shade привязан к фазе package по умолчанию

Этот преобразователь предназначен для генерации файлов манифеста

Выполните ввод Main-Class

Настройте финальный JAR так, чтобы он был многорелизным JAR. Это необходимо в случае, когда любой из исходных JAR является многорелизным JAR

Запуск mvn package дает два артефакта:

При работе с проектом, взятым за образец, финальный исполняемый файл все еще не работает так, как ожидалось. Действительно, во время сборки появляется множество предупреждений о дублировании ресурсов. Два из них мешают корректной работе проекта. Чтобы правильно их объединить, нам нужно посмотреть на их формат:

META-INF/org/apache/logging/log4j/core/config/plugins/Log4j2Plugins.dat: этот Log4J2 файл содержит предварительно скомпилированные данные плагина Log4J2. Он закодирован в двоичном формате, и ни один из готовых преобразователей не может объединить такие файлы. Тем не менее, случайный поиск показывает, что кто-то уже занимался этой проблемой и выпустил преобразователь для работы с объединением.

META-INF/spring.factories : эти файлы, специфичные для Spring, они имеют формат «один ключ/много значений». Поскольку они текстовые, ни один готовый преобразователь не может корректно объединить их. Однако разработчики Spring предоставляют такую возможность (и многое другое) в своем плагине.

Чтобы настроить эти преобразователи, нам нужно добавить вышеуказанные библиотеки в качестве зависимостей к плагину Shade:

Объедините файлы /META-INF/spring.factories

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

Эта конфигурация работает! Тем не менее, есть оставшиеся предупреждения:

Лицензии, предупреждения и схожие файлы

Файлы конфигурации Service Loader

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

Плагин Spring Boot

Плагин Spring Boot использует совершенно другой подход. Он не объединяет ресурсы из JAR по отдельности; он добавляет зависимые JAR по мере их появления в uber JAR. Для загрузки классов и ресурсов он предоставляет специальный механизм. Очевидно, что он предназначен для проектов Spring Boot.

Настройка плагина Spring Boot проста:

Давайте проверим структуру финального JAR:

Скомпилированные классы проекта

Загрузка классов в Spring Boot

Вот выдержка из манифеста по образцу проекта:

Как вы можете видеть, главный класс является специфичным классом Spring Boot, в то время как «настоящий» главный класс упоминается в другой записи.

Для получения дополнительной информации о структуре JAR, пожалуйста, ознакомьтесь со справочной документацией.

Заключение

В этой статье мы описали 3 различных способа создания самодостаточных исполняемых JAR:

Assembly хорошо подходит для простых проектов

Когда проект становится более сложным и вам нужно работать с дублирующимися файлами, используйте Shade

Наконец, для проектов Spring Boot лучше всего использовать специальный плагин.

Полный исходный код этой статьи можно найти на Github в формате Maven.

Материалы для дополнительного изучения:

Что такое «хороший код» — это во многом спорная тема. Кто-то скажет, что если код работает, значит он достаточно хорош. Кто-то обязательно добавит, что код должен быть легок в понимании и сопровождении. А кто-то добавит, что код еще обязательно должен быть быстрым. Об этом уже много написано и сказано. Что же, давайте еще раз поговорим на эту интересную и холиварную тему. Регистрируйтесь на онлайн-интенсив

Источник

Руководство по Node.js, часть 4: npm, файлы package.json и package-lock.json

Основы npm

Npm (node package manager) — это менеджер пакетов Node.js. В первой части этого материала мы уже упоминали о том, что сейчас в npm имеется более полумиллиона пакетов, что делает его самым большим в мире репозиторием кода, написанного на одном языке. Это позволяет говорить о том, что в npm можно найти пакеты, предназначенные для решения практически любых задач.

Изначально npm создавался как система управления пакетами для Node.js, но в наши дни он используется и при разработке фронтенд-проектов на JavaScript. Для взаимодействия с реестром npm используется одноимённая команда, которая даёт разработчику огромное количество возможностей.

▍Загрузка пакетов

С помощью команды npm можно загружать пакеты из реестра. Ниже мы рассмотрим примеры её использования.

▍Установка всех зависимостей проекта

▍Установка отдельного пакета

Отдельный можно установить следующей командой:

Часто можно видеть, как эту команду используют не в таком вот простом виде, а с некоторыми флагами. Рассмотрим их:

▍Обновление пакетов

Для обновления пакетов служит следующая команда:

Обновить можно и отдельный пакет:

▍Загрузка пакетов определённых версий

В дополнение к стандартной загрузке пакетов, npm поддерживает и загрузку их определённых версий. В частности, можно заметить, что некоторые библиотеки совместимы лишь с некими крупными релизами других библиотек, то есть, если бы зависимости таких библиотек устанавливались бы без учёта версий, это могло бы нарушить их работу. Возможность установить определённую версию некоего пакета полезна и в ситуациях, когда, например, вам вполне подходит самый свежий релиз этого пакета, но оказывается, что в нём имеется ошибка. Ожидая выхода исправленной версии пакета, можно воспользоваться и его более старым но стабильным релизом.

Во всех этих случаях возможность указания версий пакетов, необходимых проекту, чрезвычайно полезна. Npm следует стандарту семантического версионирования (semver).

▍Запуск скриптов

Файл package.json поддерживает возможность описания команд (скриптов), запускать которые можно с помощью такой конструкции:

Например, вот как выглядят перечень скриптов, имеющийся в соответствующем разделе файла:

Весьма распространено использование этой возможности для запуска Webpack:

Такой подход даёт возможность заменить ввод длинных команд, чреватый ошибками, следующими простыми конструкциями:

▍Куда npm устанавливает пакеты?

При установке пакетов с использованием npm (или yarn) доступны два варианта установки: локальная и глобальная.

Выполняя такую команду, npm не устанавливает пакет в локальную папку проекта. Вместо этого он копирует файлы пакета в некое глобальное расположение. Куда именно попадают эти файлы?

Для того чтобы это узнать, воспользуйтесь следующей командой:

Однако если вы используете для управления версиями Node.js nvm, путь к папке с глобальными пакетами может измениться.

▍Использование и выполнение пакетов, установленных с помощью npm

Для того чтобы использовать её в своём коде, достаточно импортировать её с применением команды require :

Как быть, если пакет представляет собой исполняемый файл?

Посмотреть на то, как выглядит работа этого механизма можно, установив пакет cowsay. Он представляет собой шуточную программу, написанную для командной строки. Если передать этому пакету какой-нибудь текст, в консоли, в стиле ASCII-арта, будет выведено изображение коровы, которая «произносит» соответствующий текст. «Озвучивать» текст могут и другие существа.

Путь к пакету npx найдёт автоматически.

Файл package.json

Файл package.json является важнейшим элементов множества проектов, основанных на экосистеме Node.js. Если вы программировали на JavaScript, была ли это серверная или клиентская разработка, то вы, наверняка, уже встречались с этим файлом. Зачем он нужен? Что вам следует о нём знать и какие возможности он вам даёт?

Package.json представляет собой нечто вроде файла-манифеста для проекта. Он даёт в распоряжение разработчика множество разноплановых возможностей. Например, он представляет собой центральный репозиторий настроек для инструментальных средств, используемых в проекте. Кроме того, он является тем местом, куда npm и yarn записывают сведения об именах и версиях установленных пакетов.

▍Структура файла

Вот пример простейшего файла package.json :

Как видите, он пуст. Нет жёстких требований, касающихся того, что должно присутствовать в подобном файле для некоего приложения. Единственное требование к структуре файла заключается в том, что она должна следовать правилам формата JSON. В противном случае этот файл не сможет быть прочитан программами, которые попытаются получить доступ к его содержимому.

Если вы создаёте Node.js-пакет, который собираетесь распространять через npm, то всё радикальным образом меняется, и в вашем package.json должен быть набор свойств, которые помогут другим людям пользоваться пакетом. Подробнее мы поговорим об этом позже.

Вот ещё один пример package.json :

Вот пример посложнее, который я взял из приложения-примера, написанного с использованием Vue.js:

Как видите, тут прямо-таки немеряно всего интересного. А именно, здесь можно выделить следующие свойства:

▍Свойства, используемые в package.json

Большинство свойств, которые мы опишем, используются лишь для нужд репозитория npm, некоторые используются программами, которые взаимодействуют с кодом, вроде того же npm.

Свойство name

Свойство name задаёт имя пакета:

Подобные ограничения существуют из-за того, что когда пакет публикуется в npm, его имя используется для формирования URL страницы пакета.

Если вы публиковали код пакета на GitHub, в общем доступе, то хорошим вариантом имени пакета является имя соответствующего GitHub-репозитория.

Свойство author

Свойство author содержит сведения об авторе пакета:

Оно может быть представлено и в таком формате:

Свойство contributors

Свойство contributors содержит массив со сведениями о людях, внёсших вклад в проект:

Это свойство может выглядеть и так:

Свойство bugs

В свойстве bugs содержится ссылка на баг-трекер проекта, весьма вероятно то, что такая ссылка будет вести на страницу системы отслеживания ошибок GitHub:

Свойство homepage

Свойство homepage позволяет задать домашнюю страницу пакета:

Свойство version

Свойство version содержит сведения о текущей версии пакета:

При формировании значения этого свойства нужно следовать правилам семантического версионирования. Это означает, в частности, что номер версии всегда представлен тремя цифрами: x.x.x.

Первое число — это мажорная версия пакета, второе — минорная версия, третье — патч-версия.

Изменение этих чисел несёт в себе определённый смысл. Так, релиз пакета, в котором лишь исправляются ошибки, приводит к увеличению значения патч-версии. Если выходит релиз пакета, изменения, внесённые в который, отличаются обратной совместимостью с предыдущим релизом — то меняется минорная версия. В мажорных версиях пакетов могут присутствовать изменения, которые делают эти пакеты несовместимыми с пакетами предыдущих мажорных версий.

Свойство license

Свойство license содержит сведения о лицензии пакета:

Свойство keywords

Свойство keywords содержит массив ключевых слов, имеющих отношение к функционалу пакета:

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

Свойство description

Свойство description содержит краткое описание пакета:

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

Свойство repository

Свойство repository указывает на то, где находится репозиторий пакета:

Используемую при разработке пакета систему контроля версий можно задать и в явном виде:

Один и тот же пакет может использовать разные системы контроля версий:

Свойство main

Свойство main задаёт точку входа в пакет:

Когда пакет импортируют в приложение, именно здесь будет осуществляться поиск того, что экспортирует соответствующий модуль.

Свойство private

Свойство scripts

Свойство scripts задаёт список скриптов или утилит, которые можно запускать средствами npm:

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

Свойство dependencies

Свойство dependencies содержит список npm-пакетов, установленных в виде зависимостей пакета:

При установке пакета с использованиеме npm или yarn используются команды такого вида:

Эти пакеты автоматически добавляются в список зависимостей разрабатываемого пакета.

Свойство devDependencies

Свойство devDependencies содержит список npm-пакетов, установленных как зависимости разработки:

Пакеты попадают в этот список при их установке с помощью npm или yarn, выполняемой следующим образом:

Свойство engines

Свойство engines указывает, какие версии Node.js и других программных продуктов используются для обеспечения работы пакета:

Свойство browserlist

Свойство browserlist позволяет сообщить о том, какие браузеры (и их версии) собирается поддерживать разработчик пакета:

Этим свойством пользуются Babel, Autoprefixer и другие инструменты. Анализ этого списка позволяет им добавлять в пакет только те полифиллы и вспомогательные механизмы, которые нужны для перечисленных браузеров.

Показанное здесь в качестве примера значение свойства browserlist означает, что вы хотите поддерживать как минимум 2 мажорные версии всех браузеров с как минимум 1% использования (эти данные берутся с ресурса CanIUse.com), за исключением IE 8 и более старых версий этого браузера (подробнее об этом можно узнать на странице пакета browserlists).

▍Хранение в package.json настроек для различных программных инструментов

В package.json можно хранить настройки для различных вспомогательных инструментов вроде Babel или ESLint.

▍О версиях пакетов и семантическом версионировании

Учитывая то, что при использовании семантического версионирования все номера версий пакетов состоят из последовательностей, представляющих собой три числа, о смысле которых мы говорили выше, опишем следующие правила использования спецификаторов версий:

: если вы задаёте версию в виде

Файл package-lock.json

Цель этого файла заключается в отслеживании точных версий установленных пакетов, что позволяет сделать разрабатываемый продукт стопроцентно воспроизводимым в его исходном виде даже в случае, если те, кто занимается поддержкой пакетов, их обновили.

в применении к версии некоего пакета, вышел его патч-релиз, установлен будет не тот пакет, который использовался при разработке, а именно этот патч-релиз.

Эта концепция не нова, менеджеры пакетов, применяемые в других языках программирования (вроде менеджера Composer в PHP) используют похожую систему многие годы.

Файл package-lock.json нужно отправить в Git-репозиторий, что позволит другим людям скачать его в том случае, если проект является общедоступным, или тогда, когда его разработкой занимается команда программистов, или если вы используете Git для развёртывания проекта.

▍Пример файла package-lock.json

Разберём этот файл. Мы устанавливаем пакет cowsay, который зависит от следующих пакетов:

Итоги

Уважаемые читатели! Какой менеджер пакетов вы предпочитаете — npm или yarn?

Источник

Читайте также:  как узнать что симка заблокирована
Библиотека с советами