Making Turbolinks work with Vue.js: Fast server-generated pages with reactive front-end components

Preview:

Citation preview

Turbolinks + Vue.jsPascal Laliberté

Starting small Depth

WHAT I VALUE

Turbolinks Vue.js

WHICH IS WHY I’M ATTRACTED TO THESE TWO TECHNOLOGIES

Turbolinks

A PAGE HAS A BODY

AND A HEAD

<head>

A PAGE HAS A BODY

<head>

Replaces the body

with the new content

<head>

WITH TURBOLINKS, CLICKING A LINK…

<head>

Replaces the body

with the new content

<head>

WITH TURBOLINKS, CLICKING A LINK…

Merges the head

<head>

Replaces the body

with the new content

<head>

WITH TURBOLINKS, CLICKING A LINK…

Merges the head

It keeps a Cache of snapshotsFor Back operations, etc

<head>

Replaces the body

with the new content

<head>

WITH TURBOLINKS, CLICKING A LINK…

Merges the head

It keeps a Cache of snapshotsFor Back operations, etc

WHICH MAKES PAGE TRANSITIONS(AND PAGE RESTORES)

SUPER QUICK

Vue.js

jQuery

In the category of Front-end UX

Dev Tools

jQuery Vanilla JS

In the category of Front-end UX

Dev Tools

Angular A full-fledge client-side

MVC

jQuery Vanilla JS

In the category of Front-end UX

Dev Tools

React

Angular A full-fledge client-side

MVC

jQuery Vanilla JS

In the category of Front-end UX

Dev Tools

React

Angular A full-fledge client-side

MVC

jQuery Vanilla JS

In the category of Front-end UX

Dev Tools

View renderers

React

Angular A full-fledge client-side

MVC

Vue

jQuery Vanilla JS

In the category of Front-end UX

Dev Tools

View renderers

AS AN EXAMPLE, LET’S TAKE A FORM FIELD

<div class=“purchase-form”> <input v-model=“quantity”>

AS AN EXAMPLE, LET’S TAKE A FORM FIELDAS PART OF A PURCHASE FORM…

new Vue({ el: “.purchase-form”, data: { }

quantity: null

})

<div class=“purchase-form”> <input v-model=“quantity”>

WHEN WE SETUP THE VUE INSTANCE, WE SET THE MODEL

new Vue({ el: “.purchase-form”, data: { }

quantity: 2

}

2

<div class=“purchase-form”> <input v-model=“quantity”>

})

AS THE FORM FIELD’S VALUE CHANGES, SO DOES THE VALUE IN THE MODEL

new Vue({ el: “.purchase-form”, data: { }

quantity: 23

}

23

<div class=“purchase-form”> <input v-model=“quantity”>

})

AS THE FORM FIELD’S VALUE CHANGES, SO DOES THE VALUE IN THE MODEL

AND VICE VERSA

, price: 25 }

new Vue({ el: “.purchase-form”, data: {

quantity: 23

})

23

WE CAN ADD OTHER PROPERTIES TO THE MODEL

, price: 25 }

new Vue({ el: “.purchase-form”, data: {

quantity: 23

})

23 , computed: { total () { return this.quantity * this.price } }

AND COMPUTED PROPERTIES TOO, WHICH UPDATE ON THE FLY

, price: 25 }

new Vue({ el: “.purchase-form”, data: {

quantity: 23

})

23

methods events components

, computed: { total () { return this.quantity * this.price } }

YOU CAN ALSO DEFINE

<map-popover :lat=“lat” :long=“long” :zoom=“zoom” ></map-popover>

DEFINING SUB-COMPONENTS MAKES VUE SCALABLE

React

Angular

Vue

jQuery Vanilla JS

SPA

Front-end UX

vue-routervue-resource SPA

YOU CAN GO ALL OUT AND BUILD A SPA…

Approachable

SmallFast

DelightfulScalable

BUT VUE’S BEST QUALITIES ARE THAT IT IS

Now available: Vue.js 2.0

IF YOU WANT

mostly server-generated content

in places: more front-end reactivity

Turbolinks + Vuejs

mostly jQuery / Vanilla js, Unobtrusive JS

<head>

Replaces the body

with the new content

<head>

WITH TURBOLINKS, CLICKING A LINK…

Merges the head

It keeps a Cache of snapshotsFor Back operations, etc

THE PROBLEM MERGING THEM TOGETHER IS THE BODY REPLACEMENT

CAUSES VUE INSTANCES TO LOSE REACTIVITY ON RESTORES

Turbolinks + Vuejs

new Vue({ el: “.purchase-form”, data: { }

quantity: 23

}

23

REACTIVITY = DOM EVENTS, OBSERVERS

DESTROYED WHEN CLONING THE BODY FOR THE RESTORE CACHE

FOR THE SOLUTION LET’S LOOK AT THE TIMELINE OF EVENTS

turbolinks:load

FOR THE SOLUTION LET’S LOOK AT THE TIMELINE OF EVENTS

turbolinks:load turbolinks:before-cache

FOR THE SOLUTION LET’S LOOK AT THE TIMELINE OF EVENTS

turbolinks:load turbolinks:before-cache

init destroy(Vue.js events)

FOR THE SOLUTION LET’S LOOK AT THE TIMELINE OF EVENTS

turbolinks:load turbolinks:before-cache

init destroy

re-inject in turbolinks snapshot the original DOM

element with end data (serialized) injected

(Vue.js events)

turbolinks:load turbolinks:before-cache

init destroy

save initial DOM element before it’s

walked

re-inject in turbolinks snapshot the original DOM

element with end data (serialized) injected

(Vue.js events)

turbolinks:load turbolinks:before-cache

init destroy

save initial DOM element before it’s

walked

re-inject in turbolinks snapshot the original DOM

element with end data (serialized) injected

detect serialized start data attached to initial DOM element

(Vue.js events)

turbolinks:load turbolinks:before-cache

init destroy

save initial DOM element before it’s

walked

re-inject in turbolinks snapshot the original DOM

element with end data (serialized) injected

detect serialized start data attached to initial DOM element

Vue.js Mixin

(Vue.js events)

turbolinks:load turbolinks:before-cache

init destroy

save initial DOM element before it’s

walked

re-inject in turbolinks snapshot the original DOM

element with end data (serialized) injected

detect serialized start data attached to initial DOM element

Vue.js Mixin …for each Vue component on the page

(Vue.js events)

@pascallalibertepascallaliberte.me

Recommended