taking your “web” app to places you never expected - ember fest 2014
DESCRIPTION
Presentation slides for Ember Fest 2014. Gives overview of steps needed to take an ember app offline.TRANSCRIPT
IAEA International Atomic Energy Agency
Taking Your “Web” App To places you never expected
Garth Williams @williamsgarth
IAEA
Background
• The IAEA inspects nuclear facilities all over the world
• The IAEA is currently modernising a number of legacy applications
• Our inspectors need to collect and store data where no network connection is guaranteed or even allowed
• Our team is writing the next version of software for facility inspections
IAEA
Let’s use WPF?
• A desktop app is the logical choice, right?
• Organisation standards are based on Microsoft technologies
• So Windows Presentation Foundation must be the right choice?
• (Oh, by the way, we may need to support tablets in 2015)
IAEA
Why HTML(5) is better
• HTML5 includes all the building blocks for offline apps
• Web apps don’t need to be installed
• HTML is portable
IAEA
Ember is a good fit
• Full stack framework
• Well suited to larger projects:
• Ember offers familiar conventions
• Ember encourages consistency and structure through the use of components, ember data, stateful routing, etc…
• Compiles down to one or two js distributables
IAEA
Taking ember offline (manifest.appcache)
• Use a manifest file • Lists all resources needed when offline
• CSS, Fonts, Images, JavaScript, HTML, etc… • Referenced in your html tag
<!DOCTYPE*html>*<html*manifest=“/manifest.appcache”>***…*</html>
IAEA
Taking ember offline (manifest.appcache)
CACHE*MANIFEST*#-Version-1.0.0-!
CACHE:*/js/app.js*/css/app.css*/images/logo.png*/fonts/fontawesomeJwebfont.woff*/404.html*!
NETWORK:*/api*!
FALLBACK:*/*/404.html
IAEA
What about my beautiful client side URLs?
• Single page apps used to use # for client side routing
• For an app is located at
• https://stunningapp.com/
• When the client navigates to entity 5 then we can have
• https://stunningapp.com/#/entity/5
IAEA
What about my beautiful client side URLs?
• But now I’m using push state, how can this dynamic url be available offline?
• https://stunningapp.com/entity/5/
IAEA
What about my beautiful client side URLs?
• Use the FALLBACK section of the manifest file
CACHE*MANIFEST*!
CACHE:*/*!
FALLBACK:*#-normal-fallback:-/-/404.html-#-Support-Push-State-/*/
• Any page not stored locally will return the cached root page
IAEA
Caching hell & double reloads
• First time a browser visits your app:
1. HTML is downloaded
2. Manifest is detected and downloaded
3. Resources listed in manifest are downloaded and stored
IAEA
Caching hell & double reloads
• On subsequent visits:
1. Cached version of all app files are used
• Fast load time!
• Potentially out of date!
2. Check if manifest file has changed
IAEA
Caching hell & double reloads
• Manifest is only checked on first load
• Long running apps won’t know there’s a new version
• Only the manifest file is checked
• Changes in other files will not be detected
• If there is a new version it will be silently downloaded
• User is not automatically informed
• Changes are not applied until reload
IAEA
Caching hell & double reloads
• Mitigation:
1. Auto-generate the manifest
• Put a content hash of cached files in a comment
CACHE*MANIFEST*!
CACHE:*#-app.js-hash:-1921ec2e922f7f11c73c870e908b1c50-/js/app.js
IAEA
Caching hell & double reloads
• Mitigation:
2. Notify the user
applicationCache.addEventListener('updateready',*function*()*{***//*let*the*user*know*that*they*need*to*reload*});
IAEA
Caching hell & double reloads
• During development you may spend a lot of time reloading the app
• 1 reload is not enough
• 1st reload will download the changes
• 2nd will put them into effect
• 2 reloads is tedious
• If you reload too quickly it might not work
IAEA
Caching hell & double reloads
• Mitigation:
3. Periodically check for a new version
setInterval(function*()*{***applicationCache.update();*},*config.newVersionCheckInterval);
• If the manifest has changed then it will be downloaded in the background
IAEA
Toggle online only features
• Some features require a server
• We can check network connection status
• Also need to check if the server can be reached
IAEA
Toggle online only features
• Detecting network availability
var*updateNetworkStatus*=*function*()*{***if*(applicationController.get('isNetworkConnected')*!==*navigator.onLine)*{*****applicationController.set('isNetworkConnected',*navigator.onLine);*****//*if*we*just*moved*from*offline*to*online*check*for*app*update*****if*(navigator.onLine)*{*******applicationCache.update();*****}***}*};*window.addEventListener('online',*updateNetworkStatus);*window.addEventListener('offline',*updateNetworkStatus);
IAEA
Toggle online only features
• Detecting service availability
var*updateServiceStatus*=*function*(status)*{***applicationController.set('isServiceAvailable',*status.type*!==*'error');*};*!
applicationCache.addEventListener('error',*updateServiceStatus);*applicationCache.addEventListener('noupdate',*updateServiceStatus);*applicationCache.addEventListener('updateready',*updateServiceStatus);
IAEA
Toggle online only features
• Putting network and service status together
isOnline:*function*()*{***return*this.get('isNetworkConnected')*&&*this.get('isServiceAvailable');*}.property('isNetworkConnected',*'isServiceAvailable')
IAEA
Data Access
• Ember data offers useful layered abstractions
• An adaptor lets you communicate with your data source
• A serialiser lets you transform from the format of your source to the format expected by ember
• The store provides an agnostic API for application to load and save models
IAEA
Data Access
• Server side we’re using ASP.NET MVC Web API
• Requires a custom Adaptor and Serialiser
• Adding offline support at the adaptor level is easy
• Application code does not need know
IAEA
Data Access
• Oversimplified data adaptor
var*CacheAdapter*=*DS.RESTAdapter.extend({***ajax:*function*(url,*type,*options)*{*****if*(App.get('isOnline'))*{*******options.success*=*function*(responseData)*{*********cacheResponse(url,*type,*options,*responseData);*******};*******return*this._super(url,*type,*options);*****}*else*{*******return*cachedResponse(url,*type,*options);*****}***}*});
IAEA
Data Access
• Not always desirable to cache every response
• Pass intentions to store methods
IAEA
Data Accessstore.findById('person',*id,*{*cacheResponse:*true*});
var*CacheStore*=*DS.Store.extend({***findById:*function*(type,*id,*options)*{*****return*this.findQuery(type,*{*id:*id*},*options).then(function*(result)*{*******return*result.get('firstObject');*****});***},*!
**findQuery:*function*(type,*data,*options)*{*****data*=*data*||*{};*****data.__options*=*options*||*{};*****return*this._super(type,*data);***}*});
IAEA
Hold on… “new” requirement
• We forgot to mention…
• Sometimes it’s not possible to bring the laptop/tablet back to headquarters
• How can you deploy and update a web app to a computer that never connects to the server?
IAEA
Hold on… “new” requirement
• At a small number of locations, the only hardware allowed back to HQ is a hardware encrypted USB stick…
• Put the browser on the USB stick
• Configure the browser to store all data cache data on the USB
• Now when at HQ the browser will update the app and store data needed ready for offline use
IAEA
Recap
• Ember offers the structure necessary for large (and small) projects
• Build tools like ember-cli give you manageable output for manifest.appcache and can easily be extended to automate its content
• Build automation is essential from the start when using appcache
• Ember data has the abstractions necessary to provide good offline support which can be transparent to your app
• There’s not much that you can’t do with Ember.js “web” application
IAEA
Questions?