Slide 1

Slide 1 text

Building Web Apps Simon Gauvin, CTO www.simongauvin.com [email protected] +

Slide 2

Slide 2 text

We are Looking for developers... We work on contracts building large scale web apps... Startups need to build apps quickly, and scale from the start Looking for contractors to help front-end (Polymer) and back-end (Firebase) Do contacts? Email me: [email protected]

Slide 3

Slide 3 text

Going to the Web Browser API and DOM structures full of legacy code Many parts missing: 1. No general loading Mechanism for code 2. Managing CSS-JS-HTML together 3. HTML limitations, everything is a
, slow parsing 4. CSS namespace leaking into other rules, kill entire app layout 5. No OOP or MVC patterns for creating apps at scale

Slide 4

Slide 4 text

Scale: Build a mobile programming language in web browser

Slide 5

Slide 5 text

Scaling brings problems... Managing Code/Implementation/Deployment/Versioning Managing OS/Services/Libs/VMs Managing Networking/Security Managing Performance Managing Memory/Disk/Network Managing “Change” breaks all the above!

Slide 6

Slide 6 text

A scalable dev platform provides solutions. Managing Code/Implementation/Deployment/Versioning Managing OS/Services/Libs/VMs Managing Networking/Security Managing Performance Managing Memory/Disk/Network Improve focus on code, release faster, release better code.

Slide 7

Slide 7 text

+ Front end Back end https://www.polymer-project.org https://firebase.google.com

Slide 8

Slide 8 text

Polymer Designed on top of Webcomponents.org specification for custom HTML Client library for building Fixes the CSS/JS/HTML mess with integrated model Fixes CSS leakage with Shadow DOM Fixes code loading with HTML imports Fixes OOP/MVC with Components and Dataflow 3 releases 1.0 (2014), 2.0 (2017), 3.0 (2018) https://www.polymer-project.org/

Slide 9

Slide 9 text

No content

Slide 10

Slide 10 text

No content

Slide 11

Slide 11 text

Polymer 1.0 Registration Lifecycle Declared Properties Local DOM Events Data binding Behaviours (mixins) Utility Functions

Slide 12

Slide 12 text

Polymer 2.0 /* CSS rules for your element */
{{greeting}}
// Define the element's API using an ES2015 class class XCustom extends Polymer.Element { static get is() { return 'x-custom'; } // Declare properties for the element's public API static get properties() { return { greeting: { type: String, value: "Hello!" } } } // Add methods to the element's public API greetMe() { console.log(this.greeting); } } // Register the x-custom element with the browser customElements.define(XCustom.is, XCustom); Custom Elements ES5 Classes Shadow DOM Events Dataflow System Utility Functions HTML Imports Bower package manager

Slide 13

Slide 13 text

