В настоящее время разработка программного обеспечения с использованием пакетов стала стандартной практикой в самых популярных языках программирования. Существуют различные менеджеры пакетов, такие как 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)


  1. tzlom
    12.07.2023 07:03
    +5

    Вот вам причины почему это не случится никогда.

    Вредоносная версия пакета уроет не один а множество сайтов.

    JS пакеты едят диск как не в себя, а браузеры и так много ресурсов потребляют.

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

    На этот вебсайт можно зайти только с эджа т.к. только у него "правильный пакетный менеджер (тм)".

    Во времена JQuery куча сайтов тянули его с официального CDN, так что можно сказать что идея уже устарела т.к. почему-то так больше не делают.


    1. Helldar
      12.07.2023 07:03

      т.к. почему-то так больше не делают

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


  1. flancer Автор
    12.07.2023 07:03

    Вредоносная версия пакета уроет не один а множество сайтов.

    Пакеты с версией кэшируются локально (т.е., в браузере). Новая версия пакета уроет множество сайтов, которые используют именно эту, новую, версию. Есть вариант, что в центральном хранилище, типа npmjs подменят уже ранее версионированный пакет, но он маловероятен. Опять же в локальном кэше браузера лежат "правильные" старые версии. В общем, этот момент в браузерах кардинально не отличается от серверной версии пакетного менеджера.

    JS пакеты едят диск как не в себя, а браузеры и так много ресурсов потребляют.

    А типа, когда они кэшируют тот же jQuery по 10 раз в разных бандлах разных сайтов, это лучше?

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

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

    На этот вебсайт можно зайти только с эджа т.к. только у него "правильный пакетный менеджер (тм)".

    Чё-т как-то за уши притянуто. package.json работает и с npm, и с yarn.

    Во времена JQuery куча сайтов тянули его с официального CDN, так что можно сказать что идея уже устарела т.к. почему-то так больше не делают.

    unpkg.com и jsdelivr.com


    1. DjPhoeniX
      12.07.2023 07:03
      +2

      unpkg.com и jsdelivr.com

      Для пет-проектов и небольших сайтов - сгодится. Но

      почему-то так больше не делают

      Потому что крупные проекты думают ещё и о безопасности, выставляя Content-Security-Policy как минимум.

      npmjs подменят уже ранее версионированный пакет, но он маловероятен

      Далеко ходить не надо


      1. flancer Автор
        12.07.2023 07:03
        +1

        Потому что крупные проекты думают ещё и о безопасности, выставляя Content-Security-Policy как минимум.

        Это хорошо, но не отменяет того факта, что крупные проекты делаются из модулей, которые хранятся в пакетах, имеют свои зависимости и как-то должны менеджироваться. Либо каждым проектом в отдельности, либо всё-таки можно будет договориться и доверять какому-то источнику, типа npmjs.com. По факту, исходники с него-то и тянутся, потом билдятся, а потом уже выставляют полиси.

        Далеко ходить не надо

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


  1. fedorro
    12.07.2023 07:03
    +1

    Для сборки бандла небольшого фронтенда качается пакетов на несколько гигабайт, сборка занимает от минут до получаса, в зависимости от железа и размера кодовой базы и всех зависимостей - и всё это собирается в небольшой оптимизированный файл или несколько. И даже при этом браузерам временами не легко всё это выполнять без тормозов. А Вы хотите половину этого процесса ещё в браузерах запускать: десктопные варианты на мощных ПК ещё потянут, а мобильные чет мне кажется не очень, да ещё и гигабайты кэша пакетов надо где-то хранить.


    1. flancer Автор
      12.07.2023 07:03
      -2

      Я думал о браузерных пакетах, как о результатах сборки, а не как об исходниках для сборки. Сборка делается на сервере разраба, а в центральный репо помещается уже собранный пакет. Примерно так сейчас и происходит, но только без браузера (загляните в каталог ./dist/).


      1. fedorro
        12.07.2023 07:03
        +1

        Это какие-то полумеры, в папке dist такие-же собранные бандлы. Тогда надо зависимости зависимостей так-же подключать пакетами.


        1. flancer Автор
          12.07.2023 07:03
          +1

          Справедливо. Понятно, что пакетный менеджер для браузера не может быть один в один, как серверный пакетный менеджер. Но направление движения верное - делается пакет для работы в браузере и определяются зависимости на другие пакеты, собранные для работы в браузере. Можно начать с пакетов без зависимостей. С того же jQuery, хотя бы. Можно даже заморочится версиями ES6/CJS вдобавок.


  1. HemulGM
    12.07.2023 07:03
    +1

    А может не надо делать ещё одну операционку внутри другой? Может всё же делать клиентские приложения нативными? А сайты оставить сайтами?


    1. flancer Автор
      12.07.2023 07:03
      +1

      Поздно. Уже свершилось. Виртуализация, контейнеризация - это всё об этом. А теперь ещё и браузеры с IDB вместо файловой системы.


  1. 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 в карту.


    1. flancer Автор
      12.07.2023 07:03

      А если идет речь об идентичных прямых ссылках на внешний скрипт на различных сайтах, то кэширование будет распространяться на каждый отдельный ресурс. Посещая таких 2 сайта, идентичный файл библиотеки вы скачаете 2 раза.

      Да, кэширование в разные origin'ы одного и того же ресурса идёт раздельно. Так тем более есть смысл какие-то вещи (такие, как код библиотек) хранить в браузере централизованно.

      А вообще, общий кеш в браузере вряд ли будет, в первую очередь по причине безопасности.

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

      Есть прекрасный механизм import maps, который по сути является картой импортов.

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


  1. iliazeus
    12.07.2023 07:03

    Не совсем понял, чем это будет принципиально отличается от использования unpkg/jsdelivr. Если хочется именно в одном отдельном файле это хранить, можно сделать себе vendor.js, в котором импортировать их с cdn и ре-экспортировать.


    1. flancer Автор
      12.07.2023 07:03

      Как тут уже указывали, браузер хранит кэш раздельно для каждого origin (схема://домен:порт). Если на одну и ту же картинку (например, аватар на gravatar.com) ссылаются различные сайты, то браузер будет кэшировать эту картинку для каждого сайта. Ну, вот так устроен мир (вернее, браузер).

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

      С кодом вообще беда. Когда мы собираем бандлы, мы заталкиваем в них одни и те же библиотеки с npmjs.com (если нам нужна единая точка внедрения/отказа, то она у нас уже есть). А затем этот код в составе бандла закачивается на клиента и кэшируется браузером. Вот и получается, что тот же jQuery в кэш ложится не один раз, а несколько десятков, а то и сотен. В том числе и поэтому профиль Хрома и занимает гигабайты (у меня 3.5 Г в ~/.config/google-chrome).

      Раз уж мы всё равно тянем исходники из npm-пакетов (единого репозитория), то почему бы не вынести менеджер пакетов на уровень самого браузера и не замкнуть его на аналогичный репозиторий? Только не npm-пакетов, а браузерных. Сбилдили разрабы jQuery новую версию для браузера, выложили её в этот репо, а все остальные в своём коде ссылаются на нужную им версию. То же самое, что и сейчас, только без всяких посредников в виде webpack'а и npm.


      1. iliazeus
        12.07.2023 07:03

        Как тут уже указывали, браузер хранит кэш раздельно для каждого origin (схема://домен:порт).

        Не учел, спасибо. Правда, утверждается, что это, в первую очередь, защита от трекинга - по тому, насколько быстро загрузился ресурс, можно понять, был ли он уже в кеше, и использовать это как маркер. Как эта проблема будет решаться в случае с единым репозиторием? По набору пакетов и их версий в кеше, подозреваю, можно неплохой такой fingerprint составить.


        1. flancer Автор
          12.07.2023 07:03

          "Сложные задачи имеют более одного правильного решения, оптимальность которых зависит от применяемых критериев оценки." (с) и "Каждому решению присуще сожаление" (с) :) Кому-то важнее секьюрность, кому-то скорость, кому-то размер. Лично я не вижу проблем, если кто-то узнает, что у меня в кэше лежат программные файлы, относящиеся к gmail, shopify, mail.ru, habr, reddit и т.п. На край, можно сделать как в FF с разделением кэша - сделать использование менеджера пакетов настраиваемым.


      1. iliazeus
        12.07.2023 07:03
        +1

        Кстати, если вас волнует размер профиля, то разделение кешей можно полностью или частично отключить на уровне браузера. Как минимум в Firefox: https://developer.mozilla.org/en-US/docs/Web/Privacy/State_Partitioning#exempt_specific_origins_from_partitioning. Но, понятное дело, это влечет те самые потенциальные проблемы с трекингом.