Если вы в течение последних двух лет занимались веб-разработкой, вы, вероятно, знакомы с термином прогрессивные веб-приложения (сокращенно PWA). PWA - это, по сути, веб-приложения, которые обеспечивают почти нативную работу на мобильных устройствах. По мнению Google, они должны быть:

  • Надежно - загружается мгновенно и никогда не показывает дауназавра, даже в неопределенных сетевых условиях.
  • Быстро. Быстро реагируйте на действия пользователя с помощью плавной анимации и без резкой прокрутки.
  • Увлекательный. Почувствуйте себя естественным приложением на устройстве с захватывающим пользовательским интерфейсом.

Итак, как мы можем убедиться, что наши приложения Angular следуют этим принципам и обеспечивают лучший пользовательский интерфейс?

Давайте возьмем простое приложение, которое я уже написал, и превратим его в PWA.

git clone --branch v0.0 https://github.com/MichaelSolati/ng-popular-movies-pwa.git
cd ng-popular-movies-pwa
npm install

Это приложение зависит от API The MovieDB. Получите ключ API и поместите его как moviedb переменную среды в свои src/environments/environment.ts и src/environments/environment.prod.ts .

Теперь, когда у нас все настроено, давайте запустим наше приложение npm run start:pwa, откроем Chrome, перейдем в localhost:8080 и посмотрим, что оно делает.

Что ж, он работает, и если вы нажмете на фильм, мы сможем получить о нем более подробную информацию. КЛАССНО! Но что происходит, когда мы не в сети?

Хм ... это не так уж и хорошо. Если бы существовал тест на PWA, который определенно провалил бы его ...

Подожди секунду! Есть тест на PWA! Google предоставляет расширение для Chrome под названием Lighthouse (установите его!), Которое будет запускать множество тестов для нашего приложения и генерировать отчет о том, насколько хорошо приложение работает. И, как я и ожидал, это приложение сильно провалилось.

Мы можем добиться большего, поэтому давайте сделаем это приложение более надежным!

Первое, что мы можем сделать для решения многих из этих проблем, - это использовать Service Worker. Service Worker позволяет нашему PWA загружаться мгновенно, независимо от состояния сети. Он выступает в качестве посредника между нашим приложением и внешним миром и позволяет нам контролировать кеш и то, как отвечать на запросы ресурсов. Наш Service Worker позволяет нам кэшировать важные ресурсы, чтобы снизить нашу зависимость от сети, обеспечивая мгновенный и надежный опыт для ваших пользователей даже при отсутствии Интернета.

Теперь команда Angular фактически предоставляет нам простой инструмент для добавления Service Worker, а также еще один набор инструментов (мы рассмотрим их позже), поэтому давайте установим наши инструменты со следующими.

npm install --save @angular/service-worker @angular/platform-server ng-pwa-tools

Это было легко, но нам также нужно будет обновить наш .angular-cli.json, чтобы сообщить, что мы хотим включить Service Worker. Таким образом, каждый раз, когда мы создаем производственную сборку, она будет включать нашего Service Worker.

ng set apps.0.serviceWorker=true

Теперь, если мы запустим производственную сборку ng build --prod и проверим нашу dist/ папку, мы увидим файл с именем ngsw-manifest.json, и если мы заглянем в него, мы увидим все ресурсы, которые будут кэшированы нашим Service Worker.

{
  "static": {
    "urls": {
      "/polyfills.859f19db95d9582e19d4.bundle.js": "afac7bb7a75d8e31bca1d0a21bc8a8b8d5c8043c",
      "/main.9058c5e7c9cdfe8d2b7e.bundle.js": "93293a45586e8923695e614746ae61d658cde5ed",
      "/sw-register.e4d0fe23aa9c2f3a68bb.bundle.js": "2a8aea5c32b446b61dab2d7c18231c4527f04bdc",
      "/vendor.1fd4688f90e61a7dc14d.bundle.js": "92513639a29f19b868733d40bb37732fc051b326",
      "/inline.6e6ae94836243f3c1fa2.bundle.js": "7e89339e980b3fe1ac59ed6ee44800ad1c647084",
      "/styles.b11de945749bdbf0b1ca.bundle.css": "3e920bb539d1da98370748436c09677e81a50d46",
      "/assets/.DS_Store": "edc93fc6e9f594928b74bd2e15a23417aa68ac5d",
      "/assets/app-icon.png": "cd65256eb15ba9d4150e783ddaf93399799f605f",
      "/favicon.ico": "c31b53fba70406741520464040435aabaaed370e",
      "/index.html": "3953d6c604ff7dc6b9e77e8310cd7877d2b49b0d"
    },
    "_generatedFromWebpack": true
  }
}

Но это не включает нашу конфигурацию маршрутизации, поэтому мы можем создать ее с помощью инструмента ngu-sw-manifest (часть ng-pwa-tools, которую мы установили ранее).

./node_modules/.bin/ngu-sw-manifest --module src/app/app.module.ts

Вероятно, у вас возникла такая ошибка…

ENOENT: no such file or directory, open 'app.component.html' ;

