Primary tabs

Проблемы с ростом JavaScript: от 0 до 13 000 зависимостей

Ссылка на оригинал - https://blog.appsignal.com/2020/05/14/javascript-growing-pains-from-0-to-13000-d…, автор публикации - Nikola Đuza

В сегодняшней заметке мы расскажем, как растет количество JavaScript-зависимостей во время работы над относительно простым проектом. Стоит ли беспокоиться о их количестве?

Имейте в виду, что этот пост в блоге связан с заголовком "Ride Down The JavaScript Dependency Hell", который был опубликован некоторое время назад. Мы покажем "реальный" пример того, как зависимости проекта могут вырасти с нуля до 13K.

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

Создание TODO в HTML и JavaScript

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

Довольно просто на данный момент - мы не хотим становиться дикими и модными в данный момент. Вы можете взглянуть на код на репозитории GitHub "просто сделай это".

Прямо сейчас единственная зависимость, в которой нуждается это приложение, - это браузер, который может открывать HTML-страницы. Мы можем сделать это практически с любым браузером.

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

  • прямые зависимости - количество установленных нами зависимостей (вместе с devDependencies)
  • унаследованные зависимости - количество зависимостей, установленных с прямыми зависимостями
  • итого - общее количество вышеперечисленных двух
  • новые зависимости - сколько зависимостей было установлено в предыдущей установке
Прямые зависимости Унаследованные зависимости Общее количество Новые зависимости
0 0 0 (не считая браузер) 0

У проекта все еще нет проекта package.json, поэтому мы все еще не являемся частью этой прекрасной экосистемы пакетов NPM. Это полезно, если вы не хотите усложнять вещи. Но сейчас мы здесь не для простых решений. Мы хотим смоделировать, как вы можете быстро перейти от нуля к куче зависимостей!

Итак, как и любой проект с внешним интерфейсом, нам не нужен простой JS. Мы хотим быть крутыми и использовать React!

Добавление React к нашему проекту

Повальное увлечение React сейчас в самом разгаре. Возможно, он даже не достигнет своего пика в 2020 году. Сейчас самое подходящее время, чтобы отказаться от того старого простого (Vanilla) JavaScript, который мы использовали в нашем проекте, и переключиться на то, что крутые дети используют в наши дни - всемогущий React.

Мы собираемся следовать инструкциям «Добавить React на сайт» с официального сайта React. Это означает, что мы добавим элемент тега script в наш HTML:

<head>
  <!-- ... other HTML ... -->
  <script
    src="https://unpkg.com/[email protected]/umd/react.development.js"
    crossorigin\
  ></script>
  <script
    src="https://unpkg.com/[email protected]/umd/react-dom.development.js"
    crossorigin\
  ></script>
  <!-- ... other HTML ... -->
</head>

Но, поскольку мы хотим использовать JSX, мы познакомимся с экосистемой NPM. Чтобы использовать JSX, мы должны установить Babel. Babel скомпилирует наш JSX-файл в JS, чтобы наш браузер мог легко его отобразить.

Во-первых, нам нужно package.json. Мы можем добавить его с помощью следующей команды:

$ npm init -y

Предыдущая команда настроит package.json и сделает наш проект готовым к установке Babel:

$ npm install --save-dev [email protected] [email protected]

...

+ [email protected]
+ [email protected]
added 305 packages from 128 contributors and audited 3622 packages in 15.904s

Вау, так что мы явно установили два пакета - babel-cli и babel-preset-react-app, но у них появилось больше собственных зависимостей. Если вы новичок в этой идее, вам может показаться странным. Я предлагаю вам прочитать предыдущий пост в блоге о том, как работают зависимости JavaScript.

Установка этих двух пакетов позволяет получить от 0 зависимостей NPM до 2 прямых и 3620 унаследованных зависимостей.

Прямые зависимости Унаследованные зависимости Общее количество Новые зависимости
2 3620 3622 +3622

Отлично, теперь мы можем использовать JSX во время работы Babel в фоновом режиме, чтобы следить за нашими изменениями:

$ npx babel --watch src --out-dir . --presets react-app/prod

Посмотрите, как выглядит репо после изменений.

