Meteor объединяет ваш код и все внешние библиотеки JavaScript, на которые вы полагаетесь, в один файл JavaScript. По мере роста сложности вашего приложения и количества зависимостей размер пакета будет увеличиваться. Это легко быстро выйти из-под контроля.

В этом посте я покажу вам, как значительно уменьшить размер вашего пакета с помощью динамического импорта и встряхивания дерева в вашем приложении Meteor.

Вы увидите, как я сократил свой пакет с 966 КБ до 399 КБ 📉
Gzip, то есть с 259 КБ до 123 КБ. 🚀

1. Базовое приложение

Чтобы проиллюстрировать эти методы, я создал простое приложение Meteor, которое состоит из двух экранов: home screen и test screen.

Экран home (App.js) - это легкий компонент; единственная трудность, которую он выполняет, - это объявление маршрутов с использованием react-router. test screen (Test.js) импортирует три дополнительных библиотеки: material-ui, moment и lodash.

Запустив визуализатор пакетов, мы видим, что размер пакета этого приложения составляет 966 КБ. Следует обратить внимание на следующие модули:

  • Материал пользовательского интерфейса - 347 КБ
  • Lodash - 72,1 КБ
  • Момент - 53,1кБ

Аудит Google Lighthouse оценил производительность нашего простого приложения на 89/100. Это приличный рейтинг, но у Lighthouse есть претензии к 651 мс времени оценки скрипта пакета meteor.js. Мы улучшим это, а также уменьшим размер пакета, выполнив следующие действия.

2. Тряска дерева

Этот шаг почти вдвое уменьшает размер пакета (до 536 КБ), и его реализация требует минимальных усилий ✌️

Пока мы не можем встряхнуть дерево всего нашего приложения, мы можем удалить неиспользуемые модули как изmaterial-ui, так иlodash. Это достигается с помощью пакетов babel-plugin-lodash и babel-plugin-direct-import. Установите с помощью следующей команды:

meteor npm i --save-dev babel-plugin-lodash babel-plugin-direct-import@^0.6.0-beta.1

Затем в корне вашего приложения создайте следующий .babelrc file:

Теперь, когда наше приложение компилируется, неиспользуемые модули frommaterial-ui и lodash исчезают.

Глядя на пакет, мы видим, что теперь размер приложения составляет всего 536 КБ. Мы можем понять почему, если посмотрим на размер следующего импорта:

  • Материал пользовательского интерфейса - 32,2 КБ (было 347 КБ)
  • Lodash - 21,7 КБ (было 72,1 КБ)
  • Момент - 53,1кБ (без изменений)

Meteor теперь объединяет только те коды material-ui и lodash, которые мы действительно используем.

Рейтинг Google Lighthouse теперь 95/100, и он больше не жалуется на время оценки скрипта. # победа

3. Динамический импорт с реактивным маршрутизатором

Домашняя страница приложения очень проста. Не требует material-ui, lodash или moment. Тем не менее, клиент по-прежнему должен загружать эти модули при посещении домашней страницы. Что, если бы мы могли отложить эти загрузки до тех пор, пока они действительно не понадобятся клиенту?

Динамический импорт позволяет нам это делать.

Хотя статически импортированный модуль будет включен в исходный пакет JavaScript, динамически импортированный модуль извлекается с сервера во время выполнения.

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

Есть несколько способов подойти к этому:

  1. Импортируйте дополнительные модули в зависимости от того, что может понадобиться пользователю. По сути, пользователи-администраторы (у которых намного больше экранов и используют дополнительные библиотеки - диаграммы, кто-нибудь?) Будут динамически импортировать больше маршрутов и, следовательно, больше компонентов + модулей, чем неаутентифицированные пользователи.
  2. Динамически импортируйте модули, когда вы их используете. Это будет работать нормально, но выполнение этого на основе модуля за модулем приводит к спагетти-коду.
  3. Динамический импорт отдельных компонентов. Чтобы получить действительно маленький начальный размер пакета, динамически импортируйте его по маршруту или по отдельности.

В предыдущем сообщении блога я показал вам, как динамически импортировать группы маршрутов (метод 1).

Метод 2 немного рудиментарен. Гораздо проще динамически импортировать отдельный компонент, чем динамически импортировать группу модулей внутри компонента.

Я предпочитаю метод 3, и для этого я создал компонент более высокого порядка. Используйте его на уровне react-router (т.е. передайте этот HOC в маршрут, чтобы экран загружался динамически) или отдельно, если вы хотите отложить загрузку дочернего компонента. Ситуации, в которых этот HOC полезен:

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

Как это работает?

DefferedComponent расширяет React.Component. Когда компонент монтируется, он идет и выполняет динамический импорт. После завершения импорта он будет повторно визуализирован с использованием только что импортированного компонента. Код показан ниже, или вы можете установить модуль @ninjapixel/meteor-defered-component, введя в свой терминал следующее:

meteor npm i --save @ninjapixel/meteor-deferred-component

Как это использовать

В следующих примерах я динамически загружаю компонент и экран (usingreact-router v4). Нам нужно указать путь к загружаемому компоненту реакции; к сожалению, мы не можем просто передать этот путь DeferredComponent, потому что динамический импорт должен быть объявлен заранее со статическими строками, чтобы компилятор мог это сделать. Мы работаем над этим, передавая функцию (importFunction), которая возвращает динамический импорт.

Используя эту технику для импорта экрана, размер пакета упал до 399 КБ. Обратите внимание на размер следующего импорта:

  • Материал пользовательского интерфейса - 4,44 КБ (было 347 КБ)
  • Lodash - 0 КБ (было 72,1 КБ)
  • Момент - 0кБ (было 53,1кБ)

4. Blaze и jQuery

Многие пакеты пользовательского интерфейса в экосистеме Meteor зависят от Blaze (38,7 КБ). В свою очередь, Blaze зависит от jQuery (96,5 КБ). Итак, если вы не используете Blaze в качестве интерфейса, убедитесь, что вы не используете пакеты, зависящие от Blaze (например, пакет accounts-ui).

5. Резюме

Можно добиться огромного прироста производительности за счет импорта только необходимого кода в исходный клиентский пакет. Это тоже довольно легко реализовать. Я хотел бы знать, для чего вы это используете, так что напишите мне в комментариях, чем вы занимаетесь!

Первоначально опубликовано на www.ninjapixel.io.