#infoshare / Blake Newman / @blakenewman
Text
slides.com/blakenewman
Background and features of Vue.js
Reactivity Systems
Templates, are they bad?
Service Workers in Realtime
Plus much more from alternative avenues
<body>
<div id="app">
{{ message }}
</div>
<script src="https://unpkg.com/vue"></script>
<script>
new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
}
});
</script>
</body>
CSS Modules
<template>
<p class="red">
{{ message }}
</p>
</template>
<script>
module.exports = {
data: function () {
return {
message: 'Hello world!'
};
}
};
</script>
<style>
.red {
colour: red;
}
</style>
<template lang="pug">
p.red {{ message }}
</template>
<script lang="ts">
import Vue from 'vue'
import Component from 'vue-class-component'
@Component
export default class MyComponent extends Vue {
message: string = 'Hello world!'
}
</script>
<style lang="styl">
.red
colour red
</style>
<template>
<p class="red"></p>
</template>
<style scoped>
.red {
colour: red;
}
</style>
<p class="red" data-v-f3f3eg9></p>
<style>
.red[data-v-f3f3eg9] {
color: red;
}
</style>
<template>
<p :class="$style.red"></p>
</template>
<style module>
.red {
colour: red;
}
</style>
<div class="_1VyoJ-uZOjlOxP7jWUy19_0"></div>
<style>
._1VyoJ-uZOjlOxP7jWUy19_0 {
color: red;
}
</style>
Explicit pull signal from developer
Manual optimisation hints from developer
Simplified with immutable data
Memory overhead, proportional to dataset size
Improved by skipping observation of immutable data
Improved by reducing computation granularity
Angular 2 onPush with Observables
React + MobX
Vue 2 + Immutable data
<template>
<p>{{ message }}</p>
</template>
function render() {
var _vm = this
var _h = _vm.$createElement
var _c = _vm._self._c || _h
return _c('p', [
_vm._v(_vm._s(_vm.message))
])
}
function render() {
return (
<div>{ this.message }</div>
)
}
{
class: {
foo: true,
bar: false
},
style: {
color: 'red',
fontSize: '14px'
},
attrs: {
id: 'foo'
},
props: {
myProp: 'bar'
},
on: {
click: this.clickHandler
},
// ...
}
function render() {
return React.createElement(
"div",
null,
this.items.map(function (item) {
return React.createElement("p", null, item);
}),
React.createElement("p", null, this.message)
)
}
function render() {
return (
<div>
{ this.items.map(item => <p>{ item }</p>) }
<p>{ this.message }</p>
</div>
)
}
[node, [node, ...], node]
<template>
<div>
<p v-for="item in items">{{ item }}</p>
<p>{{ message }}</p>
</div>
</template>
function render() {
var _vm = this
var _h = _vm.$createElement
var _c = _vm._self._c || _h
return _c('div', [_vm._l((_vm.items), function(item) {
return _c('p', [_vm._v(_vm._s(item))])
}), _c('p', [_vm._v(_vm._s(_vm.message))])], 2)
}
<template>
<div>
<span>Static content</span>
<span>More static content</span>
</div>
</template>
function render() {
return (
<div>
<h2>Static content</h2>
<p>More static content</p>
</div>
)
}
function render() {
var _vm = this
var _h = _vm.$createElement
var _c = _vm._self._c || _h
return _vm._m(0)
}
function render() {
return React.createElement(
"div",
null,
React.createElement("span", null, "Static content"),
React.createElement("span", null, "More static content")
)
}
Render (JSX)
Templates
Declarative with JSX
Presentational
Logical
HTML + small DSL
Child normalization
Declarative
Power of JavaScript
No DSL?
Static node hoisting
Progressive code updates
Closer to compiler
Server
Service Worker
Cache
Client
WebSocket
Server
Client
Server
Service Worker
Client
WebSocket
Server
Service Worker
Cache
Client
WebSocket
Server
Service Worker
Cache
Client
WebSocket
self.addEventListener('fetch', event => {
const { request } = event;
const url = new URL(request.url);
// Ignore not GET request or is is different origin.
if (request.method !== 'GET' || url.origin !== self.location.origin) return;
event.respondWith(async () => {
try {
// If not online and cache available then use cache
if (!navigator.onLine) {
const cache = await caches.match(request);
if (cache) return cache;
}
// Request message
const response = await self.fetch(request);
// If not 'ok' then do not cache
if (!response.ok) return response;
// Add response to cache
const openCache = await caches.open(CACHE_NAME);
await openCache.put(request, response.clone());
return response;
} catch (error) {
// User is landing on a page.
return request.mode === 'navigate' ? caches.match('./') : '';
}
});
});
Server
Service Worker
Cache
Client
WebSocket
const socketIO = require('socket.io');
const express = require('express');
const app = express();
const io = socketIO(app);
app.post('/api/user', () => {
io.emit('USER_COUNT_UPDATED');
});
app.get('/api/user/count', (req, res) => {
res.json({ count: 99283374 }).end();
});
Server
Service Worker
Cache
Client
WebSocket
import io from 'socket.io-client';
export default store => {
const socket = io.connect();
socket.on('connect', () => store.dispatch('app/connect'));
socket.on('disconnect', () => store.dispatch('app/disconnect'));
socket.on('USER_COUNT_UPDATED', () => store.dispatch('user/getCount'));
};
// Load Socket layer asynchronously in separate chunk
import('./socket').then(socket => socket.default(store));
// Setup service worker
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('service-worker.js', { scope: './' });
}
Server
Service Worker
Cache
Client
WebSocket