Building Progressive Web Apps · •Web apps that behavelike native apps-Prompt add to home...

Post on 04-Oct-2020

1 views 0 download

Transcript of Building Progressive Web Apps · •Web apps that behavelike native apps-Prompt add to home...

Building Progressive Web AppsBuilding Progressive Web AppsArcGIS API for JavaScriptArcGIS API for JavaScript

Andy Gup, @agup, ESRI Redlands

Rene Rubalcava, @odoenet , ESRI Redlands

Thomas Other, ESRI R&D Center Zürich

TopicsTopicsProgressive Web Apps

RequirementsTipsPWA w/ JSAPI

Mobile WebImproving Performance Best practices in 3D

Progressive Web Apps Agenda

• What is a progressive web app (PWA)

• Requirements

• Building progressive web apps with the ArcGIS API for JavaScript

• Mobile Web Performance

• 3D Performance

What is a PWA?

• Web apps that behave like native apps

- Prompt add to home screen- Run in a sandbox environment

• Smooth transitions

• Responsive

• Fast loading

• Native look and feel

PWA Requirements

PRPL

• Push critical resources

• Render initial page or route

• Pre-cache remaining assets

• Lazy load parts of your application

JS CSSCritical Resources

JS CSSJSPre-cache

JS JSLazy load

Render!

Service Workers

• Not a web worker

• Control and cache network requests

• Series of APIs

- Notification – send notification to desktop- Push – pub/sub capabilities- Background Sync – useful for offline to ensure data is sent- Channel Messaging – communication with other works, ie: iframes

App Shell

• Useful for fast loading

• Minimal HTML, JS, CSS required to display a UI

• Can allow an app to look ready while resources load

• When to use?

- When UI doesn’t really change- But content does

• Separate content from navigation

manifest.json

• How your PWA will behave when installed as a home screen app

• Defines

- App Name- Icons- Colors (themes)- Display information

PWA Tips

Native Image Lazy Loading

• Built into modern browsers

https://web.dev/native-lazy-loading/

IntersectionObserver

• JavaScript can do anything

https://developers.google.com/web/updates/2016/04/intersectionobserver

WebP Images

• Load webp if you can, have jpg/png fallbacks

https://developers.google.com/web/updates/2016/04/intersectionobserver

PWA w/ JSAPI

Considerations when building mapping apps

• Provide app shell when possible

• Delay the loading of the map if you can

• JavaScript API is powerful, lots of capabilities

- What layers are in webmap?- What portals are used in webmaps? (Identity)- What are the capabilities of the services?- Hosted or enterprise?- Does data need to be reprojected?

Considerations when building mapping apps

• Provide app shell when possible

• Delay the loading of the map if you can

• JavaScript API is powerful, lots of capabilities

- What layers are in webmap?- What portals are used in webmaps? (Identity)- What are the capabilities of the services?- Hosted or enterprise?- Does data need to be reprojected?

Patterns

• Determine your app/map pattern

• Mapless apps

- Map not the initial focus- Spatial tasks run in the background- Opportunity to delay map loading- Opportunity to use routing, lazy loading

Demo Application

• Nearby JavaScript

• Uses mapless app pattern

Andy

Mobile Web - Improving Performance

Improving Mobile Performance - Responsiveness

Focus on:• Initial load performance• User workflow performance

Improving Mobile Performance – Recommendations!

Understand your visitors

Lazy Load (where possible)

Use fewer map layers

Visible vs remove()

Simplify!

Understand your users – analyze web server logs

Ask your IT team to help analyze your site visitors

Very useful stats can be calculated for example:• Browser + version• Device types (e.g. Android vs iOS)• Percentage of desktop vs mobile users• Which pages get visited most• And more!

Understand your users – analyze web server logs

220.101.115.150 - - [11/Feb/2020:00:17:32 -0500] "GET /your_web_directory/ HTTP/1.1" 200 8434 "https://www.google.com/" "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.87 Safari/537.36"

User agent string demo

Improving Mobile Performance - Responsiveness

Responsive also means User Interface performanceUsers will notice any operation longer than . . .

16msOr < 60 fps

Improving Mobile Performance – Lazy load modules

Reduce size for initial app loadDefer loading modules if they aren’t needed immediatelyNot everything needs to be async. Can overload CPU

Demo

Improving Mobile Performance – Lazy load layers

Defer loading layers if they aren’t needed immediately

