Comments 19
Есть мнение, что зависимости которые требуются для сборки пакета необходимо ставить в секцию dependencies
. Тогда при npm ci --production
мы будем ставить зависимости, необходимые для того, чтобы проект заработал. Например на CI
это просто сэкономит время сборки вашего приложения, особенно если у вас в dev-dependencies
находятся какие-нибудь жирные библиотеки, качающие бинарники.
Оптимизировать сборку проекта в контексте CI/CD имеет смысл при помощи других инструментов, например, кэширования. Я постараюсь раскрыть этот вопрос в следующих постах.
Посыл в том, что ваш код не будет работать без тех самых сборщиков, которые установлены в devDependencies
. Когда стоит придерживаться той семантики, которую вы описали? Когда вы разрабатываете библиотеку или backend
под nodejs
.
В той же документации на npmjs.org назначение devDependencies поля однозначно:
Packages that are only needed for local development and testing.
webpack
=> чтобы приложение работало
webpack-dev-server
=> для локальной разработки
Не холивара ради, а ради того, что есть и другие способы организации зависимостей.
Есть статья, которая возможно даст пищу для размышлений :) https://incubator.flaks.dev/devdependencies-mistake
Посыл в том, что ваш код не будет работать без тех самых сборщиков, которые установлены в devDependencies.
А он и не должен, т. к. пакет фронтенд приложения не является полноценным npm-пакетом. npm используется исключительно для того, чтобы скачать зависимости и сложить их в node_modules
.
Даже, если мы говорим о программе на Node.js, которая должна собираться перед своей работой (например через tsc), то распределение зависимостей может быть точно таким же. Разница лишь в том, что перед публикацией пакета в registry он будет автоматически скомпилирован (скрипт prepublishOnly
) и уже готовый для выполнения код окажется в архиве пакета. Таким образом, при установке в проект всё будет работать, несмотря на отсутствие dev-зависимостей, которые нужны для сборки.
А он и не должен, т. к. пакет фронтенд приложения не является полноценным npm-пакетом. npm используется исключительно для того, чтобы скачать зависимости и сложить их в node_modules.
Зачем вы пишите код, который не работает без devDependencies
?) Мой комментарий касается только процесса написания конечного web
клиента (не npm
пакета) и уменьшения кол-ва скачиваемых зависимостей, необходимых для того чтобы ваше приложение собралось и запустилось в браузере
Зачем вы пишите код, который не работает без devDependencies ?)
Не совсем уловил суть вопроса.
Мой комментарий касается только процесса написания конечного web клиента (не npm пакета) и уменьшения кол-ва скачиваемых зависимостей, необходимых для того чтобы ваше приложение собралось и запустилось в браузере
Это я понял и все мои ответы в данной ветке как раз соответствуют данному контексту.
Если только для фронтенда, то действительно, разделение на прод-зависимости и дев-зависимости не несет значимого смысла, т.к. в ci после сборки не нужны node_modules, и в финальную папку можно копировать только папку build.
В изоморфной же схеме либо при сборке для ноды, когда зависимости не включаются в билд, а подтягиваются в рантайме (например, с помощью опции externals в Webpack), разделение на разного рода зависимости становится актуальным. После сборки в финальном образе с файлами ci в идеале должен выполнить npm i --production, чтобы очистить node_modules от лишнего и уменьшить размер. Эту оговорочку надо бы включить в статью
Есть мнение, что зависимости которые требуются для сборки пакета необходимо ставить в секцию dependencies
Потом вы решите использовать Docker. Поиграетесь и придете к multistage сборке. И для оптимизации придется опять переносить зависимости сборки в devDependencies. Хотя не спорю, для отдельных сценариев этот способ может иметь право на жизнь.
К примеру, Express, как и многие другие библиотеки, использует пакет «debug». Если каждая библиотека будет бандлить «debug» внутри себя, то в конечном приложении код «debug» разных версий будет встречаться десятки раз, что будет раздувать количество кода. А так npm при установке зависимостей автоматически выполняет дедубликацию и пакет «debug» устанавливается только один раз (об этом упомянуто в моём посте).
Кроме того, бандлинг плохо бы сказался на безопасности. С одной стороны, как я упомянул выше, зависимости уже нельзя было бы обновлять на уровне приложения, а соответственно фиксы дыр не прилетели бы, пока каждый пакет не выпустит новую версию с пересобранным бандлом. Второй момент заключается в том, что код бандла очень большой, как правило минифицирован и соответственно не читабелен. Таким образом в нем очень легко скрыть какие-то программные закладки.
В будущих постах я подробнее расскажу о проблеме дублирующихся пакетов и почему это важно.
Прошу прощения. Видимо я не совсем уловил суть вопроса. Однако, часть моего ответа все еще верна — бандлинг изобретение для фронтенда, чтобы повысить производительность при работе со старыми версиями протокола HTTP, т. к. передать один файл по сети проще, чем, скажем, тысячу.
При использовании Node.js такой проблемы впринципе не стоит, по этой причине ее и нет смысла решать, это только усложнило бы сборку приложения. Кроме того, это лишило бы приложение ряда интересных возможностей, например, загрузки модулей динамически: представьте, что у вас в приложении есть директория в которую вы можете класть JS-файлы, а приложение само их находит, загружает и выполняет по мере необходимости. Забандлить такую реализацию было бы очень проблематично.
Ну и делать npm install
на продакшене явно не самая лучшая идея. Если вкратце, то лучше собирать артефакт приложения в среде CI/CD (на сборочной машине), а потом уже разворачивать готовый к выполнению код в продуктовой среде передавая нужные данные через окружение. Я постараюсь подробнее об этом написать в будущих постах.
Почему не делают? Делают. Погуглите “use webpack bundling for server side code”. Только вот смысла в этом не очень много: вебпак довольно-таки тормозной, а многие современные проекты пишут на TypeScript, который очень хорошо создает директорию типа dist из src и кладет в нее те же файлы, что были в src, но js, d.ts и map. И работает он гораздо быстрее костыльного ts-loader’а или awesome-ts-loader-а (причем все быстрее и быстрее, особенно с -b), плюс все фичи из tsconfig.json поддерживает. Зачем там еще webpack какой-то...
К слову, именно таким образом я лично и собираю проекты на Node.js, при помощи чистого tsc
и ни какой магии.
Да… Магия возникает, когда хочется задействовать разные нетрадиционные вещи типа ttypescript или typescript-is. Или когда хочется билдить при помощи tsc -b —watch не только сервер, но и клиент (с реактом и tsx!), я потом на результат (js+map) натравливать уже webpack —watch (ибо так работает гораздо быстрее, чем ts-loader, когда монорепа с многими подпроектами). Или когда хочется jest гонять не по ts-файлам, а по все тем же сгенерированным js (ибо так тесты в 2-3 раза быстрее запускаются, чем чере ts-jest, но приходится доставать бубен для поддержки снапшотов в правильном месте). Или когда хочется нормальный watch или eslint сделать в монорепе (ужас-ужас). А уж про es6-модули для TS и node и говорить не приходится. Все это в 2020 году находится в страшно сыром и разрозненном состоянии, к сожалению, но процесс медленно идет.
лучше собирать артефакт приложения в среде CI/CD (на сборочной машине), а потом уже разворачивать готовый к выполнению код в продуктовой среде
Такой подход превращает «отладку на продакшене» в кромешный ад. Например, если у меня есть в продакшене невидимая для юзеров веб-морда, либо какой-то фоновый сервис, в случае аварийной ситуации (или для эксперимента) я смогу всегда там файлик руками подправить, перебилдить-перезапустить и посмотреть, что будет. А если мне артефакты собирает CI, то такой фокус уже ее пройдет, да и депллй начинает длиться долговато (возникает зависимость от CI, аварийные фиксы не прочеррипикать также быстро).
В общем, много удобств в том, чтобы собирать там, где ранаешь. Например, в WhatsApp весь сервер так собирался (там erlang), и это суперудобно в аварийных ситуациях или для экспериментов.
Управление зависимостями JavaScript