javascript

AngularJS + Webpack = lazyLoad

  • пятница, 12 января 2018 г. в 03:16:13
https://habrahabr.ru/post/346406/
  • Разработка веб-сайтов
  • Клиентская оптимизация
  • JavaScript
  • Angular


AngularJS + Webpack = lazyLoad

Вступление


При написании Single Page Application разработчики в большинстве случаев сталкиваются с одной очень распространенной проблемой, а именно — создание lazyLoad модулей и их последующая загрузка на сторону клиента. Т.е. по какому-то действию или по переходу по URL (в большинстве случаев) мы должны загрузить определенный набор зависимостей — JavaScript, CSS, HTML и т.д. В реалиях современной Front-End разработки это будет большущий JavaScript файл. В этой статье я хочу поделиться своим опытом и показать как реализовать lazyLoad модули для AngularJS и тем самым уменьшить общий объем кода при первой загрузке приложения.

Почему AngularJS 1.x


Наверное, у тебя, уважаемый читатель, появился резонный вопрос: «Стоп, какой AngularJS 1.x, ведь совсем недавно был релиз Angular v5.2». Вопрос более чем уместен. Все просто, довольно много проектов, которые используют AngularJS 1.x и при этом себя хорошо чувствуют. Есть целый ряд отраслей для которых переход на новую версию очень затратный как в человеко-часах, так и в денежном эквиваленте. AngularJS 1.x еще очень востребован на рынке.

Велосипеды, которые уже есть


Так уж повелось, что в мире Front-End разработки велосипедов инструментов/подходов, чтобы решить один и тот же вопрос — вагон и маленькая тележка. Каждый выбирает под свои нужды, умения и знания. И здесь нет какого-то одного выверенного решения, которое подойдет в 99,99% случаев. Это и не хорошо и не плохо. Просто нужно это принять и жить дальше разрабатывать дальше. Кто-то выбирает RequireJS, кто-то curl.js, кто-то Browserify, кто-то <вставить свое>. Мы рассмотрим как реализовать lazyLoad загрузку модулей с использованием Webpack, UI-Router и ocLazyLoad. Всю закулисную магию будет проделывать ocLazyLoad. Если мы попробуем сделать lazyLoad модуль при помощи того же require.ensure и без использования ocLazyLoad, то получим примерно такую ошибку:

require.ensure error

Структура проекта


Итак, приступим. Оригинальный код проекта, для которого мне нужно было реализовать lazyLoad модули, я не могу предоставлять в общий доступ. Поэтому я сделал небольшое приложение. Я старался сделать так, чтобы приложение не выглядело как звездолет в котором непонятно, что откуда берется и вообще как это все работает. Основное назначение — это сделать рабочий прототип, который будет доступен онлайн (не только исходники). Ниже вы можете видеть структуру проекта для веток require-ensure и system-import. Для ветки import-es6 мы внесем небольшое дополнение.

project-root
├── src
│   ├── core
│   │   ├── bootstrap.js
│   ├── pages
│   │   ├── home
│   │   │   ├── about
│   │   │   │   ├── about.module.js
│   │   │   │   ├── about.view.html
│   │   │   ├── index
│   │   │   │   ├── index.module.js
│   │   │   │   ├── index.view.html
│   │   │   ├── home.module.js
│   │   │   ├── home.module.routing.js
│   │   │   ├── home.module.states.js
├── app.js
├── index.html

Прежде, чем мы приступим к работе с кодом, давайте обсудим два важных момента, которые влияют на то, будет ли наш модуль lazyLoad или нет:
  1. Чтобы модуль стал lazyLoad его не нужно указывать как зависимость для других модулей.
  2. Модуль не должен быть импортирован нигде, кроме того роута для которого вы хотите сделать этот модуль lazyLoad.

Если не очень понятно, не волнуйтесь — на практике сразу станет ясно, что к чему.

require.ensure() + $ocLazyLoad


require.ensure был предложен командой webpack еще в его первых версиях. Этот метод позволяет разработчикам динамически создавать отдельные файлы (чанки в контексте терминологии webpack) с какой-то частью кода, которые будут впоследствии загружены по требованию на стороне клиента. Данный подход является менее предпочтительным для создания динамически загружаемых модулей, но если сильно хочеться, то ничего страшного в этом нет. Этот метод подойдет прекрасно тем, кто хочет сделать lazyLoad модули без больших затрат на рефакторинг. Ниже вы можете видеть пример использования require.ensure для загрузки index.module.js: