Vendor js для чего нужен
Еще один способ использования Webpack 4 и разделение кода
Ни для кого не секрет, что с выходом Webpack 4 стратегия разделения кода сильно поменялась. Тут даже лучше сказать, что она была заново придумана, т.к. старый подход просто перестал работать, а новый не понятно как использовать.
Для тех, кто все еще не в курсе, плагина webpack.optimize.CommonsChunkPlugin больше нет. Совсем. Вместо этого предлагается в конфиге писать следующее:
Это должно работать как магия. Т.е. теперь не мы говорим webpack’у что сделать общим чанком, а он сам все сделает, да еще может даже и лучше нас.
И наступит счастье. Шутка. На самом деле нет.
Базовые приготовления
Вот пример из документации:
Результатом сборки будут 3 файла: another.bundle.js, index.bundle.js, vendors
Теперь, для того, чтобы запустить наши веб приложения, мы, в одном случае, должны подключить vendors
index.bundle.js и index.bundle.js, а во втором vendors
index.bundle.js и another.bundle.js.
В чем проблема?
Проблема в имени vendors
index.bundle.js. Пока у нас меньше трех точек входа, ничего страшного не происходит. Здесь все кажется логичным — бандл содержит npm модули (они же vendors) и общие модули для index и another. На каждую из страниц мы подключаем 2 файла и не имеем проблем.
Однако если у нас три и более точки входа, то новых бандлов (они же чанки) может быть куда больше и мы уже не знаем ни их количества, ни имен. Все становится еще веселее, если мы еще и css извлекаем в отдельные файлы. И это проблема.
Как решить эту проблему?
После завершения работы webpack у нас нет никаких файлов, которые содержали бы в себе информацию о том, какие именно бандлы на той или иной странице надо подключать. И в какой последовательности.
Однако в output’е мы можем найти вот такие строки:
На самом деле это почти то, что нам надо. Т.е. webpack прекрасно знает какие бандлы нужны для каждой точки входа, но почему-то сам не хочет этой информацией с нами делиться.
Манифест нам здесь не помогает. Да, мы знаем что такой (vendors
index.bundle.js) бандл есть. Мы знаем где он лежит. Но кому он нужен не знаем. Т.е. манифест бесполезен.
Тогда я решил что раз webpack знает нужную информацию, то ее возможно получится достать с помощью плагинов. Готовых я не нашел и решил написать свой. И, только ради демонстрации этого плагина, я и пишу эту статью.
В файле webpack.config.(ts|js) добавим новый плагин:
и дождемся результата. Результатом будет файл entrypoints.json с вот таким содержанием:
Если используется extract-css, то кроме секции js будет еще и css.
5 приемов по разделению «бандла» и «ленивой» загрузке компонентов в React
Разделение Javascript-кода на несколько файлов называется разделением «бандла» или сборки (bundle splitting). Это позволяет загружать только тот код, который который используется приложением в данный момент, другие части загружаются по необходимости (по запросу пользователя).
Распространенные случаи разделения сборки и «ленивой» или отложенной загрузки (lazy loading) включают в себя следующее:
Загрузка дополнительного кода при переходе пользователя к новому представлению (view — слой, отвечающий за визуальное отображение)
Загрузка такого кода может быть связана с определенным действием, таким как прокрутка или нажатие кнопки
Также можно реализовать предварительную загрузку определенных ресурсов, которые представляют потенциальный интерес для пользователя
Это приводит к тому, что когда пользователь захочет получить доступ к определенной функциональности, она уже будет готова
1. Динамический импорт с помощью Webpack
Webpack позволяет загружать модули (компоненты) динамически во время выполнения кода. Рассмотрим пример:
Динамический импорт может использоваться в любом месте кода. Такой импорт сообщает Webpack о необходимости создания отдельной сборки для конкретного компонента. Поскольку модальное окно отображается только когда пользователь нажимает кнопку, мы можем отложить загрузку соответствующего кода.
Динамический импорт позволяет каждому компоненту выступать в роли микрофронтенда (microfrontend).
2. Split API для загрузки React-компонентов
Резервного компонента при возникновении ошибки
«Настоящего» компонента после загрузки сборки
Рассматриваемый интерфейс облегчает задачу разделения React-компонентов, позволяя избежать повторения шаблонного кода.
Разделение компонентов верхнего уровня на основе маршрутов — еще одна техника оптимизации, способ уменьшения времени загрузки приложения.
В целом, отложенная загрузка кода до запроса пользователем страницы по конкретному маршруту — это хорошая идея.
В данном случае мы также имеем возможность использовать динамический импорт.
3. Создание «вендорного бандла» (vendor bundle)
Прежде всего, вы можете спросить, для чего нам это нужно? Основная идея заключается в том, что в вендор помещается (выносится) код, который изменяется намного реже, чем код разрабатываемого приложения. Это позволяет использовать эффективные техники по кэшированию кода для повышения скорости загрузки страниц.
Вот как можно извлечь вендорный бандл из директории node_modules :
Если после этого вы запустите сборку ( yarn build или npm run build ), то увидите что-то вроде этого:
4. Создание нескольких вендорных бандлов
Обычно, все модули объединяются в один вендорный бандл.
Знаете ли вы, что мы можем создать несколько таких бандлов?
Например, поскольку React не будет меняться между сборками, имеет смысл закэшировать его в виде отдельного пакета в случаях, когда вопрос производительности является критически важным.
5. Ленивая загрузка компонентов с помощью React.lazy()
React.lazy() — это функция, позволяющая рендерить динамически импортируемые компоненты как обычные компоненты.
Динамический импорт с помощью React.lazy() :
Проп fallback принимает любой элемент (компонент). Компонент Suspense может быть помещен на любом родительском по отношению к «ленивому» компоненту уровне.
Suspense может оборачивать как отдельный компонент, так и группу компонентов:
Заключение
После применения техник, названных в данной статье, при анализе производительности вашего приложения, вы увидите два главных улучшения. Уменьшение размера сборки, загружаемой при инициализации приложения, и увеличение количества сборок, загружаемых по необходимости.
Это, безусловно, положительно повлияет на пользовательский опыт работы с приложением, поскольку оно станет более быстрым и отзывчивым.
Также не стоит забывать о том, что загруженный JavaScript-код, должен быть разобран и выполнен, что также требует некоторого времени и вычислительной мощности.
Облачные серверы от Маклауд быстрые и безопасные.
Зарегистрируйтесь по ссылке выше или кликнув на баннер и получите 10% скидку на первый месяц аренды сервера любой конфигурации!
Vendor js для чего нужен
Vendor.js is another way to use AMD on frontend.
Put vendor.js into public root of your project. Connect vendor.js to your page:
Now, vendor.js is ready to work. Option baseUrl in library configuration become automaticly to ‘myproject/’. WHat it means? Any request with relative paths will search file in the baseUrl folder. For example:
getting js file from the folder myproject/js
So, you can get many files:
Or, get different types of files:
As well as in the RequireJs it’s supports dependencies. If your module supports define(), you can get the fabric of module by the vendor() function. Just like this:
You can use nesting:
Or, run your script only after loading images And that script which you intend to use, you can load in one queue with other images.
Talk about bower components
Load bower package by the force
Well. Do you think this record loads only bootstrap.js? No, you’re wrong. It loads all files you need from this package (js and css, if you remember). You can say enough, but it is not. Bootstrap required jQuery, so that simple record loads jQuery too from bower_components/ folder.
You can change default bower folder by the calling function vendor.config(
You can use define() function:
Relative paths in define
You can get CSS files as well as get Js-files with function vendor.requirecss(string || array) or vendor(string || array)
This script will get file `mynewfolder/scripts/foo.js’
Debugging works with two functions: debug() and watch()
Use vendor.debug function to see reports in console
Use vendor.watch to watch reports only for [filename]
Chrome,FF,Opera,Safari,webkit’s browser in short, IE8+
Why reinvent the wheel??
What different between Requirejs, for example? — you can say. Simple reasons — the existence of Coca-Cola exclude the existence of other drinks? Good day.
Поиск правильного способа разделения материалов сайтов с помощью Webpack
Поиск наилучшего способа организации материалов веб-проектов может оказаться непростой задачей. Существует множество различных сценариев работы пользователей с проектами, множество технологий и других факторов, которые нужно принимать во внимание.
Автор материала, перевод которого мы сегодня публикуем, говорит, что хочет рассказать здесь обо всём, что нужно знать для грамотной подготовки материалов веб-проектов к работе. Во-первых, речь пойдёт о том, как подобрать такую стратегию разделения файлов сайта, которая наилучшим образом подойдёт для конкретного проекта и для его пользователей. Во-вторых — будут рассмотрены средства реализации выбранной стратегии.
Общие сведения
В соответствии с глоссарием Webpack, существуют две стратегии разделения файлов. Это — разделение бандла (bundle splitting) и разделение кода (code splitting). Эти термины могут показаться взаимозаменяемыми, но таковыми они не являются.
Однако мне хотелось бы сказать, что для многих сайтов гораздо более ценным оказывается именно первая стратегия — разделение бандлов. И, пожалуй, от её внедрения способны выиграть буквально все веб-проекты.
Поговорим об этом подробнее.
Разделение бандлов
В основе методики разделения бандлов лежит весьма простая идея. Если у вас имеется один огромный файл и вы меняете в нём одну единственную строчку кода, постоянному пользователю придётся, при очередном посещении сайта, загрузить весь этот файл. Однако если разделить этот файл на два файла, тогда такому же пользователю нужно будет загрузить лишь тот из них, в который внесены изменения, а второй файл будет взят из браузерного кэша.
Стоит отметить, что так как оптимизация материалов сайта путём разделения бандлов завязана на кэшировании, пользователям, посещающим сайт впервые, в любом случае, придётся загружать все материалы, поэтому для них нет разницы — будут ли эти материалы представлены в виде одного файла или в виде нескольких.
Мне кажется, что слишком много разговоров о производительности веб-проектов посвящено пользователям, которые посещают сайт впервые. Возможно, это так, отчасти, из-за важности первого впечатления, которое проект произведёт на пользователя, а также от того, что объёмы данных, передаваемые пользователям при первом посещении сайта, просто и удобно измерять.
Когда же дело доходит до регулярных посетителей, может оказаться сложным измерить воздействие на них применяемых техник оптимизации материалов. Но мы просто обязаны знать о том, к каким последствиям приводят подобные оптимизации.
Для анализа таких вещей потребуется нечто вроде электронной таблицы. Также нужно будет сформировать строгий перечень условий, в которых мы можем протестировать каждую из исследуемых стратегий кэширования.
Вот сценарий, подходящий под общее описание, данное в предыдущем абзаце:
▍Исходные условия
В соответствии с вышеописанным сценарием, когда мы, каждую неделю, вносим в код сайта какие-то изменения, строка contenthash пакета меняется. В результате, посещая еженедельно наш сайт, Алиса вынуждена загружать новый файл размером 400 Кб.
Если сделать симпатичную табличку (с бесполезной пока строкой итогов), содержащую данные о еженедельном объёме загрузки данных, приходящихся на этот файл, то у нас получится следующее.
Объём данных, загруженных пользователем
В результате оказывается, что пользователь, за 10 недель, загрузил 4.12 Мб кода. Этот показатель можно улучшить.
▍Отделение пакетов сторонних разработчиков от основного кода
Webpack 4 старается максимально облегчить жизнь разработчику, поэтому он делает всё, что может, и при этом не требует, чтобы ему сообщали о том, как именно нужно разбивать бандлы на части.
Такое вот автоматическое поведение программы приводит к немногочисленным восторгам, вроде: «Ну что за прелесть этот Webpack», и к множеству вопросов в духе: «А что это тут делается с моими бандлами?».
В любом случае, добавление в конфигурацию конструкции optimization.splitChunks.chunks = ‘all’ сообщает Webpack о том, что нам надо, чтобы он взял всё из node_modules и поместил бы это в файл vendors
После того, как мы провели такое вот базовое разделение бандла, Алиса, регулярно посещающая наш сайт еженедельно, будет загружать при каждом визите файл main.js размером 200 Кб. А вот файл vendor.js она загрузит лишь три раза. Произойдёт это во время визитов в первую, пятую и восьмую недели. Вот соответствующая таблица, в которой, волею судьбы, размеры файлов main.js и vendor.js в первые четыре недели совпадают и равняются 200 Кб.
Объём данных, загруженных пользователем
В результате получается, что объём загруженных пользователем за 10 недель данных составил 2.64 Мб. То есть, в сравнении с тем, что было до разделения бандла, объём уменьшился на 36%. Не такой уж и плохой результат, достигнутый добавлением нескольких строк в конфигурационный файл. Кстати, прежде чем читать дальше — сделайте то же самое в своём проекте. А если вам надо обновиться с Webpack 3 на 4 — делайте это и не беспокойтесь, так как процесс это довольно простой и всё ещё бесплатный.
Мне кажется, что рассматриваемое тут улучшение выглядит несколько абстрактно, так как оно растянуто на 10 недель. Однако если считать объём данных, отправленных лояльному пользователю, то это честное сокращение этого объёма на 36%. Это очень хороший результат, но его можно улучшить.
▍Выделение пакетов в отдельные файлы
В документации можно найти отличное разъяснение использованных здесь конструкций, но я, всё же, посвящу немного времени рассказу о некоторых вещах, так как для того, чтобы правильно ими воспользоваться, у меня ушло немало времени.
Ниже показана новая версия таблицы со сведениями об объёмах еженедельных загрузок данных. По странному стечению обстоятельств размер каждого файла с npm-пакетами составляет 20 Кб.
Объём данных, загруженных пользователем
Теперь объём загруженных за 10 недель данных составляет 2.24 Мб. Это значит, что мы улучшили базовый показатель на 44%. Результат это уже весьма приличный, но тут возникает вопрос о том, можно ли сделать так, чтобы добиться результата, превышающего 50%. Если подобное получится — это будет просто здорово.
▍Разбиение кода приложения на фрагменты
Выше я говорил о том, что на нашем сайте имеется два самостоятельных раздела. Первый — это список товаров, второй — страница с подробными сведениями о товаре. Размер кода, уникального для каждого из них, составляет 25 Кб (а 150 Кб кода применяется и там и там).
Страница со сведениями о товаре не подвергается изменениям, так как мы уже довели её до совершенства. Поэтому, если мы выделим её код в отдельный файл, этот файл, большую часть времени работы с сайтом, будет загружаться в браузер из кэша.
Кроме того, как оказалось, у нас имеется огромный встроенный SVG-файл, используемый для рендеринга значков, который весит целых 25 Кб и изменяется редко.
С этим надо что-то делать.
Мы вручную создали несколько входных точек, сообщая Webpack о том, что ему нужно создать отдельный файл для каждой из этих сущностей.
То, что мы только что сделали, позволит Алисе экономить почти каждую неделю по 50 Кб трафика. Обратите внимание на то, что файл с описанием значков мы отредактировали на шестой неделе. Вот наша традиционная таблица.
Объём данных, загруженных пользователем
Теперь за десять недель загружено всего 1.815 Мб данных. Это означает, что экономия трафика составила впечатляющие 56%. В соответствии с нашим теоретическим сценарием постоянный пользователь всегда будет работать с таким уровнем экономии.
Всё это сделано за счёт изменений, внесённых в конфигурацию Webpack. Код приложений мы для достижения таких результатов не меняли.
Выше я говорил о том, что конкретный сценарий, по которому проводится подобный тест, на самом деле, особой роли не играет. Сказано это из-за того, что, вне зависимости от используемого сценария, вывод из всего, о чём мы говорили, будет одним и тем же: разбиение приложения на небольшие файлы, имеющие смысл в применении к его архитектуре, позволяет снизить объёмы данных сайта, загружаемых его постоянными пользователями.
Совсем скоро мы перейдём к разговору о разделении кода, но сначала мне бы хотелось ответить на три вопроса, над которыми вы, наверняка, сейчас размышляете.
▍Вопрос №1. Разве необходимость выполнения множества запросов не вредит скорости загрузки сайта?
На этот вопрос можно дать простой короткий ответ: «Нет, не вредит». Подобная ситуация выливалась в проблему в былые времена, когда в ходу был протокол HTTP/1.1, а при использовании HTTP/2 это уже неактуально.
Хотя, надо отметить, что в этом материале, опубликованном в 2016 году, и в этой статье Khan Academy 2015 года делаются выводы о том, что даже при использовании HTTP/2, использование слишком большого количества файлов замедляет загрузку. Но в обоих этих материалах «слишком большое количество» означает «несколько сотен». Поэтому стоит помнить о том, что если вам приходится работать с сотнями файлов, на скорость их загрузки могут повлиять ограничения на параллельную обработку данных.
Если интересно, поддержка HTTP/2 имеется в IE 11 в Windows 10. Кроме того, я проводил всестороннее исследование среди тех, кто пользуется более старыми системами. Они единодушно заявили, что их скорость загрузки веб-сайтов особенно не заботит.
▍Вопрос №2. В Webpack-бандлах есть вспомогательный код. Создаёт ли он дополнительную нагрузку на систему?
▍Вопрос №3. При работе с множеством маленьких файлов ухудшается уровень их сжатия, не так ли?
Да, это тоже так. На самом деле, мне хотелось бы сказать вот что:
Только что я провёл испытание, в ходе которого код из файла размером 190 Кб был разбит на 19 частей. Это добавило примерно 2% к объёму данных, отправляемых в браузер.
В итоге получается, что при первом посещении сайта пользователь загрузит на 2% больше данных, а при последующих — на 60% меньше, и продолжаться это будет очень и очень долго.
Так стоит ли об этом беспокоиться? Нет, не стоит.
Когда я проводил сравнение системы, использующей 1 файл, и системы с 19 файлами, я испытал её с использованием различных протоколов, в том числе и HTTP/1.1. Нижеприведённая таблица очень сильно поддерживает идею о том, что больше файлов — значит лучше.
Данные о работе с 2 версиями сайта, размещённого на статическом хостинге Firebase, код которого имеет размеры 190 Кб, но, в первом случае, упакован в 1 файл, а во втором — разбит на 19
При работе в 3G и 4G-сетях на загрузку варианта сайта с 19 файлами ушло на 30% меньше времени, чем на загрузку сайта с одним файлом.
В данных, представленных в таблице, много шума. Например, один сеанс загрузки сайта по 4G (Run 2 в таблице) занял 646 мс, ещё один (Run 4) — 1116 мс, что на 73% дольше. Поэтому возникает ощущение, что говорить о том, что HTTP/2 «на 30% быстрее» — это несколько нечестно.
Я создал эту таблицу для того, чтобы посмотреть, что даёт использование HTTP/2. Но, на самом деле, единственное, что тут можно сказать, заключается в том, что применение HTTP/2, вероятно, не особо заметно влияет на загрузку страниц.
Настоящим сюрпризом стали две последних строчки в этой таблице. Тут представлены результаты для не самой новой версии Windows с IE11 и HTTP/1.1. Я, если бы заранее пытался предсказать результаты испытания, точно сказал бы, что такая конфигурация будет загружать материалы гораздо медленнее других. Правда, тут использовалось очень быстрое сетевое подключение, и мне, для подобных испытаний, вероятно, стоит пользоваться чем-то более медленным.
А теперь расскажу вам одну историю. Я, чтобы исследовать мой сайт на совсем уж древней системе, загрузил виртуальную машину Windows 7 с сайта Microsoft. Там был установлен IE8, который я решил обновить до IE9. Для этого я пошёл на страницу Microsoft, предназначенную для загрузки IE 9. Но сделать этого мне не удалось.
Кстати, если говорить об HTTP/2, хочется отметить, что этот протокол интегрирован в Node.js. Если вы хотите поэкспериментировать — можете воспользоваться написанным мной небольшим HTTP/2 сервером с поддержкой кэша ответов, gzip и brotli.
Пожалуй, о методике разделения бандлов я сказал всё, что хотел. Думаю, что единственный минус такого подхода, при использовании которого пользователям приходится загружать очень много файлов, на самом деле, не является таким уж «минусом».
Теперь поговорим о разделении кода.
Разделение кода
Основная идея методики разделения кода звучит так: «Не загружайте ненужный код». Мне говорили, что использование этого подхода имеет смысл лишь для некоторых сайтов.
Я предпочитаю, когда речь идёт о разделении кода, использовать правило 20/20, которое я только что сформулировал. Если есть какая-то часть сайта, которую посещают лишь 20% пользователей, и её функционал обеспечивают более 20% JavaScript-кода сайта, тогда этот код нужно загружать только по запросу.
Это, конечно, не абсолютные цифры, их можно подстроить под конкретную ситуацию, и в реальности существуют гораздо более сложные сценарии, чем вышеописанный. Самое важное тут заключается в балансе, и совершенно нормально совсем не пользоваться разделением кода, если для вашего сайта это не имеет смысла.
▍Разделять или нет?
Как найти ответ на вопрос о том, нужно вам разделение кода или нет? Предположим, у вас имеется интернет-магазин, и вы размышляете о том, надо ли отделить от остального кода тот код, который используется для приёма оплаты от покупателей, так как лишь 30% посетителей у вас что-то покупают.
Что тут сказать? Во-первых — вам стоило бы поработать над наполнением магазина и продавать что-то такое, что окажется интересным большему количеству посетителей сайта. Во-вторых — нужно понять то, какой объём кода совершенно уникален для того раздела сайта, где принимается оплата. Так как перед «разделением кода» следует всегда выполнять «разделение бандла», и вы, надеюсь, так и делаете, то вы, вероятно, уже знаете о том, какие размеры имеет интересующий нас код.
Возможно, этот код может оказаться меньше, чем вы думаете, поэтому, прежде чем радоваться новой возможности оптимизации сайта, стоит всё спокойно посчитать. Если у вас, например, имеется React-сайт, тогда хранилище, редьюсеры, система маршрутизации, действия, будут совместно использоваться всеми частями сайта. Уникальный для разных частей сайта код будет, в основном, представлен компонентами и вспомогательными функциями для них.
Итак, вы выяснили, что совершенно уникальный код раздела сайта, используемого для оплаты покупок, занимает 7 Кб. Размер остального кода сайта — 300 Кб. В подобной ситуации я не стал бы заниматься разделением кода по нескольким причинам:
А теперь рассмотрим пару примеров применения этой технологии.
▍Полифиллы
Я начинаю именно с этого примера, так как то, что мы тут рассмотрим, просто реализуется и применимо к большинству сайтов.
Я использую на своём сайте множество полезных штуковин в виде полифиллов. Поэтому у меня имеется файл, в котором всё это подключается. Он состоит из следующих восьми строчек:
Благодаря использованию конфигурации Webpack из предыдущего раздела, материалы полифиллов будут автоматически разделены на четыре файла, так как для их реализации используются четыре npm-пакета. Их размер составляет примерно 25 Кб, 90% браузеров они не нужны, поэтому имеет смысл загружать их динамически.
Благодаря применению Webpack 4 и использованию конструкции import() (не путайте её с ключевым словом import ), организовать условную загрузку полифиллов очень просто:
Кстати сказать, для использования import() вам понадобится плагин Babel dynamic-import. Кроме того, как сказано в документации к Webpack, команда import() использует промисы, поэтому полифилл для данной возможности нужно загружать отдельно от других полифиллов.
Как я и говорил, это очень просто. Рассмотрим теперь пример посложнее.
▍Динамическая загрузка материалов в React, основанная на маршрутах
Вернёмся к примеру с Алисой. Предположим, теперь на нашем сайте есть закрытый раздел для администраторов магазинов, куда они могут входить для того, чтобы управлять своими товарами.
В этом разделе имеется множество замечательных возможностей, куча графиков и здоровенная npm-библиотека для работы с ними. Так как на сайте уже применяется разделение бандлов, я могу понять, что всё это занимает более 100 Кб.
Причём, для этого не нужно заниматься конфигурированием.
Итоги
Полагаю, я рассказал всё, что хотел (хотя, надо отметить, мы не говорили тут о CSS). Подведём краткие итоги: