Slide 1

Slide 1 text

Airbnb. Until we all belong. How we’ve built a global campaign with Vue.js. @VueJsAustralia

Slide 2

Slide 2 text

@maoosi @_maoosi Sylvain Simao Technical Lead @ Clemenger BBDO Melbourne

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

untilweallbelong.com #

Slide 5

Slide 5 text

After 48h 236,000 pageviews 23,000 rings ordered 5,000 pledges shared

Slide 6

Slide 6 text

Workflow :: Dev Webpack + Babel + Eslint Vue 2.2.6 + VueX + Vue-Router + Vue-Touch Axios + Chroma.js + Spritz.js

Slide 7

Slide 7 text

Workflow :: Test Jira + BugHerd Parallels for Mac + BrowserStack

Slide 8

Slide 8 text

Workflow :: Deploy Bitbucket + Buddy.works + AWS

Slide 9

Slide 9 text

Workflow :: Deliver Sentry.io + Contentful + Analytics

Slide 10

Slide 10 text

Serverless Architecture using AWS

Slide 11

Slide 11 text

Advantages of the Serverless Architecture - ………………… - ……………… - …………………………... - …………… ?

Slide 12

Slide 12 text

Advantages of the Serverless Architecture - Quick to setup - Cost effective - Scalable (without the hassle) - Modular (micro services)

Slide 13

Slide 13 text

AWS Architecture >

Slide 14

Slide 14 text

AWS Architecture ?

Slide 15

Slide 15 text

Blue / Green deployment... >

Slide 16

Slide 16 text

…& Nginx proxy Static HTML Vue.js SPA is user? is robot?

Slide 17

Slide 17 text

Micro services

Slide 18

Slide 18 text

>

Slide 19

Slide 19 text

Micro services

Slide 20

Slide 20 text

VueX + Axios App VueX store Axios HTTP AWS Vue framework Vanilla JS >

Slide 21

Slide 21 text

import api from './api.js' export default new Vuex.Store({ state: { isInStock: true }, actions: { checkStock ({ commit, state }) { api.checkStock().then((stock) => { commit('SET_STOCK', stock) } } }, mutations: { SET_STOCK: (state, stock) => { state.isInStock = stock }) } }) import axios from 'axios' export function checkStock () { return new Promise((resolve, reject) => { axios.get('/aws-service') .then((response) { return resolve(response) }) }) } VueX + Axios Vue framework Vanilla JS

Slide 22

Slide 22 text

Hand + Y axis + X axis = Handyx.js

Slide 23

Slide 23 text

No content

Slide 24

Slide 24 text

Hand Selector Combinations 36 different hands + 36 different colors

Slide 25

Slide 25 text

Hand Selector Grid

Slide 26

Slide 26 text

Challenges - Cross-browser images drawing - Lock / unlock hand selection - Preloading 36 images - Responsive display and behaviors - Accessible for blind users - Editable grid / hands / colors >

Slide 27

Slide 27 text

Output = Handyx.js - Dependency-free ES6 library - HTML5 canvas - WebP support (up to 50% reduction) - Screen-readers compatible - Async preloading

Slide 28

Slide 28 text

Vue + ES6 lib
import Handyx from 'handyx.js' export default { data () { return { handSelector: false } }, activated () { this.handSelector = new Handyx(this.$refs.handSelector, { hands: require('hands.json') }) }, deactivated () { this.handSelector.destroy() } }

Slide 29

Slide 29 text

Consider writing Vanilla / ES6 libs - Because it is testable - Because it is reusable - Because it is maintainable

Slide 30

Slide 30 text

Dynatiles.js

Slide 31

Slide 31 text

Pledgr.js

Slide 32

Slide 32 text

Spritz.js https://github.com/maoosi/spritz.js

Slide 33

Slide 33 text

Vue-Router, the Swiss army tool

Slide 34

Slide 34 text

Vue-Router + Meta const router = new Router({ routes: [ { path: '/order-your-ring', component: Order, name: 'order', meta: { restrictFrom: ['ring'], preload: ['dom', 'ring-image', 'stock'], color: colors.$black } } ] })

Slide 35

Slide 35 text

Vue-Router + Preloading const router = new Router({ routes: [ { path: '/order-your-ring', component: Order, name: 'order', meta: { restrictFrom: ['ring'], preload: ['dom', 'ring-image', 'stock'], color: colors.$black } } ] })

Slide 36

Slide 36 text

Vue-Router + Guards const router = new Router({ routes: [ { path: '/order-your-ring', component: Order, name: 'order', meta: { restrictFrom: ['ring'], preload: ['dom', 'ring-image', 'stock'], color: colors.$black } } ] })

Slide 37

Slide 37 text

Vue-Router + VueX VueX store Vue Router > Set next bg color > Set preload list Preloader component Background component Global state Router Components

Slide 38

Slide 38 text

Code and memory best practices

Slide 39

Slide 39 text

#1 Use keep-alive export default { mounted () { // First time a component is loaded }, activated () { // Each time a component is activated }, deactivated () { // Each time a component is deactivated } } >

Slide 40

Slide 40 text

#1 Use keep-alive

Slide 41

Slide 41 text

#2 Remove events listeners export default { activated () { window.addEventListener('resize', this.resizeHandler) }, deactivated () { window.removeEventListener('resize', this.resizeHandler) }, methods: { resizeHandler (event) { /* code here */ } } }

Slide 42

Slide 42 text

#3 Avoid setInterval / setTimeout class Animate { construct (callback, interval) { callback.call() this.animation = setInterval(callback, interval) } stop () { clearInterval(this.animation) } } const animation = new Animate(animFunc, 1000) animation.stop() ?

Slide 43

Slide 43 text

class Animate { construct (callback, interval) { this.callback = callback this.interval = interval this.isPlaying = true this.animation = requestAnimationFrame(this.step.bind(this)) } step (timestamp) { this.timer = this.timer || timestamp if (timestamp - this.timer >= this.interval) { this.callback.call() this.timer = false } if (this.isPlaying) this.animation = requestAnimationFrame(this.step.bind(this)) } stop () { cancelAnimationFrame(this.animation) this.isPlaying = false } } const animation = new Animate(animFunc, 1000) animation.stop() >

Slide 44

Slide 44 text

#3 Prefer requestAnimationFrame new Animate(animFunc, 1) // Execute animFunc every milliseconds setInterval / setTimeout requestAnimationFrame Pause inactive tabs

Slide 45

Slide 45 text

#4 Empower webpack - CommonsChunkPlugin :: Bundle common modules - UglifyJsPlugin :: Compress JavaScript - Url-loader :: Base64 encode assets - Svg-sprite-loader & svgo-loader :: SVG Sprites - CompressionWebpackPlugin :: Gzipping

Slide 46

Slide 46 text

No content

Slide 47

Slide 47 text

Question to win an acceptance ring ?

Slide 48

Slide 48 text

Thanks! @VueJsAustralia Want to give a talk? Please contact us on @VueJsAustralia