Babel предварительно обработает наши JSX-файлы в JS-файлы. Но это звучит немного отрывочно. Я не хочу, чтобы React загружался в тег скрипта. Я хочу полный опыт разработчика, похожий на создание-реакции-приложение.

Для этого нам нужно будет добавить немного Babel и пакет - Webpack.

Добавление установки, аналогичной Create-React-App

Чтобы сделать это правильно, мы будем следовать рекомендованному способу настройки React в проекте с нуля.

Давайте удалим старые зависимости Babel, которые мы использовали:

$ npm uninstall babel-cli babel-preset-react-app --save-dev

Хорошо, мы вернулись к нулю зависимостей NPM.

Далее давайте добавим новые версии зависимостей Babel:

$ npm install --save-dev @babel/core @babel/cli @babel/preset-env @babel/preset-react

...

+ @babel/[email protected]
+ @babel/[email protected]
+ @babel/[email protected]
+ @babel/[email protected]
added 25 packages from 4 contributors, removed 4 packages, updated 7 packages and audited 4216 packages in 13.394s

babel-core является основным пакетом Babel - он необходим для преобразования нашего кода в Babel. babel-cli позволяет компилировать файлы из командной строки. preset-react и preset-env являются пресетами, которые преобразуют определенные разновидности кода - в этом случае пресет env позволяет нам преобразовать ES6 + в более традиционный JS, а пресет React делает то же самое, но вместо этого с JSX.

Теперь, когда нам это удалось, у нас есть 4216 зависимостей, основанных на отчете об аудите npm.

Теперь наша таблица зависимостей выглядит следующим образом:

Прямые зависимости Унаследованные зависимости Общее количество Новые зависимости
4 4212 4216 +594

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

Мы можем установить необходимые зависимости с помощью:

$ npm install --save-dev webpack webpack-cli webpack-dev-server style-loader css-loader babel-loader

...

+ [email protected]
+ [email protected]
+ [email protected]
+ [email protected]
+ [email protected]
+ [email protected]
added 448 packages from 308 contributors and audited 13484 packages in 23.105s

Это добавило еще несколько пакетов. Сейчас у нас всего 13484.

Прямые зависимости Унаследованные зависимости Общее количество Новые зависимости
10 13474 13484 +9268

Ну, это быстро обострилось! Здесь произошло то, что у каждой установленной нами зависимости есть свои зависимости. Тогда эти зависимости имеют свои зависимости. В общее число (13484) включаются все зависимости плюс зависимости зависимостей. Даже devDependencies! Вот почему мы получили дополнительные 9268 зависимостей, установив webpack и другие необходимые зависимости, чтобы он работал.

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

Например, если мы запустим npm audit в этот момент, мы получим это:

$ npm audit

                       === npm audit security report ===

┌──────────────────────────────────────────────────────────────────────────────┐
│                                Manual Review                                 │
│            Some vulnerabilities require your attention to resolve            │
│                                                                              │
│         Visit https://go.npm.me/audit-guide for additional guidance          │
└──────────────────────────────────────────────────────────────────────────────┘
┌───────────────┬──────────────────────────────────────────────────────────────┐
│ Low           │ Prototype Pollution                                          │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Package       │ yargs-parser                                                 │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Patched in    │ >=13.1.2 <14.0.0 || >=15.0.1 <16.0.0 || >=18.1.2             │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Dependency of │ webpack-dev-server [dev]                                     │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Path          │ webpack-dev-server > yargs > yargs-parser                    │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ More info     │ https://npmjs.com/advisories/1500                            │
└───────────────┴──────────────────────────────────────────────────────────────┘
found 1 low severity vulnerability in 13484 scanned packages
  1 vulnerability requires manual review. See the full report for details.

Мы видим, что зависимость а webpack-dev-server имеет yargs-parser низкую степень серьезности. Это зависимость от разработки, webpack-dev-serverи это, вероятно, не должно нас беспокоить. Быть зависимостью для разработки означает, что она webpack-dev-server используется yargs-parser в разработке, и очень маловероятно, что этот код окажется в нашей рабочей комплектации.

Помните, что пока мы добавили только devDependencies. Все это не попадет в наш производственный пакет, так что не о чем беспокоиться, верно? Давайте продолжим и узнаем.

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

