Клиентская веб-разработка претерпела множество изменений в дизайне, начиная с выгрузки всего кода (включая PHP + HTML + CSS + JS и т. Д.) В один файл до написания модульного кода, в котором мы разбиваем код на более мелкие части, чтобы упростить процесс разработки. Точно так же способы доставки кода на клиентскую сторону претерпели значительные улучшения. В настоящее время распространенной практикой для одностраничных приложений (SPA) является объединение всех этих файлов в один файл JS (в основном известный как файл пакета) и отправка его клиенту.

Почему мы должны использовать один файл ??

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

Да! Поэтому нам нужно найти золотую середину, где мы сможем отправить пользователю достаточно информации, чтобы он мог начать работу и отправить более поздние биты «по запросу». Это делается с помощью «разделения кода».

Определение разделения кода от Адди Османи:

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

Я использую здесь сборщик модулей Webpack. Он достаточно умен, чтобы автоматически определять фрагменты при сканировании кода приложения в процессе сборки. Для начала я отделяю код поставщика от кода приложения (фактический код, написанный нами), предоставляя несколько точек входа в файле webpack.config.js. Делая это, я могу кэшировать комплект поставщика на стороне клиента, поскольку он не сильно меняется с течением времени. Таким образом, монолитный пакет теперь разбит на две части: bundle.js и vendor.bundle.js. Большой! Однако я все еще отправляю весь свой код клиенту в bundle.js, что нежелательно.

Теперь посмотрим, как можно еще уменьшить и разделить bundle.js с помощью Webpack. Концепция: в процессе объединения Webpack читает исходный код и понимает, какие биты необходимо объединить отдельно при обнаружении функции dynamic import (), тем самым создавая значимые фрагменты (отдельные файлы javascript). Затем эти фрагменты загружаются на клиентскую сторону по запросу. В отличие от традиционных способов импорта модулей статически, что приводит к созданию одного пакета, теперь пакеты будут импортироваться динамически, что приведет к созданию нескольких пакетов.

Я буду делать разбиение кода на 2 уровня

а) Уровень маршрута

б) Уровень компонентов

Разделение кода на уровне маршрута

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

В моем приложении есть два маршрута, а именно вводный и завершенный, хранящиеся в файле Router.jsx. Это приведет к созданию монолитного пакета. Давайте изменим этот код так, чтобы процесс объединения приводил к созданию нескольких пакетов и загружал их для клиента только по запросу. Ниже приведен обновленный файл маршрутизатора, в котором я использую функцию getComponent (), предоставляемую response-router Вместе с динамическим import () для разрыва и загрузки компонентов.

Здесь для каждого маршрута я заменил компонент prop в ‹Route /› с имени компонента на функцию getComponent (), которая принимает два аргумента nextState и функцию обратного вызова. Здесь в функции import () мы передаем путь к компоненту. Давайте рассмотрим процесс объединения здесь - Webpack начинает с обхода каждой строки кода, и всякий раз, когда встречается import (), Webpack достаточно умен, чтобы начать создавать новый пакет для компонентов внутри него. Таким образом, в моем приложении было создано 3 пакета, один для компонента «вводного» маршрута и его частей, второй для компонента маршрута «завершено» и его частей, третий для кода, который не является частью маршрута.

Обратите внимание, что Webpack будет внутренне отслеживать пакеты и их взаимосвязь; нам не о чем беспокоиться. Итак, здесь всякий раз, когда встречается какой-либо маршрут, выполняется соответствующая функция getComponent (). Выполняется функция import (), которая здесь действует как обещание. Соответствующий пакет будет доставлен клиенту, который был создан во время процесса объединения.

Подождите, почему это все еще не работает?

Примечание. Нам нужно добавить плагин babel для поддержки динамического импорта () в нашем приложении с помощью syntax-dynamic-import.

Разделение кода на уровне компонентов

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

Мы импортируем модули статически, например, компонент UserProfile связан с компонентом HomeScreen. Позвольте мне показать вам, как вы можете разбить это на отдельные части и загрузить по запросу. Здесь я снова использую функцию import (), которая творит «магию». Я создал служебный компонент «LazyLoad», который поможет мне разделить компоненты на несколько пакетов и загрузить их при обнаружении. Давайте посмотрим на компонент LazyLoad.

Посмотрев, что такое компонент LazyLoad, давайте воспользуемся компонентом LazyLoad для вызова компонента UserProfile из компонента HomeScreen.

Альт! Разделение кода нашего приложения завершено.

Подождите …… Какого черта, как?

Вот посмотрите, что только что произошло. Теперь я вызываю компонент LazyLoad вместо компонента UserProfile из компонента HomeScreen. Функция getComponent () передается в качестве реквизита компоненту LazyLoad, который выполняется в componentDidMount () LazyLaod. Эта функция использует динамический import () для импорта компонента UserProfile по запросу. Я упомянул путь к компоненту UserProfile для импорта функции. Таким образом, с помощью функции импорта мы можем разбить наш единственный пакет на несколько пакетов.

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

Первоначальный размер моего монолитного пакета составлял 2,7 МБ, который разбит на несколько пакетов. Первый пакет, содержащий базовый код для обслуживания пользователя, на данный момент составляет 482 КБ.

Что нужно помнить

I. Разделение кода может выполняться на разных уровнях, здесь, в сообщении блога, это сделано в трех разных местах - 1. Разделение кода поставщика и кода приложения. 2. Разделение кода по маршрутам. 3. Разделение компонентов на части.

II. Функция javascript import () помогает нам разбивать код на части и загружать их на клиентскую сторону по запросу.