An app in 3 days [with an intro to PWA/Polymer]

An app in 3 days [with an intro to PWA/Polymer]

Think of your favorite 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.

053e75a5b48b44d6dd0612795dfb326d?s=128

Monica Dinculescu

October 22, 2016
Tweet

Transcript

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

    M O R E O R L E S S )
  2. ӞԫӣࢥԲمӠكԜ܈ݣ傀 ፓ෭์กॠӧय़ੜஞமӾ࿜ᅉ ࢿᔭ๙຋༏ਦՈفڊݗ樌槹樄 ๜᥺ਞঀካኦ୙ᛔ૩አࡋ揌ಋ ᜎሴᡩێઊྋྊ㾴

  3. @NOTWALDORF

  4. @NOTWALDORF NEELIX

  5. @NOTWALDORF EMOJINEER

  6. @NOTWALDORF

  7. None
  8. PROGRESSIVE WEB APPS C O O L “ N E

    W ” T H I N G !
  9. PROGRESSIVE WEB APPS N AT I V E L O

    O K & F E E L
  10. PROGRESSIVE WEB APPS F R I C T I O

    N L E S S D O W N L O A D S
  11. PROGRESSIVE WEB APPS O F F L I N E

    ! S E RV I C E W O R K E R !
  12. PROGRESSIVE WEB APPS S O U N D S U

    P E R H A R D ?
  13. I’VE NEVER BUILT O K . R E A L

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

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

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

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

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

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

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

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

  22. HTTPS://MOJIBRAG.FIREBASEAPP.COM

  23. POLYMER 101 W H AT I S I T ?

    0
  24. HTML

  25. HTML E L E M E N T S A

    R E M A D E BY T H E B R O W S E R
  26. <html> <body> <input> <input type=“checkbox”> <video src=“video.mp3” controls></video> </body> </html>

  27. HTML E L E M E N T S A

    R E E N C A P S U L AT E D
  28. None
  29. None
  30. HTML E L E M E N T S H

    AV E A N A P I
  31. HTML R E A L LY V E R B

    O S E A N D H A R D T O S H A R E : (
  32. WEB COMPONENTS E L E M E N T S

    A R E M A D E BY Y O U !
  33. <html> <head> <link rel=“stylesheet” href=“fancy-button.css”> </head> <body> <div class=“fancy button

    jquery-ui”>Meow</div> </body> </html>
  34. <html> <head> <link rel=“import” href=“number-input.html”> </head> <body> <fancy-button>Meow</fancy-button> </body> </html>

  35. <html> <head> <link rel=“import” href=“number-input.html”> </head> <body> <fancy-button>Meow</fancy-button> </body> </html>

  36. <html> <head> <link rel=“import” href=“fancy-button.html”> </head> <body> <fancy-button>Meow</fancy-button> </body> </html>

  37. <html> <head> <link rel=“import” href=“fancy-button.html”> </head> <body> <fancy-button>Meow</fancy-button> </body> </html>

  38. None
  39. <html> <head> <link rel=“import” href=“google-map.html”> </head> <body> <google-map latitude=“37.7” longitude=“-122.3”>

    </google-map> </body> </html>
  40. JQUERY E A S I E R J AVA S

    C R I P T
  41. NPM MODULES E A S I E R J AVA

    S C R I P T
  42. POLYMER E A S I E R W E B

    C O M P O N E N T S
  43. POLYMER “ T H E R E ’ S A

    N E L E M E N T F O R T H AT ”
  44. DO LESS / BE LAZY B U T F O

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

    ̙ҹ).̶ӈὑ ~/Code/app ❥ polymer init starter-kit
  46. None
  47. None
  48. localhost:8000/view2

  49. localhost:8000/view3

  50. None
  51. None
  52. AUTHENTICATION 2

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

    U B T
  54. None
  55. None
  56. <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>
  57. <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>
  58. login: function() { this.$.auth.signInWithPopup(); }, logout: function() { this.$.auth.signOut(); },

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

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

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

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

    LY.
  63. <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>

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

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

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

  67. <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>

  68. <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>

  69. <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>

  70. <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>

  71. None
  72. None
  73. None
  74. PUTTING IT TOGETHER V I E W S ’ N

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

    B O U T
  76. 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
  77. None
  78. None
  79. None
  80. None
  81. None
  82. <FIREBASE-AUTH>

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

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

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

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

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

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

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

  90. None
  91. ACTIVE CHANNEL

  92. ACTIVE CHANNEL EVENT: POST !

  93. OFFLINE: FALSE EVENT: POST !

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

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

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

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

    WA N T
  98. 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)); },
  99. 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)); },
  100. 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)); },
  101. 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)); },
  102. <paper-button hidden$=“[[offline]]> Sign in </paper-button>

  103. None
  104. None
  105. M AKE IT FAST 6

  106. D O L E S S . B E L

    A Z Y RENDER LESS DOM
  107. D O L E S S . B E L

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

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

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

  111. <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); } }
  112. <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(); }); } }
  113. <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(); }); } }
  114. None
  115. None
  116. None
  117. None
  118. LIGHTHOUSE I S R E A A A A L

    LY AW E S O M E
  119. None
  120. WEBPAGETEST.ORG

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

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

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

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

    “sign-out”: “Déconnexion” }, “tw”: { “sign-out”: “ጭڊ” } }
  125. locales.json: { “en”: { “sign-out”: “Sign out” }, “fr”: {

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

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

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

    “sign-out”: “Déconnexion” }, “tw”: { “sign-out”: “ጭڊ” } } Polymer({ behaviors: [Polymer.AppLocalizeBehavior], ready: { this.language = ‘en’; this.loadResources(‘locales.json’); } });
  129. None
  130. None
  131. None
  132. ALL TOGETHER NOW

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

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

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

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

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

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

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

    FAST ELEMENTS LAZY LOADING APP-LOCALIZE-BEHAVIOUR
  140. POLYMER CLI APP-LAYOUT SERVICE-WORKER POLYFIRE PROPERTIES ⇣ EVENTS ⇡ NAVIGATOR.ONLINE

    FAST ELEMENTS LAZY LOADING APP-LOCALIZE-BEHAVIOUR
  141. POLYMER CLI APP-LAYOUT SERVICE-WORKER POLYFIRE PROPERTIES ⇣ EVENTS ⇡ NAVIGATOR.ONLINE

    FAST ELEMENTS LAZY LOADING APP-LOCALIZE-BEHAVIOUR
  142. @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