Progressive Web Apps

with Angular

Jeado Ko

Angular GDE

Jeado Ko

​haibane84@gmail.com

www.facebook.com/jeado.ko

  • Google Developer Expert in Angular

  • Software Engineer at Awair

NG-Conf 2017

10 Progressive Web App 특징

  • Progressive
  • Discoverable
  • Linkable
  • App-like
  • Responsive
  • Connectivity-independent
  • Re-engageable
  • Installable
  • Fresh
  • Safe

 App Shell architecture

 Service Worker API

Push API and Notifications API

관련된 APIs

  • Service Worker API

  • Cache API

  • Fetch API

  • Notifications API

  • Push API

  • IndexedDB API

  • Promises

Mobile Toolkit

Angular CLI를 사용할 때 --mobile 왜 안되요?

답변

더 이상의

플래그는 없습니다.

--mobile

2   NPM 패키지

@angular/service-worker

v1.0.0-beta.8 - Experimental service worker by the Angular Mobile team

@angular/app-shell

v0.1.0 - App Shell runtime library for Angular Progressive Web Apps

Service Worker

Angular Service Worker

NGSW

@angular/service-worker/bundles

@angular/service-worker/build

@angular/service-worker/companion

@angular/service-worker/worker

@angular/service-worker/plugins

4   앵귤러 서비스워커 주요 파트

@angular/service-worker/bundles

@angular/service-worker/build

@angular/service-worker/companion

@angular/service-worker/worker

@angular/service-worker/plugins

4   앵귤러 서비스워커 주요 파트

NGSW 설치

# 첫째, Angular Service Worker를 설치합니다.
$ npm install --save @angular/service-worker
# SW 등록과 app shell를 Angular CLI에서 활성화합니다.
$ ng set apps.0.serviceWorker=true
"apps": [
    {
        "serviceWorker": true
    }
]

.angular-cli.json

App 빌드

# NGSW works only in --prod mode
$ ng build --prod
<script src="sw-register.{HASH}.bundle.js"></script>
  • sw-register.{HASH}.bundle.js

  • worker-basic.min.js

  • ngsw-manifest.json

index.html

정적 콘텐츠 캐슁

{
  "static": {
    "urls": {
      "/index.html": "ae543...",
      "/main.bundle.js": "9ff18...",
      "/styles.bundle.css": "d6f44...",
      "/assets/images/logo.png": "0e33a...",
      ...
    }
  }
}

ngsw-manifest.json

라우트 리다이렉션

{
  "routing": {
    "index": "/index.html",
    "routes": {
      "/": {
        "prefix": false
      },
      "/some/routes-group-prefix": {
        "prefix": true
      }
    }
  }
}

ngsw-manifest.json

NGSW manifest 확장

{
    "static" : {
        ...autogenerated
    }
}
{
    "routing" : {...}
    ...
}

ngsw-manifest.json

간단히 데모를 볼까요?

Angular PWA

Static Content

Cache

외부 콘텐츠 캐슁

{
  "external": {
    "urls": [
      {
        "url": "https://fonts.gstatic.com/Roboto.ttf"
      }
    ]
  }
}

ngsw-manifest.json

Angular PWA

Static Content

Cache

External Content Cache

동적 콘텐츠 캐슁

{
  "dynamic": {
    "groups": [
      {
        "name": "api",
        "urls": {...},
        "cache": {...}
       }
    ]
  }
}

ngsw-manifest.json

동적 콘텐츠 캐슁

cache: {
  "optimizeFor": "freshness",   // or 'performance'
  "networkTimeoutMs": 200,
  "maxAgeMs": 1000,
  "maxEntries": 2,
  "strategy": "fifo"            // or 'lru', 'lfu'
}
urls: {
    "/api/breakingnews": {
        "match": "prefix"
    }
},

ngsw-manifest.json

Coming soon

Angular PWA

Static Content

Cache

External Content Cache

Dynamic Content

Cache

Companion

import {NgServiceWorker} from '@angular/service-worker';
constructor(public sw: NgServiceWorker) {}

app.component.ts

import {ServiceWorkerModule} from '@angular/service-worker'
imports: [
    ...
    ServiceWorkerModule
]

app.module.ts

유저에게 앱 업데이트를 물어본다!

sw.updates.subscribe(event => {
  if (event.type === 'pending') {
    // Ask user if they want to update?
    if (agreeToUpdate) {
        sw.activateUpdate(event.version);
    }
  } else {
    // event.type === 'activation'
    // NGSW is now serving a new version
    location.reload();
  }
});

app.component.ts

Web Push Notification

Web Push Notification with NGSW

Backend

Notification

Push Service

NGSW

Backend

Push Service

App

Subscription

Sending a notification

NGSW

App

Push settings

{
  "push": {
    "showNotifications": true,
    "backgroundOnly": false
  }
}

ngsw-manifest.json

Push subscription

constructor(public sw: NgServiceWorker) {}
sw.registerForPush().subscribe(subscriptionObject => {
    // Send subscription data to the server
});
import {NgServiceWorker} from '@angular/service-worker';

push.component.ts

sw.push.subscribe(notificationPayload => {
    // Process notification data
});

간단히 데모를 볼까요?

Mqtt Broker

GCM

Send Subscription

Send Push Message

Mqtt Connection

Send Notification

Angular PWA

Static Content

Cache

External Content Cache

Push

Dynamic Content

Cache

Basic Service Worker

import {bootstrapServiceWorker} from '@angular/service-worker/worker';
import {StaticContentCache} from '@angular/service-worker/plugins/static';
...

bootstrapServiceWorker({
  manifestUrl: '/ngsw-manifest.json',
  plugins: [
    StaticContentCache(),
    ...
  ]
});

worker/builds/basic.ts

Extending functionality

import {bootstrapServiceWorker} from '@angular/service-worker/worker';
import {StaticContentCache} from '@angular/service-worker/plugins/static';
...
import {MyCustomPlugin} from './plugins/my-custom-plugin';

bootstrapServiceWorker({
  manifestUrl: '/ngsw-manifest.json',
  plugins: [
    StaticContentCache(),
    ...
    MyCustomPlugin()
  ]
});

worker-custom.js

직접.. 빌드해야 합니다..

Automatic PWA

{
  "static": {...},
  "routing": {...},
  "external": {...},
  "dynamic": {...},
  "push": {...}
}

ngsw-manifest.json

Angular PWA

Static Content

Cache

External Content Cache

Push

Dynamic Content

Cache

Automatically

배운점

아직 프러덕션에선 쓰지말자...

배운점

그래도 Push Notification은 쓸만했다...

Thank you!

www.facebook.com/jeado.ko

Jeado Ko