В настоящее время разработка программного обеспечения с использованием пакетов стала стандартной практикой в самых популярных языках программирования. Существуют различные менеджеры пакетов, такие как Maven, Composer, npm и другие, которые помогают управлять зависимостями проектов путем кэширования зависимостей в операционной системе (например, в папках ~/.cache/composer/repo/
или ~/.npm/
). Обычно проекты хранят свои зависимости внутри своей файловой структуры, например, в папках ./node_modules/
или ./vendor/
. Если два проекта на одном компьютере используют одну и ту же зависимость, то обычно эта зависимость будет присутствовать в трех экземплярах: в файлах первого проекта, в файлах второго проекта и в кэше менеджера.
Клиентская часть веб‑приложений работает внутри браузера, и для нее браузер играет роль своего рода «операционной системы«. Существует множество популярных библиотек, таких как jQuery, Lodash, Three.js и другие, которые широко используются множеством веб‑сайтов и веб‑приложений. Поскольку клиентская часть часто собирается с помощью бандлеров, таких как Webpack, эти библиотеки многократно кэшируются браузерами. Ресурсы, такие как unpkg.com и jsdelivr.com, в некоторой степени помогают уменьшить дублирование, поскольку если несколько сайтов ссылается на один и тот же ресурс на unpkg.com, то все они будут использовать один и тот же объект из кэша браузера.
Учитывая, что основным языком программирования для фронтенда в веб‑приложениях является JavaScript/TypeScript, у которого есть собственный формат пакетов (package.json
), и что сборщики бандлов для фронтенда используют эти пакеты для формирования клиентской кодовой базы, возникает вопрос: почему бы не хранить npm‑пакеты (или хотя бы транспилированные значимые объекты кода) прямо в браузере, учитывая версионность и другие свойства, присущие пакету? Таким образом, можно было бы ссылаться на зависимости и их версии в каком‑нибудь «манифесте веб‑приложения«, вместо использования ссылок на unpkg.com/:package@:version/:file. Браузер мог бы автоматически загружать необходимые пакеты, если они еще не находятся в локальном хранилище, и предоставлять доступ к соответствующим файлам внутри пакета веб‑приложению или странице.
Мне кажется, что это весьма вероятный вектор развития веб‑разработки. Пакетные менеджеры уже доказали свою полезность в серверных приложениях, и этот опыт может быть применим и в браузерах. Возможно, этот функционал не появится уже завтра или послезавтра, но на мой взгляд, уже сейчас существует потребность в таком решении, иначе не было бы ресурсов, таких как unpkg.com.
Если у вас есть информация о движении в этом направлении, я буду очень признателен, если вы поделитесь этими данными в комментариях. Спасибо.
Комментарии (18)
flancer Автор
12.07.2023 07:03Вредоносная версия пакета уроет не один а множество сайтов.
Пакеты с версией кэшируются локально (т.е., в браузере). Новая версия пакета уроет множество сайтов, которые используют именно эту, новую, версию. Есть вариант, что в центральном хранилище, типа npmjs подменят уже ранее версионированный пакет, но он маловероятен. Опять же в локальном кэше браузера лежат "правильные" старые версии. В общем, этот момент в браузерах кардинально не отличается от серверной версии пакетного менеджера.
JS пакеты едят диск как не в себя, а браузеры и так много ресурсов потребляют.
А типа, когда они кэшируют тот же jQuery по 10 раз в разных бандлах разных сайтов, это лучше?
Вебсайт сломался потому что пакетный менеджер сломался.
или браузер сломался, или интернет отвалился, или ОСь пала... Чаще сайты ломаются из-за кривого скрипта в них самих, чем из-за ошибок браузера.
На этот вебсайт можно зайти только с эджа т.к. только у него "правильный пакетный менеджер (тм)".
Чё-т как-то за уши притянуто.
package.json
работает и с npm, и с yarn.Во времена JQuery куча сайтов тянули его с официального CDN, так что можно сказать что идея уже устарела т.к. почему-то так больше не делают.
DjPhoeniX
12.07.2023 07:03+2Для пет-проектов и небольших сайтов - сгодится. Но
почему-то так больше не делают
Потому что крупные проекты думают ещё и о безопасности, выставляя Content-Security-Policy как минимум.
npmjs подменят уже ранее версионированный пакет, но он маловероятен
flancer Автор
12.07.2023 07:03+1Потому что крупные проекты думают ещё и о безопасности, выставляя Content-Security-Policy как минимум.
Это хорошо, но не отменяет того факта, что крупные проекты делаются из модулей, которые хранятся в пакетах, имеют свои зависимости и как-то должны менеджироваться. Либо каждым проектом в отдельности, либо всё-таки можно будет договориться и доверять какому-то источнику, типа npmjs.com. По факту, исходники с него-то и тянутся, потом билдятся, а потом уже выставляют полиси.
и тем не менее, пакетами пользоваться не перестали. Выводы сделали, ошибки исправили и продолжают.
fedorro
12.07.2023 07:03+1Для сборки бандла небольшого фронтенда качается пакетов на несколько гигабайт, сборка занимает от минут до получаса, в зависимости от железа и размера кодовой базы и всех зависимостей - и всё это собирается в небольшой оптимизированный файл или несколько. И даже при этом браузерам временами не легко всё это выполнять без тормозов. А Вы хотите половину этого процесса ещё в браузерах запускать: десктопные варианты на мощных ПК ещё потянут, а мобильные чет мне кажется не очень, да ещё и гигабайты кэша пакетов надо где-то хранить.
flancer Автор
12.07.2023 07:03-2Я думал о браузерных пакетах, как о результатах сборки, а не как об исходниках для сборки. Сборка делается на сервере разраба, а в центральный репо помещается уже собранный пакет. Примерно так сейчас и происходит, но только без браузера (загляните в каталог
./dist/
).fedorro
12.07.2023 07:03+1Это какие-то полумеры, в папке dist такие-же собранные бандлы. Тогда надо зависимости зависимостей так-же подключать пакетами.
flancer Автор
12.07.2023 07:03+1Справедливо. Понятно, что пакетный менеджер для браузера не может быть один в один, как серверный пакетный менеджер. Но направление движения верное - делается пакет для работы в браузере и определяются зависимости на другие пакеты, собранные для работы в браузере. Можно начать с пакетов без зависимостей. С того же jQuery, хотя бы. Можно даже заморочится версиями ES6/CJS вдобавок.
HemulGM
12.07.2023 07:03+1А может не надо делать ещё одну операционку внутри другой? Может всё же делать клиентские приложения нативными? А сайты оставить сайтами?
flancer Автор
12.07.2023 07:03+1Поздно. Уже свершилось. Виртуализация, контейнеризация - это всё об этом. А теперь ещё и браузеры с IDB вместо файловой системы.
SuperCat911
12.07.2023 07:03+1Вообще такая технология есть и ей лет 15-20 - называется IFRAME. Вставляете IFRAME со всеми нужными политиками безопасности на свои страницы. Тот грузит скрипты внутри себя. Далее получаете ссылку на объект window этого iframe (через свойство iframe.contentWindow) И вперед.
А вообще, общий кеш в браузере вряд ли будет, в первую очередь по причине безопасности. Например, с такой технологией подключить к вредоносному сайту банковский скрипт с данными станет легко, даже куки не надо воровать.
Ресурсы, такие как unpkg.com и jsdelivr.com, в некоторой степени помогают уменьшить дублирование, поскольку если несколько сайтов ссылается на один и тот же ресурс на unpkg.com, то все они будут использовать один и тот же объект из кэша браузера.
Как они помогают? Я бы еще могу согласиться в том случае, если бы речь шла о загрузке таких скриптов через IFRAME. Вот в таком случае мы точно с вами могли бы говорить об экономии трафика. А если идет речь об идентичных прямых ссылках на внешний скрипт на различных сайтах, то кэширование будет распространяться на каждый отдельный ресурс. Посещая таких 2 сайта, идентичный файл библиотеки вы скачаете 2 раза.
почему бы не хранить npm‑пакеты (или хотя бы транспилированные значимые объекты кода) прямо в браузере, учитывая версионность и другие свойства, присущие пакету?
Да никто и сейчас Вам не мешает это делать даже без бандлеров и хранить в браузере. Есть прекрасный механизм import maps, который по сути является картой импортов. Эту карту импортов можно и в ручную писать, если есть надобность, а так видел на npm пакет, который конвертирует package.json в карту.
flancer Автор
12.07.2023 07:03А если идет речь об идентичных прямых ссылках на внешний скрипт на различных сайтах, то кэширование будет распространяться на каждый отдельный ресурс. Посещая таких 2 сайта, идентичный файл библиотеки вы скачаете 2 раза.
Да, кэширование в разные origin'ы одного и того же ресурса идёт раздельно. Так тем более есть смысл какие-то вещи (такие, как код библиотек) хранить в браузере централизованно.
А вообще, общий кеш в браузере вряд ли будет, в первую очередь по причине безопасности.
Так ведь речь на за общий кэш, а за менеджер пакетов. Мы же и так тянем одни и те же пакеты через npm при сборке. А потом один и тот же код пихаем в свои собственные бандлы, которые кэшируются раздельно под каждый origin, типа это секьюрно. А то, что по итогу в раздельные кэши попадает одна и та же библиотека из npm'а, так то такое.
Есть прекрасный механизм import maps, который по сути является картой импортов.
Надо будет его пощупать поближе. С первого раза он мне как-то не показался.
iliazeus
12.07.2023 07:03Не совсем понял, чем это будет принципиально отличается от использования unpkg/jsdelivr. Если хочется именно в одном отдельном файле это хранить, можно сделать себе vendor.js, в котором импортировать их с cdn и ре-экспортировать.
flancer Автор
12.07.2023 07:03Как тут уже указывали, браузер хранит кэш раздельно для каждого origin (схема://домен:порт). Если на одну и ту же картинку (например, аватар на gravatar.com) ссылаются различные сайты, то браузер будет кэшировать эту картинку для каждого сайта. Ну, вот так устроен мир (вернее, браузер).
В целом мотивы поведения вполне понятны - ресурс может для разных сайтов выдаваться по-разному. В зависимости от того, кто его запрашивал. Поэтому и кэшировать его нужно также с привязкой к origin. Вот и получается, что одни и те же ресурсы кэшируются множество раз на одном и том же браузере. Даже если в месте раздачи они постоянны и не изменяются в зависимости от запрашивающего.
С кодом вообще беда. Когда мы собираем бандлы, мы заталкиваем в них одни и те же библиотеки с npmjs.com (если нам нужна единая точка внедрения/отказа, то она у нас уже есть). А затем этот код в составе бандла закачивается на клиента и кэшируется браузером. Вот и получается, что тот же jQuery в кэш ложится не один раз, а несколько десятков, а то и сотен. В том числе и поэтому профиль Хрома и занимает гигабайты (у меня 3.5 Г в
~/.config/google-chrome
).Раз уж мы всё равно тянем исходники из npm-пакетов (единого репозитория), то почему бы не вынести менеджер пакетов на уровень самого браузера и не замкнуть его на аналогичный репозиторий? Только не npm-пакетов, а браузерных. Сбилдили разрабы jQuery новую версию для браузера, выложили её в этот репо, а все остальные в своём коде ссылаются на нужную им версию. То же самое, что и сейчас, только без всяких посредников в виде webpack'а и npm.
iliazeus
12.07.2023 07:03Как тут уже указывали, браузер хранит кэш раздельно для каждого origin (схема://домен:порт).
Не учел, спасибо. Правда, утверждается, что это, в первую очередь, защита от трекинга - по тому, насколько быстро загрузился ресурс, можно понять, был ли он уже в кеше, и использовать это как маркер. Как эта проблема будет решаться в случае с единым репозиторием? По набору пакетов и их версий в кеше, подозреваю, можно неплохой такой fingerprint составить.
flancer Автор
12.07.2023 07:03"Сложные задачи имеют более одного правильного решения, оптимальность которых зависит от применяемых критериев оценки." (с) и "Каждому решению присуще сожаление" (с) :) Кому-то важнее секьюрность, кому-то скорость, кому-то размер. Лично я не вижу проблем, если кто-то узнает, что у меня в кэше лежат программные файлы, относящиеся к gmail, shopify, mail.ru, habr, reddit и т.п. На край, можно сделать как в FF с разделением кэша - сделать использование менеджера пакетов настраиваемым.
iliazeus
12.07.2023 07:03+1Кстати, если вас волнует размер профиля, то разделение кешей можно полностью или частично отключить на уровне браузера. Как минимум в Firefox: https://developer.mozilla.org/en-US/docs/Web/Privacy/State_Partitioning#exempt_specific_origins_from_partitioning. Но, понятное дело, это влечет те самые потенциальные проблемы с трекингом.
tzlom
Вот вам причины почему это не случится никогда.
Вредоносная версия пакета уроет не один а множество сайтов.
JS пакеты едят диск как не в себя, а браузеры и так много ресурсов потребляют.
Вебсайт сломался потому что пакетный менеджер сломался.
На этот вебсайт можно зайти только с эджа т.к. только у него "правильный пакетный менеджер (тм)".
Во времена JQuery куча сайтов тянули его с официального CDN, так что можно сказать что идея уже устарела т.к. почему-то так больше не делают.
Helldar
Так не делают в том числе потому, что этот сайт может от нагрузки упасть или вовсе быть недоступным для пользователя и, таким образом, сайт не сможет загрузить недостающие звенья.