Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Vue.js @ Airbnb - Until we all belong

Vue.js @ Airbnb - Until we all belong

Case study focused on untilweallbelong.com and the use of Vue.js.
---
Melbourne Vue.js Meetup: http://www.meetup.com/vuejs-melbourne/
Google Slides: http://bit.ly/2q7LhYI
Presentation by: http://sylvainsimao.fr

maoosi

May 10, 2017
Tweet

More Decks by maoosi

Other Decks in Programming

Transcript

  1. Airbnb. Until we all belong. How we’ve built a global

    campaign with Vue.js. @VueJsAustralia
  2. Workflow :: Dev Webpack + Babel + Eslint Vue 2.2.6

    + VueX + Vue-Router + Vue-Touch Axios + Chroma.js + Spritz.js
  3. Advantages of the Serverless Architecture - Quick to setup -

    Cost effective - Scalable (without the hassle) - Modular (micro services)
  4. >

  5. 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
  6. Challenges - Cross-browser images drawing - Lock / unlock hand

    selection - Preloading 36 images - Responsive display and behaviors - Accessible for blind users - Editable grid / hands / colors >
  7. Output = Handyx.js - Dependency-free ES6 library - HTML5 canvas

    - WebP support (up to 50% reduction) - Screen-readers compatible - Async preloading
  8. Vue + ES6 lib <template> <div ref="handSelector"></div> </template> <script> 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() } } </script>
  9. Consider writing Vanilla / ES6 libs - Because it is

    testable - Because it is reusable - Because it is maintainable
  10. 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 } } ] })
  11. 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 } } ] })
  12. 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 } } ] })
  13. Vue-Router + VueX VueX store Vue Router > Set next

    bg color > Set preload list Preloader component Background component Global state Router Components
  14. <template> <div id="app" ref="viewport" class="view"> <keep-alive> <router-view class="router-view"></router-view> </keep-alive> </div>

    </template> #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 } } >
  15. #2 Remove events listeners export default { activated () {

    window.addEventListener('resize', this.resizeHandler) }, deactivated () { window.removeEventListener('resize', this.resizeHandler) }, methods: { resizeHandler (event) { /* code here */ } } }
  16. #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() ?
  17. 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() >
  18. #3 Prefer requestAnimationFrame new Animate(animFunc, 1) // Execute animFunc every

    milliseconds setInterval / setTimeout requestAnimationFrame Pause inactive tabs
  19. #4 Empower webpack - CommonsChunkPlugin :: Bundle common modules -

    UglifyJsPlugin :: Compress JavaScript - Url-loader :: Base64 encode assets - Svg-sprite-loader & svgo-loader :: SVG Sprites - CompressionWebpackPlugin :: Gzipping