Добавление React

Давайте переместим React с головы прямо в package.json:

$ npm install react react-dom

...

+ [email protected]
+ [email protected]
added 5 packages and audited 13506 packages in 6.148s
Прямые зависимости Унаследованные зависимости Общее количество Новые зависимости
12 13494 13506 +22

Теперь это другое. Мы получили только 22 дополнительных зависимости от установки reactи react-dom. Если мы запустим аудит npm для производства, мы получим это:

npm audit --production

                       === npm audit security report ===

found 0 vulnerabilities
 in 22 scanned packages

Результаты аудита означают, что в нашем производственном пакете окажется всего 22 пакета - код, который мы будем предоставлять людям, посещающим наше приложение со списком TODO. Это звучит не так уж плохо по сравнению с ошеломляющими 13506 зависимостями, которые мы имеем в нашей среде разработки.

После того, как мы установили все эти зависимости и переработали наш код для использования Webpack и Babel, наше приложение все еще работает:

TODO список рабочих

Кстати, вы можете просмотреть весь код, который мы добавили в репозитории на GitHub. Мы не вдавались в детали того, как мы создавали компоненты React и настраивали Webpack. Мы сосредоточились больше на зависимостях и их значении. Если вы заинтересованы в технических деталях работы списка TODO, пожалуйста, посетите репозиторий, упомянутый выше.

Стоит ли беспокоиться о стольких зависимостях?

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

Вставка вредоносного кода в библиотеку

Некоторое время назад была ситуация с широко используемым пакетом NPM - event-stream. Кто-то внедрил вредоносный код в популярный пакет, чтобы получить информацию о криптовалюте от своих пользователей. Посылка не взломана. Напротив, злоумышленник был сопровождающим, у которого был доступ на запись, предоставленный создателем пакета. Если вы заинтересованы в разговоре, ознакомьтесь с проблемой GitHub. Об этом также есть запись в блоге NPM.

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

Нарушение процесса сборки каждого

Совсем недавно другой широко используемыйis-promise пакет нарушил всю экосистему JS. Сам пакет состоит из 2 строк исходного кода. Он служит для проверки, является ли объект JS Обещанием . Библиотека использует 3,4 миллиона проектов, основанных на отчетах GitHub. Да, вы правильно прочитали - три целых четыре миллиона проектов.

Недавнее обновление 2.2.0 нарушило процесс сборки, поскольку проект не соответствовал стандартам модуля ES. Такие вещи случаются. Это не первый раз, и это, конечно, не будет последним. Если вы хотите узнать больше об этом, есть сообщение об этом.

«Доверяй, но проверяй» то, что ты устанавливаешь

Вы должны знать, что вы вкладываете в свой проект. Вы должны принять менталитет «доверяй, но проверяй». Нет никакой гарантии, что ситуации, которые случались event-stream или is-promise не произойдут в будущем с какой-либо другой зависимостью. Вы не должны отчаиваться от использования или участия в проектах с открытым исходным кодом. Этот инцидент был обнаружен только благодаря групповым усилиям. Просто помните о том, что вы вкладываете внутрь, package.json чтобы вы могли действовать правильно, когда наступают трудные времена.

С другой стороны, вы не можете знать о каждой зависимости. Представьте себе, что вы знаете, что происходит со всеми установленными нами 13k-зависимостями - вы, вероятно, сошли бы с ума. К счастью, существуют инструменты, такие как оповещения о безопасности GitHub и вся инициатива GitHub по безопасности.

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

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

Я надеюсь, что это сообщение в блоге добавило еще больше понимания того, что происходит, когда вы добавляете зависимости в свой проект JavaScript. Я также надеюсь, что это повысило некоторую осведомленность о безопасности с открытым исходным кодом и сделает вас более осторожными при выполнении этой npm installкоманды.

 

Добавить комментарий

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.

Не нашли ответ на свой вопрос? Возможно, вы найдете решение проблемы на нашем канале в Youtube! Здесь мы собрали небольшие, но эффективные инструкции. Смотрите и подписывайтесь на наш youtube-канал!

Смотреть на Youtube