Наш ngu-sw-manifest инструмент не может перемещаться по нашему приложению, если есть относительные пути для шаблонов и таблиц стилей нашего компонента. Итак, мы добавим moduleId: module.id к @Component декоратору наших трех компонентов. (src/app/app.component.ts, src/app/home/home.component.ts и src/app/movie/movie.component.ts) Итак, у нас должны быть декораторы, которые выглядят так:

@Component({
  moduleId: module.id,
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})

И если мы снова запустим неудачную команду ngu-sw-manifest, мы увидим:

{
  "routing": {
    "index": "/index.html",
    "routes": {
      "/": {
        "match": "exact"
      },
      "^/movie/[^/]+$": {
        "match": "regex"
      },
      "/movie": {
        "match": "exact"
      },
      "^/.*$": {
        "match": "regex"
      }
    }
  },
  "static": {
    "urls": {
      "/favicon.ico": "c31b53fba70406741520464040435aabaaed370e",
      "/index.html": "551a50f7e2847f7ed85cda1f8e4b7877bfdbb492",
      "/inline.341ede62d3a808c130e1.bundle.js": "79d61daf91c3d745aac6c274fadc4ac826332358",
      "/main.07650488997a7b2dfcc1.bundle.js": "49be3a9f04ebc4383806652e13f3be4ca58b3902",
      "/ngsw-manifest.json": "29a96adf2f918b27cc37be64b7ee24d15d095963",
      "/polyfills.859f19db95d9582e19d4.bundle.js": "afac7bb7a75d8e31bca1d0a21bc8a8b8d5c8043c",
      "/styles.b11de945749bdbf0b1ca.bundle.css": "3e920bb539d1da98370748436c09677e81a50d46",
      "/sw-register.e4d0fe23aa9c2f3a68bb.bundle.js": "2a8aea5c32b446b61dab2d7c18231c4527f04bdc",
      "/vendor.f47d925e37c84559515b.bundle.js": "cd70a6deaa413652cc98b444f793f5cf1e837be6",
      "/worker-basic.min.js": "93904d94c0bef0479f1ec0b182788f4301d9f28e",
      "/assets/.DS_Store": "edc93fc6e9f594928b74bd2e15a23417aa68ac5d",
      "/assets/app-icon.png": "cd65256eb15ba9d4150e783ddaf93399799f605f"
    }
  }
}

Мы собираемся немного поработать с вышеуказанным объектом, но сначала в нашем src/ каталоге мы создадим файл ngsw-manifest.json и заполним его следующим образом:

{
  "dynamic": {
    "group": [
      {
        "name": "firebase",
        "urls": {
          "https://ng-popular-movies-pwa.firebaseapp.com/": { // Our deployed app url
            "match": "prefix"
          }
        },
        "cache": {
          "optimizeFor": "performance", // grabs data from cache only if data is stale
          "maxAgeMs": 3600000, // cache for about an hour
          "maxEntries": 20, // minimize cache size
          "strategy": "lru" // tells service worker how to remove cached date (least recently used first)
        }
      }
    ]
  }
}

Это устанавливает нашу стратегию кэширования по умолчанию. (Измените dynamic.groups[0].name и dynamic.groups[0].urls в зависимости от того, как вы планируете размещать свое приложение). Просто удалите включенные комментарии, и теперь мы можем запустить инструмент ngu-sw-manifest, чтобы взять наши активы, маршрутизацию и наш настраиваемый файл манифеста и вывести его в наш dist/ngsw-manifest.json.

./node_modules/.bin/ngu-sw-manifest --module src/app/app.module.ts \
   --out dist/ngsw-manifest.json

Итак, теперь мы быстро обновим наши npm скрипты до следующего:

{
    "ng": "ng",
    "start": "ng serve",
    "start:pwa": "npm run build && cd dist && http-server",
    "build": "ng build --prod && npm run ngu-sw-manifest",
    "test": "ng test",
    "lint": "ng lint",
    "e2e": "ng e2e",
    "ngu-sw-manifest": "./node_modules/.bin/ngu-sw-manifest --module src/app/app.module.ts --out dist/ngsw-manifest.json"
  }

Затем мы можем запустить наше приложение npm run start:pwa. Попробуйте запустить приложение после отключения сетевого подключения в консоли Chrome Dev, и мы даже сможем снова запустить Lighthouse на нем!

Так что у нас дела идут немного лучше (некоторые вещи, такие как HTTPS, мы не сможем исправить, пока не развернем это). Но, по крайней мере, мы удвоили этот рейтинг PWA! На следующей неделе мы собираемся повысить этот результат, улучшив нашу скорость (воспринимаемую и реальную).

Чтобы посмотреть на отличия кода от того, с чего мы начали, прямо сейчас щелкните здесь. Также, если вы чувствуете такое желание, я приглашаю вас развернуть свое приложение в Firebase. Если вы запустите Lighthouse в развернутом приложении, вы получите гораздо более высокий балл:

Часть вторая, озаглавленная PWA с Angular: Быть быстрыми, доступна здесь.