Прежде всего, для тех, кто еще не слышал,

WebAssembly.Studio - это онлайн-среда IDE (интегрированная среда разработки), которая помогает вам изучать и обучать других WebAssembly. Это также швейцарский армейский нож, который пригодится при работе с WebAssembly ». - Майкл Бебенита

Загрузка больших зависимостей

WebAssembly Studio использует редактор с открытым исходным кодом под названием Monaco Editor, который также используется для поддержки столь популярного VSCode. Размер зависимости Monaco Editor довольно большой, примерно 15 МБ. Конечно, он становится меньше при минимизации и сжатии с помощью gzip, но при начальной загрузке страницы по-прежнему нужно много загружать (особенно для пользователей с медленным подключением).

Приведенный ниже сценарий немного упрощен, но объясняет (в общих чертах), что происходило при начальной загрузке страницы. Прежде чем можно было отобразить пользовательский интерфейс (UI), необходимо было загрузить всю зависимость Monaco Editor.

1. User visits http://webassembly.studio
2. Load the whole Monaco Editor dependency
3. Render the UI
4. Register language support

Динамический импорт

await import("monaco-editor");

Новый синтаксис импорта (в настоящее время это предложение ECMA stage 3) представляет новый динамический способ импорта модулей. В отличие от статического import "module-name", который может использоваться только на верхнем уровне файла, import() возвращает обещание и позволяет импортировать модули по запросу или условно. Давайте посмотрим на различия.

// The old way
import moduleA from "moduleA";
import moduleB from "moduleB";
function doStuff(condition) {
  if (condition) {
    moduleA.doStuff();
  } else {
    moduleB.doStuff();
  }
}

В приведенном выше примере и moduleA, и moduleB всегда будут импортированы независимо от того, используются ли они на самом деле.

// The new way
async function doStuff(condition) {
  if (condition) {
    const module = await import("moduleA");
    module.doStuff();
  } else {
    const module = await import("moduleB");
    module.doStuff();
  }
}

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

Ускорение начальной загрузки страницы

Покопавшись, выяснилось, что только половина зависимости редактора Monaco нуждалась в рендеринге пользовательского интерфейса. Остальное можно будет импортировать позже, когда это понадобится. Теоретически это приведет к тому, что WebAssembly Studio загрузится в два раза быстрее.

Для этого мы сначала определили, какие части редактора Monaco необходимы для создания нового редактора. Добавив некоторые параметры оптимизации в наш webpack.config.js, нам удалось разделить зависимость Monaco Editor на два разных пакета. Один называется monaco-editor.bundle.js, а другой - monaco-languages.bundle.js - каждый размером около 7,5 МБ.

Когда пользователь теперь посещает http://webassembly.studio, происходит следующее (опять же, это немного упрощено).

Пользователю больше не нужно ждать загрузки полной зависимости Monaco Editor, прежде чем взаимодействовать с пользовательским интерфейсом. Теперь только пакет, который содержит материал, необходимый для создания нового редактора, должен быть импортирован до того, как компонент <App/> может быть визуализирован. После визуализации пользовательского интерфейса мы импортируем языковой пакет и регистрируем языковую поддержку. Вместо того, чтобы загружать полные 15 МБ, теперь нам нужно загрузить только половину.

Как насчет ваших зависимостей?

Подумайте о своих зависимостях. Насколько они большие? Какие из них необходимо загрузить, прежде чем вы сможете визуализировать свой пользовательский интерфейс? Скорее всего, вы можете найти зависимости, которые изначально не нужны и поэтому могут быть динамически импортированы, когда пользователь вместо этого вызывает определенные функции. То же самое и с большими зависимостями, такими как Monaco Editor. Действительно ли необходимо загружать всю зависимость перед рендерингом пользовательского интерфейса или можно будет разделить ее на разные пакеты, которые можно будет загрузить по запросу?

Инструменты для расследования

Я рекомендую использовать webpack-bundle-analyzer для анализа ваших зависимостей. Он предоставляет интерактивную масштабируемую древовидную карту, показывающую сгенерированные пакеты (и то, что включено в каждый из них). Чтобы узнать, когда загружен каждый пакет, запустите инструменты Chrome dev и посмотрите на вкладку сети.

Нужна помощь в начале работы с динамическим импортом? Ударьте меня по Slack http://wasm-studio.slack.com (для приглашения перейдите сюда: https://wasm-studio-invite.herokuapp.com/).