An app in 3 days or: how I learned to stop worrying and love the Polymer toolbox

An app in 3 days or: how I learned to stop worrying and love the Polymer toolbox

Think of your favourite app. It's probably meowni.ca/emojillate (who can blame you), but if it isn't (and we need to talk) it probably has one, if not all, of these things: a database; a potential for disaster, with many users looking at and clicking on the same data; offline support, and a responsive layout. While preferably being faster than the average bear. Recreating this from scratch might sound like a terrifying experience, but I'm going to show you how the polymer toolbox and a few other already-built elements can help you go from zero to hero and build a PWA in no time.

Video: (Polymer Summit): https://www.youtube.com/watch?v=6t2JRKTCYbI&list=PLNYkxOF6rcICc687SxHQRuo9TVNOJelSZ&index=26

053e75a5b48b44d6dd0612795dfb326d?s=128

Monica Dinculescu

October 17, 2016
Tweet

Transcript

  1. 3 DAYS A N A P P I N (

    M O R E O R L E S S )
  2. @NOTWALDORF

  3. I’VE NEVER BUILT O K . R E A L

    TA L K AN APP
  4. IT’S GOT USERS THAT NEED AUTHENTICATION
 DATA IN IN THE

    RESPONSIVE UI OFFLINE ROUTES LANGUAGES
  5. IT’S GOT USERS THAT NEED AUTHENTICATION
 DATA IN IN THE

    RESPONSIVE UI OFFLINE ROUTES LANGUAGES
  6. IT’S GOT USERS THAT NEED AUTHENTICATION
 DATA IN THE RESPONSIVE

    UI OFFLINE ROUTES LANGUAGES
  7. IT’S GOT USERS THAT NEED AUTHENTICATION
 DATA IN THE OFFLINE

    RESPONSIVE UI ROUTES LANGUAGES
  8. IT’S GOT USERS THAT NEED AUTHENTICATION
 DATA IN THE OFFLINE

    RESPONSIVE UI ROUTES LANGUAGES
  9. IT’S GOT USERS THAT NEED AUTHENTICATION
 DATA IN THE OFFLINE

    RESPONSIVE UI ROUTES LANGUAGES
  10. IT’S GOT USERS THAT NEED AUTHENTICATION
 DATA IN THE OFFLINE

    RESPONSIVE UI ROUTES LANGUAGES
  11. SO LET’S BUILD THIS APP

  12. HTTPS://MOJIBRAG.FIREBASEAPP.COM

  13. DO LESS / BE LAZY B U T F O

    R L I K E , E V E RY T H I N G 1
  14. (´ ̙ҹ).牐ӈὑ ~/Code ❥ mkdir app && cd app (´

    ̙ҹ).牐ӈὑ ~/Code/app ❥ polymer init starter-kit
  15. None
  16. None
  17. localhost:8000/view2

  18. localhost:8000/view3

  19. None
  20. None
  21. AUTHENTICATION 2

  22. USE FIREBASE W H E N I N D O

    U B T
  23. <firebase-app api-key=“…” database-url=“https://your-app.firebaseio.com" auth-domain=“your-app.firebaseapp.com" storage-bucket=“your-app.appspot.com”> </firebase-app> <firebase-auth id=“auth" user="{{user}}" provider=“google”>

    </firebase-auth>
  24. <firebase-app api-key=“…” database-url=“https://your-app.firebaseio.com" auth-domain=“your-app.firebaseapp.com" storage-bucket=“your-app.appspot.com”> </firebase-app> <firebase-auth id=“auth" user="{{user}}" provider=“google”>

    </firebase-auth>
  25. login: function() { this.$.auth.signInWithPopup(); }, logout: function() { this.$.auth.signOut(); },

    attached: function() { firebase.auth().onAuthStateChanged(function(user){ // you have a user! } }
  26. login: function() { this.$.auth.signInWithPopup(); }, logout: function() { this.$.auth.signOut(); },

    attached: function() { firebase.auth().onAuthStateChanged(function(user){ // you have a user! } }
  27. login: function() { this.$.auth.signInWithPopup(); }, logout: function() { this.$.auth.signOut(); },

    attached: function() { this.$.auth.auth.onAuthStateChanged(function(user){ // you have a user! } }
  28. “THE CLOUD” 3

  29. JUST USE FIREBASE S E R I O U S

    LY.
  30. <firebase-query data="{{_fbPosts}}" path="/posts/{{ref}}"> </firebase-query> <app-indexeddb-mirror session="[[uid]]" key="/posts/{{ref}}" data="[[_fbPosts]]" persisted-data="{{posts}}"> </app-indexeddb-mirror>

  31. <FIREBASE-QUERY> <MY-APP>

  32. <FIREBASE-QUERY> <MY-APP> <MIRROR>

  33. <FIREBASE-QUERY> <MY-APP> <MIRROR>

  34. <firebase-query path=“/posts/{{channelName}}“ data="{{_liveData}}"> </firebase-query> <app-indexeddb-mirror session="[[uid]]" key="/posts/{{teamName}}" data="[[_fbPosts]]" persisted-data="{{posts}}"> </app-indexeddb-mirror>

  35. <firebase-query path=“/posts/{{channelName}}“ data="{{_liveData}}"> </firebase-query> <app-indexeddb-mirror session=“[[user.uid]]” key="/posts/{{channelName}}" data="[[_fbPosts]]" persisted-data="{{posts}}"> </app-indexeddb-mirror>

  36. <firebase-query path=“/posts/{{channelName}}“ data="{{_liveData}}"> </firebase-query> <app-indexeddb-mirror session=“[[user.uid]]" key="/posts/{{channelName}}" data="[[_liveData]]" persisted-data="{{posts}}"> </app-indexeddb-mirror>

  37. <firebase-query path=“/posts/{{channelName}}“ data="{{_liveData}}"> </firebase-query> <app-indexeddb-mirror session=“[[user.uid]]" key="/posts/{{channelName}}" data="[[_liveData]]" persisted-data="{{posts}}"> </app-indexeddb-mirror>

  38. None
  39. None
  40. None
  41. PUTTING IT TOGETHER V I E W S ’ N

    ’ D ATA 4
  42. FEATURES T H I N K I N G A

    B O U T
  43. T R A N S L AT E S T

    O W E B C O M P O N E N T S FEATURES T H I N K I N G A B O U T
  44. None
  45. None
  46. None
  47. None
  48. None
  49. <FIREBASE-AUTH>

  50. <FIREBASE-AUTH> <MY-APP>

  51. <FIREBASE-AUTH> <MY-APP> <NEW-POST>

  52. <FIREBASE-AUTH> <MY-APP> <NEW-POST> <IRON-LIST>

  53. <FIREBASE-AUTH> <MY-APP> <NEW-POST> <IRON-LIST>

  54. <MY-APP> <MAIN-SCREEN> <NEW-POST> <LOGIN-SCREEN> <IRON-LIST>

  55. PROPERTIES DOWN D ATA F L O W EVENTS UP

  56. <NEW-POST> <MAIN-SCREEN>

  57. None
  58. ACTIVE CHANNEL

  59. ACTIVE CHANNEL EVENT: POST !

  60. OFFLINE: FALSE EVENT: POST !

  61. OFFLINE: FALSE EVENT: POST ! THIS.$.POST.HIDDEN

  62. WORK OFFLINE? B U T D O E S I

    T 5
  63. SERVICE WORKER A L R E A DY D O

    N E
  64. CONDITIONAL UI Y O U M I G H T

    WA N T
  65. ready: function() { this.offline = navigator.onLine === false; window.addEventListener('online', function()

    { this.offline = false; }.bind(this)); window.addEventListener('offline', function() { this.offline = true; }.bind(this)); },
  66. ready: function() { this.offline = navigator.onLine === false; window.addEventListener('online', function()

    { this.offline = false; }.bind(this)); window.addEventListener('offline', function() { this.offline = true; }.bind(this)); },
  67. ready: function() { this.offline = navigator.onLine === false; window.addEventListener('online', function()

    { this.offline = false; }.bind(this)); window.addEventListener('offline', function() { this.offline = true; }.bind(this)); },
  68. ready: function() { this.offline = navigator.onLine === false; window.addEventListener('online', function()

    { this.offline = false; }.bind(this)); window.addEventListener('offline', function() { this.offline = true; }.bind(this)); },
  69. <paper-button hidden$=“[[offline]]> Sign in </paper-button>

  70. None
  71. None
  72. M AKE IT FAST 6

  73. D O L E S S . B E L

    A Z Y IRON-LIST
  74. IF YOU DON’T NEED IT DON’T IMPORT IT D O

    L E S S . B E L A Z Y
  75. importHref( fileName, successCallback, errorCallback)

  76. <link rel=“import” href=“signin-view.html”> <my-app> <signin-view></signin-view> <moji-feed></moji-feed> </my-app>

  77. <link rel=“import” href=“signin-view.html”> <my-app> <signin-view></signin-view> <moji-feed></moji-feed> </my-app> firebase.auth().onAuthStateChanged(function(user) { if

    (user) { this.importHref(‘humble-brag.html', function() { this.hideSigninUI(); this.showMainApp(); }, null, true); } }
  78. <link rel=“import” href=“signin-view.html”> <my-app> <signin-view></signin-view> <moji-feed></moji-feed> </my-app> firebase.auth().onAuthStateChanged(function(user) { if

    (user) { this.importHref(‘moji-feed.html’, function() { this.hideSigninUI(); this.showMainApp(); }, null, true); } }
  79. <link rel=“import” href=“signin-view.html”> <my-app> <signin-view></signin-view> <moji-feed></moji-feed> </my-app> firebase.auth().onAuthStateChanged(function(user) { if

    (user) { this.importHref(‘moji-feed.html’, function() { this.hideSigninUI(); this.showMainApp(); }, null, true); } }
  80. None
  81. None
  82. None
  83. None
  84. LIGHTHOUSE I S R E A A A A L

    LY AW E S O M E
  85. None
  86. HOW PAUL LEWIS S T O RY T I M

    E RUINED MY DAY
  87. None
  88. FAKE IT P R O T I P YOU MAKE

    IT W H I L E
  89. <my-app> <div class="splash"> <div class="header"> <div>Hi there!</div> <p class="loading">Loading..</p> </div>

    </div> </my-app>
  90. <my-app> <div class="splash"> <div class="header"> <div>Hi there!</div> <p class="loading">Loading..</p> </div>

    </div> </my-app>
  91. None
  92. BEFORE CHANGE WITH CHANGE

  93. C’EST FACILE! I N T E R N AT I

    O N A L I Z AT I O N 7
  94. <paper-button> Sign out </paper-button>

  95. <paper-button> [[localize(‘sign-out’)]] </paper-button>

  96. locales.json: { “en”: { “sign-out”: “Sign out” }, “fr”: {

    “sign-out”: “Déconnexion” }, “zh”: { “sign-out”: “蝐ڊ” } }
  97. locales.json: { “en”: { “sign-out”: “Sign out” }, “fr”: {

    “sign-out”: “Déconnexion” }, “zh”: { “sign-out”: “蝐ڊ” } } Polymer({ behaviors: [Polymer.AppLocalizeBehavior], ready: { this.language = ‘en’; this.loadResources(‘locales.json’); } });
  98. locales.json: { “en”: { “sign-out”: “Sign out” }, “fr”: {

    “sign-out”: “Déconnexion” }, “zh”: { “sign-out”: “蝐ڊ” } } Polymer({ behaviors: [Polymer.AppLocalizeBehavior], ready: { this.language = ‘en’; this.loadResources(‘locales.json’); } });
  99. locales.json: { “en”: { “sign-out”: “Sign out” }, “fr”: {

    “sign-out”: “Déconnexion” }, “zh”: { “sign-out”: “蝐ڊ” } } Polymer({ behaviors: [Polymer.AppLocalizeBehavior], ready: { this.language = ‘en’; this.loadResources(‘locales.json’); } });
  100. locales.json: { “en”: { “sign-out”: “Sign out” }, “fr”: {

    “sign-out”: “Déconnexion” }, “zh”: { “sign-out”: “蝐ڊ” } } Polymer({ behaviors: [Polymer.AppLocalizeBehavior], ready: { this.language = ‘en’; this.loadResources(‘locales.json’); } });
  101. None
  102. None
  103. None
  104. ALL TOGETHER NOW

  105. POLYMER CLI APP-LAYOUT SERVICE-WORKER POLYFIRE PROPERTIES ⇣ EVENTS ⇡ NAVIGATOR.ONLINE

    IRON-LIST LAZY LOADING APP-LOCALIZE-BEHAVIOUR
  106. POLYMER CLI APP-LAYOUT SERVICE-WORKER POLYFIRE PROPERTIES ⇣ EVENTS ⇡ NAVIGATOR.ONLINE

    IRON-LIST LAZY LOADING APP-LOCALIZE-BEHAVIOUR
  107. POLYMER CLI APP-LAYOUT SERVICE-WORKER POLYFIRE PROPERTIES ⇣ EVENTS ⇡ NAVIGATOR.ONLINE

    IRON-LIST LAZY LOADING APP-LOCALIZE-BEHAVIOUR
  108. POLYMER CLI APP-LAYOUT SERVICE-WORKER POLYFIRE PROPERTIES ⇣ EVENTS ⇡ NAVIGATOR.ONLINE

    IRON-LIST LAZY LOADING APP-LOCALIZE-BEHAVIOUR
  109. POLYMER CLI APP-LAYOUT SERVICE-WORKER POLYFIRE PROPERTIES ⇣ EVENTS ⇡ NAVIGATOR.ONLINE

    IRON-LIST LAZY LOADING APP-LOCALIZE-BEHAVIOUR
  110. POLYMER CLI APP-LAYOUT SERVICE-WORKER POLYFIRE PROPERTIES ⇣ EVENTS ⇡ NAVIGATOR.ONLINE

    IRON-LIST LAZY LOADING APP-LOCALIZE-BEHAVIOUR
  111. POLYMER CLI APP-LAYOUT SERVICE-WORKER POLYFIRE PROPERTIES ⇣ EVENTS ⇡ NAVIGATOR.ONLINE

    IRON-LIST LAZY LOADING APP-LOCALIZE-BEHAVIOUR
  112. POLYMER CLI APP-LAYOUT SERVICE-WORKER POLYFIRE PROPERTIES ⇣ EVENTS ⇡ NAVIGATOR.ONLINE

    IRON-LIST LAZY LOADING APP-LOCALIZE-BEHAVIOUR
  113. POLYMER CLI APP-LAYOUT SERVICE-WORKER POLYFIRE PROPERTIES ⇣ EVENTS ⇡ NAVIGATOR.ONLINE

    IRON-LIST LAZY LOADING APP-LOCALIZE-BEHAVIOUR
  114. @NOTWALDORF NOUN PROJECT ICONS: JAIME CARRION, RFLOR, STOCK IMAGE FOLIO,

    BERNAR NOVALYI h t t p s : // m o j i b r a g . f i r e b a s e a p p . c o m