Реализация PWA

с помощью Angular Mobile Toolkit

Angular 2

яркие особенности

мрачные особенности

2 года разработки

нет обратной совместимости с 1.x

Bre

a

king

ch

ange

s

Гибкость

разносторонность

Быстродействие

Быстродействие

Компиляция Ahead of Time

Change detection

Рендер на стороне сервера

Web Workers

Масштабируемость

Масштабируемость

Lazy-loading

Масштабируемый слой коммуникаций с сервером

Удобство

CLI

npm install -g angular-cli
ng new my-shiny-app
cd my-shiny-app
ng serve
ng generate component my-shiny-component
ng g component my-shiny-component
ng g class my-shiny-class
ng g service my-shiny-service

вернемся к PWA...

Mobile Toolkit

Angular CLI

ng new myApp --mobile

The --mobile flag has been disabled temporarily while we await an update
of angular-universal for supporting NgModule. Sorry for the inconvenience.

GitHub

NPM Packages

Latest news

App Shell

<html>
  <body>
    <app-root-component>
      <h1>Loading...</h1>
    </app-root-component>
  </body>
</html>
<html>
 <body>
    <app-root-component>
      <style>...</style>
      <div class="md-header">
        <h3>Proper Application Shell</h3>
      </div>
      <div class="md-progress-bar"></div>
      <div class="signup-form">...</div>
    </app-root-component>
 </body>
</html>

App Shell

import { UniversalModule } from 'angular2-universal';

@NgModule({
  bootstrap: [AppComponent],
  imports: [
    AppModule,
    UniversalModule.withConfig({
      ...
    }),
})
export class AppShellModule {}

platformUniversalDynamic()
  .serializeModule(ShellModule)
  .then(html => console.log(html));

App Shell

# Install app-shell utility from github.com/angular/mobile-toolkit
$ npm install --save @angular/app-shell
// App code
import {AppShellModule} from '@angular/app-shell';

// In NgModule used for Universal prerendering:
AppShellModule.prerender()

// At runtime:
AppShellModule.runtime()

App Shell

@Component({
  selector: 'app-root-component',
  template: `
    <!-- Only show loading indicator in the shell -->
    <loading-indicator *shellRender>
    </loading-indicator>

    <!-- Hide a dynamic view until runtime -->
    <dynamic-view *shellNoRender>
    </dynamic-view>
    `
})
export class AppRootComponent {}

Pre-fetching and caching

# First, install the Angular Service Worker
$ npm install --save @angular/service-worker
<script type="text/javascript">
  // Require worker-basic.min.js copied to deploy directory from
  // node_modules/@angular/service-worker/bundles 

  // Feature detection guards against older browsers that don't
  // support service workers.
  if (navigator.serviceWorker) {
    navigator.serviceWorker.register('/worker-basic.min.js');
  }
</script>

Pre-fetching and caching

ngsw-manifest.json:

{
  "static": {
    "urls": {
      "/index.html": "ae543...",
      "/app.js": "9ff18...",
      "/logo.png": "0e33a...",
      ...
    }
  }
}
import AngularSWPlugin from '@angular/service-worker/webpack';

webpack({
  entry: 'index.html',
  output: {...},
  plugins: [
    ...,
    new AngularSWPlugin()
  ]
});

Динамическое кэширование

{
  ...,
  "dynamic": {
    "match": [{
      "url": "/api",
      "prefix": true,
      "strategy": "fastest"
      "invalidate": [...]
    }]
  }
}

Скоро

Manifest

manifest.webapp

{
  "name": "Hello Mobile",
  "short_name": "Hello Mobile",
  "icons": [
        {
            "src": "/android-chrome-36x36.png",
            "sizes": "36x36",
            "type": "image/png",
            "density": 0.75
        },
        ...
  ],
  "theme_color": "#000000",
  "background_color": "#e0e0e0",
  "start_url": "/index.html",
  "display": "standalone",
  "orientation": "portrait"
}

PUSH-УВЕДОМЛЕНИЯ

Backend

Push Service

Service worker

Инициализация

ngsw-manifest.json:

{
  ...,
  "push": {
    "showNotifications": true
  }
}
manifest.webapp

{
  ...,
  "gcm_sender_id": "12345"
} 

Сервис уведомлений

Сервис уведомлений

Сервер

# web-push package nicely handles details of pushing data
$ npm install --save web-push
const webPush = require('web-push');
webPush.setGCMAPIKey(...);

let payload = {
  notification: {
    title: 'Hello from the server', body: '...', icon: '/icon.png'
  }
};
webPush.sendNotification({
  payload: new Buffer(JSON.stringify(payload)), …
});

Клиент

// Configure app to include module from @angular/service-worker
import {ServiceWorkerModule} from '@angular/service-worker';

// Inject an API for communicating with the Angular service worker
export class PushService {
  constructor(worker: NgServiceWorker) {

    worker.registerForPush().subscribe(endpoint => {
      // Send endpoint data to the server to complete registration
    };

    worker.push.subscribe(payload => {
      // Process payload
    });

  }
}

Статус

Спасибо!

@webmaxru

Максим Сальников

Made with Slides.com