Polymer 3.0 import {PolymerElement, html} from '@polymer/polymer/polymer-element.js'; // Define the element's API using an ES2015 class class XCustom extends PolymerElement { // Define optional shadow DOM template static get template() { return html` /* CSS rules for your element */
[[greeting]]
`; } // Declare properties for the element's public API static get properties() { return { greeting: { type: String } } } constructor() { super(); this.greeting = 'Hello!'; } // Add methods to the element's public API greetMe() { console.log(this.greeting); } } // Register the x-custom element with the browser customElements.define('x-custom', XCustom); Custom Elements ES5 Classes Shadow DOM Events Dataflow System React-style UX template ES6 Modules - import Npm package manager

Slide 14

Slide 14 text

Custom Element You can define your own HTML tags class NewComponent extends Polymer.Element { static get is() { return 'new-component'; } } window.customElements.define(NewComponent.is, NewComponent); // Then use it…

Slide 15

Slide 15 text

Custom Element You can define your own HTML tags Use these new tags in other HTML Use the new tags in new tags Elements can extend other elements to use inheritance. Elements can be mixed with other elements (mixins). :host { display: block } /* add your custom CSS here... */ class NewComponent extends Polymer.Element { static get is() { return 'new-component'; } static get properties() { return { // Add new properties here... name: { type: String, value: "" } }; } // Use: initializing state set up event listeners, create shadow dom. constructor() { super(); } // Use for one-time configuration of your component after local DOM is initialized. ready() { super.ready(); } // add your own methods here... } window.customElements.define(NewComponent.is, NewComponent);

Slide 16

Slide 16 text

Add Properties Properties exist with the instance of component and are encapsulated. Can be set to any JS type. Can have default values. HTML to camelCase conversion. class NewComponent extends Polymer.Element { static get is() { return 'new-component'; } static get properties() { return { // Add new properties here... userName: { type: String, value: "" }, manager: { type: Boolean }; } // Use the component and pass in values to properties

Slide 17

Slide 17 text

Add Objects/Arrays Objects and Arrays can be set to defaults with use of function. Properties accessed in methods using this.propertyName notation. class NewComponent extends Polymer.Element { static get is() { return 'new-component'; } static get properties() { return { // Add new properties here... user: { type: Object, value: function() { return {}; } }, list: { type: Array, value: function() { return []; } }; } // Use the component and pass in values to properties

Slide 18

Slide 18 text

Observed Properties Properties can trigger code when value is changed. class NewComponent extends Polymer.Element { static get is() { return 'new-component'; } static get properties() { return { userName: { type: String, value: "", observer: ‘_nameChanged’ }, }; } _nameChanged(value) { // the new value of name console.log(“my name changed: “, value); }

Slide 19

Slide 19 text

Computed Properties Properties can be computed based on some code, and depend on other properties. class NewComponent extends Polymer.Element { static get is() { return 'new-component'; } static get properties() { return { count: { type: Number, computed: ‘_computeCount(total)’ }, total: { type: number }; } _computeCount(value) { return value * 2; }

Slide 20

Slide 20 text

Data Flow Data can flow into, or out of a component. Values of properties are read in the DOM with double square brackets [[x]] for 1-way data flow. Values of properties are read in the DOM with double curly brackets {{x}} for 2-way data flow. 1. Refer to external JS object 2. Refer to local
3. Data binding to set value
[[name.first]] [[name.last]]
class NameCard extends Polymer.Element { static get is() { return "name-card"; } constructor() { super(); this.name = {first: 'Kai', last: 'Li'}; } } customElements.define(NameCard.is, NameCard);

Slide 21

Slide 21 text

Add methods Components, because they are a class, can have its own methods. Methods can be called from outside the component using the id and $ operator. The component must be in the calling components . Methods can have any number of parameters. class NewComponent extends Polymer.Element { static get is() { return 'new-component'; } static get properties() { return { user: { type: Object, value: function() { return {}; } }, list: { type: Array, value: function() { return []; } }; // Add new methods here... getUserName() { return this.user.name; } } // call method on a component using id var name = this.$.comp.getUserName();

Slide 22

Slide 22 text

Handle Events Components can handle events on their own sub-components and link these to their methods. Kick Me class XCustom extends Polymer.Element { static get is() {return 'x-custom'} handleClick() { console.log('Ow!'); } } customElements.define(XCustom.is, XCustom);

Slide 23

Slide 23 text

Add Components Components can be added to the template section of a component.
Kick Me
class XCustom extends Polymer.Element { static get is() {return 'x-custom'} } customElements.define(XCustom.is, XCustom);

Slide 24

Slide 24 text

Import Components Any HTML component, Polymer component, or custom component can be added. For custom and polymer components you need to import the html file that defines it.
Kick Me
class XCustom extends Polymer.Element { static get is() {return 'x-custom'} } customElements.define(XCustom.is, XCustom);

Slide 25

Slide 25 text

Add CSS Components can be styled using local CSS. :host { padding: 4px; background-color: gray; } .container { color: var(--my-toolbar-title-color); }
Kick Me
class XCustom extends Polymer.Element { static get is() {return 'x-custom'} } customElements.define(XCustom.is, XCustom);

Slide 26

Slide 26 text

CSS Components The name of a component can be used to customize its look. You can also use custom CSS properties to change the inside of the component. paper-button { color: var(--title-color); --paper-button-style: { Font-size: 12px; } }
Kick Me
class XCustom extends Polymer.Element { static get is() {return 'x-custom'} } customElements.define(XCustom.is, XCustom);

Slide 27

Slide 27 text

Dispatch Events Components can also communicate up the DOM by using Event system in browser. Kick Me class XCustom extends Polymer.Element { static get is() {return 'x-custom'} handleClick() { this.dispatchEvent( new CustomEvent('sign-out', {detail:{count:2}}, { bubbles: true, composed: true })); } } customElements.define(XCustom.is, XCustom);

Slide 28

Slide 28 text

Listen for Events Components can also listen to Events dispatched by other components. class XCustom extends Polymer.Element { static get is() {return 'x-custom'} constructor() { super(); this.addEventListener('sign-out', function(event) { console.log(“event received”); }); } } customElements.define(XCustom.is, XCustom);

Slide 29

Slide 29 text

Building an App... Create Firebase account Create firebase project, cloud, then shell Create polymer project Connect polymer to firebase through polymerfire $firebase serve $firebase deploy https://firebase.google.com

Slide 30

Slide 30 text

No content

Slide 31

Slide 31 text

No content

Slide 32

Slide 32 text

Building an App... 3rd Party API

Slide 33

Slide 33 text

Polymer Tools $nvm install node $npm install -g polymer-cli $polymer init $bower install --save PolymerElements/ #^ $polymer serve $polymer build

Slide 34

Slide 34 text

App Structure index.html

Slide 35

Slide 35 text

Add App Component Create a new component to interface between Polymer and index file. venn-chat-app.html class VennChatApp extends Polymer.Element { static get is() {return 'venn-chat-app'} } customElements.define(VennChatApp.is, VennChatApp); index.html

Slide 36

Slide 36 text

No content

Slide 37

Slide 37 text

No content

Slide 38

Slide 38 text

Authenticate Transfer the credentials into your app using polymerfire firebase-app component. class VennChatApp extends Polymer.Element { static get is() {return 'x-custom'} } customElements.define(VennChatApp.is, VennChatApp); bower install --save FirebaseExtended/polymerfire

Slide 39

Slide 39 text

Create Login Form Login will use the to validate your Google account. Add login() and logout() methods to call auth object API. “dom-if” template used to show/hide components based on existence of user.

Venn Chat App

Login with Google class MyLogin extends Polymer.Element { static get is() {return 'my-login'} login() { return this.$.auth.signInWithPopup(); } logout() { return this.$.auth.signOut(); } } customElements.define(MyLogin.is, MyLogin); bower install --save PolymerElements/paper-button#^2

Slide 40

Slide 40 text

Add sign-out listener handles signing out, so we send an event from to trigger API call. ... class MyLogin extends Polymer.Element { static get is() {return 'my-login'} ready() { super.ready(); this.addEventListener('sign-out', function () { this.logout(); }.bind(this)); } } customElements.define(MyLogin.is, MyLogin); ... class MyApp extends Polymer.Element { static get is() {return 'my-app'} _logout() { this.dispatchEvent( new CustomEvent('sign-out', { bubbles: true, composed: true })); } } window.customElements.define(MyApp.is, MyApp);

Slide 41

Slide 41 text

No content

Slide 42

Slide 42 text

Firebase RTDB Firebase is a realtime NoSQL DB with listeners. Can be accessed directly from app, no need to have App-tier. Can be accessed from Functions too. Updates all client data when changes are made, no polling. Modify for and . :host { display: block; } class MyView1 extends Polymer.Element { static get is() { return 'my-view1'; } static get properties() { return { user: Object, posts: { type: Object } }; } } window.customElements.define(MyView1.is, MyView1);

Slide 43

Slide 43 text

Firebase RTDB Add sub-components for list and input post. Add CSS to style the components. :host { display: block; } // Add CSS here
[[post.name]] [[post.text]]
Post
... bower install --save PolymerElements/paper-input#^2

Slide 44

Slide 44 text

Firebase RTDB Add post() method to write to database. Used id of to get reference to collection and adds a new child with push() method to auto-generate key. Use the Key to set() the value of the document to the object we create from user and text. :host { display: block; } class MyView1 extends Polymer.Element { static get is() { return 'my-view1'; } static get properties() { return { user: Object, posts: { type: Object } }; } _post() { var msg = this.$.input.value; if (msg) { var key = this.$.query.ref.push().key; this.$.query.ref.child(key).set({ photo: this.user.photoURL, name: this.user.displayName, text: msg, timestamp: -Date.now() }); this.$.input.value = ""; } } } window.customElements.define(MyView1.is, MyView1);

Slide 45

Slide 45 text

Deploy App to Hosting... $firestore deploy Use your phone to get venchat.firebaseapp.com For production you would perform: $polymer build to bundle and obfuscate JS code Create all the security rules on database, firestore, storage Create your own ico/images for mobile app homepage Add analytics to your app to watch use/crashes

Slide 46

Slide 46 text

Firebase Functions https://github.com/firebase/functions-samples

Slide 47

Slide 47 text

Firebase Functions

Slide 48

Slide 48 text

Firebase Functions // Listens for new messages added to /posts/:pushId/text and creates an // uppercase version of the message to /posts/:pushId/text exports.makeUppercase = functions.database.ref('/messages/{pushId}/text') .onCreate((snapshot, context) => { // Grab the current value of what was written to the Realtime Database. const text = snapshot.val(); const uppercase = text.toUpperCase(); return snapshot.ref.parent.child('text').set(uppercase); });

Slide 49

Slide 49 text

Firebase Functions - CRUD const express = require('express'); const cors = require('cors'); const app = express(); // Automatically allow cross-origin requests app.use(cors({ origin: true })); // Add middleware to authenticate requests app.use(myMiddleware); // build multiple CRUD interfaces: app.get('/:id', (req, res) => res.send(Widgets.getById(req.params.id))); app.post('/', (req, res) => res.send(Widgets.create())); app.put('/:id', (req, res) => res.send(Widgets.update(req.params.id, req.body))); app.delete('/:id', (req, res) => res.send(Widgets.delete(req.params.id))); app.get('/', (req, res) => res.send(Widgets.list())); // Expose Express API as a single Cloud Function: exports.widgets = functions.https.onRequest(app);

Slide 50

Slide 50 text

Firebase RTDB Make changes after deployment that does not interrupt your users. $firebase deploy :host { display: block; } class MyView1 extends Polymer.Element { static get is() { return 'my-view1'; } static get properties() { return { user: Object, posts: { type: Object } }; } ready() { super.ready(); setTimeout(() => this._scrollToBottom(), 500); } // at end of post()... setTimeout(() => this._scrollToBottom(), 500); _scrollToBottom(){ this.$.messages.scrollTop = this.$.messages.scrollHeight; } } window.customElements.define(MyView1.is, MyView1);

Slide 51

Slide 51 text

Other Topics… Firebase Storage (for media) SMS Messaging/Email Push Notification Firestore Beta (nosql that scales) NoSQL Normalization & Performance patterns Integration with Google Cloud Platform...

Slide 52

Slide 52 text

Thank You Many thanks to all developers who came to talk! Special thanks to MUG and Doreen for opportunity. Extra special thanks to Marc Albert for pizza and support! Simon Gauvin: [email protected]