Improving Mobile Performance – Use as few layer as possible

Demo 1Demo 2

Fewer layers means:

Faster loadingLess memory usageLess GPU/CPU parsing and rendering

Improving Mobile Performance – Visible vs remove()

Layer.visible - Temporary• Layer not visible means features are still loaded in memory and can

be made visible without re-querying the server.

Map.remove(layer) - Longer duration• Layer completely removed from the map.

Demo 1

Improving Mobile Performance – Simplify the data

Demo 1

More features == slower load performance

What can I do?• Set a minimum scale (max zoom out level)• Generalize your data - reduce the number of vertices• Enable web server compression (gzip, brotli)• Use AGOL hosted services – optimized for high performance

Improving Mobile Performance – test, test, test on devices

You can debug both Android Chrome and iOS Safari via USB

Test apps over cellular internet and…turn off your wifi ;-)

Use a variety of actual mobile devices: phones, tablets

Test on newer (faster) and older (slower) devices

Best practices in 3D Best practices in 3D SceneLayersTiledLayersSymbologyElevation AlignmentQuality Pro�leEnvironmentPerformance InfoDemo

Scene LayersScene LayersTip: Publish SceneLayers with ArcGIS Pro 2.3 – oriented

bounding boxes instead of spherical extents

const sceneLayer = new SceneLayer({ url: "https://tilesqa.arcgis.com/.../SceneServer" }); const view = new SceneView({ container: "viewDiv", map: { basemap: "topo", ground: "world-elevation", layers: [ sceneLayer ] } }); function play() { ...visualize i3s nodes... }

Tiled LayersTiled LayersTip: Do you really need to see the sky?

const view = new SceneView({ container: "viewDiv", map: { basemap: "topo" } }); view.watch("camera", (camera) => { logMessage(`camera.tilt: ${Math.floor(camera.tilt)}`); }); function play () { view.constraints.tilt.max = 20; ...visualize tile borders... }

> camera.tilt: 3

Symbol ComplexitySymbol ComplexityTip: Reduce symbol complexity (How many vertices?)

Icons Primitives Models

<10 ~100 >1'000

complexity ⟶

> FPS: 46, Memory: ? KB

Elevation AlignementElevation AlignementTip: absolute-height is faster than relative-to-ground

absolute-height relative-to-ground relative-to-scene

Quality Pro�leQuality Pro�leTip: A low quality pro�le reduces memory consumption

Affects: Map resolution, SceneLayer detail, Anti-aliasing

const profiles = ["low", "medium", "high"]; let profileIdx = 0; const view = new SceneView({ container: "viewDiv", map: { basemap: "satellite", ground: "world-elevation", layers: [new SceneLayer({ url: "https://tilesqa.arcgis.com/.../SceneServer" })] }, qualityProfile: "low" }); function play() { profileIdx = (profileIdx + 1) % profiles.length; view.qualityProfile = profiles[profileIdx]; }

> qualityProfile: high

Environment SettingsEnvironment SettingsTip: Shadows and Ambient-Occlusion are expensive

const profiles = ["low", "high"]; let profileIdx = 0; const view = new SceneView({ container: "viewDiv", map: { basemap: "satellite", ground: "world-elevation", layers: [new SceneLayer({ url: "https://tilesqa.arcgis.com/.../SceneServer" })] } }); function play() { profileIdx = (profileIdx + 1) % profiles.length; const highQuality = profiles[profileIdx] === "high"; const atmosphere = view.environment.atmosphere; const lighting = view.environment.lighting; lighting.directShadowsEnabled = highQuality; lighting.ambientOcclusion = highQuality; atmosphere.quality = profiles[profileIdx]; }

> profile: high, FPS: 45

Performance InfoPerformance InfoSceneView exposes memory and load/quality information

SceneView.performanceInfo = { // The total memory available in bytes. totalMemory: number; // The memory that is in use in bytes. usedMemory: number; // Quality level as a percentage. quality: number; // Average number of frame tasks waiting. load: number; // The memory currently in use by elevation layers and tiled layers, in bytes. terrainMemory: number; // The memory currently in use by adding edges to 3D objects in scene layers or extruded polygons, in bytes. edgesMemory: number; // An array containing information about non-tiled layers. layerPerformanceInfos: { layer: Layer; memory: number; ... }[]; }

Demo TimeDemo Timehttps://thother.github.io/devsummit-california-

2020/demos/resource-info/