Building Progressive Web Apps · •Web apps that behavelike native apps-Prompt add to home...
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/