1 of 43

State of the Vuenion

VueConf US, Mar.2019

Tampa, Florida

2 of 43

Usage statistics

from February 2019

  • ~700k weekly active devtool users
  • ~800k weekly downloads on NPM
  • ~461M hits/month on jsDelivr CDN

3 of 43

Usage statistics

from this morning

  • ~780k weekly active devtool users
  • ~1M weekly downloads on NPM
  • ~500M hits/month on jsDelivr CDN

4 of 43

10% month-over-month growth

5 of 43

Now the 2nd most-starred

project on GitHub! 🤩

6 of 43

Case studies from Behance, GitLab, Clemenger BBDO, Livestorm, IBM, Fathom & Laravel

7 of 43

New Releases

8 of 43

  • New slot syntax / performance improvements
  • Improved async error handling
  • Improved compiler error messages
  • Built-in data prefetch support during server-side rendering

9 of 43

Vue Devtools 5.0

Release notes

  • Routing tab
  • Performance tab
  • Settings tab
  • Editable Vuex state
  • Initial NativeScript support
  • ...and more!
  • Shoutout to @Akryum

10 of 43

Vetur 0.16

  • Template intellisense support!
    • Expression autocomplete inside interpolations & directives
    • Child component tags & props
  • Shoutout to @octref

11 of 43

12 of 43

Vue CLI 4.0 Roadmap

vuejs/vue-cli#3649

  • Jest v24
  • Workbox v4
  • core-js v3
  • Nightwatch v1

13 of 43

3.0 RFCs

14 of 43

New Slot Syntax

RFC-0001

  • More succinct usage for default scoped slots

<foo v-slot="{ msg }">

{{ msg }}

</foo>

15 of 43

New Slot Syntax

RFC-0001

<foo>

<template v-slot:one>

foo

</template>

<template v-slot:scoped="{ msg }">

{{ msg }}

</template>

</foo>

  • More consistent & explicit when using named slots

16 of 43

New Slot Syntax

  • Easier to associate slot scope declarations with the component providing the scope

17 of 43

Slots Unification:

All slots are implicitly scoped

vuejs/rfcs#20

18 of 43

Normal vs. Scoped Slots

createElement(

Foo,

// evaluated in parent render function

// this.msg dependency registered by parent

[createElement('div', this.msg)]

)

19 of 43

Normal vs. Scoped Slots

createElement(

Foo,

// lazy evaluated in child render function

// this.msg dependency registered by child

() => [createElement('div', this.msg)]

)

20 of 43

Class API

vuejs/rfcs#17

21 of 43

export default class App extends Vue {

count = 0

created() {

console.log(this.count)

}

get plusOne() {

return this.count + 1

}

increment() {

this.count++

}

}

Class API

22 of 43

  • Primary goal: to provide a built-in & more efficient replacement for vue-class-component
  • Works with both native ES2015 and TypeScript
  • Object API still supported

Class API

23 of 43

Advanced Reactivity API

vuejs/rfcs#22

24 of 43

import { state, computed, watch } from '@vue/observer'

const obj = state({ count: 1 })

const plusOne = computed(() => state.count + 1)

watch(plusOne, value => {

console.log(`count + 1 is: ${value}`)

})

Advanced Reactivity API

25 of 43

  • Create and observe reactive state outside of components�
  • Connect state into components by returning them in data()

Advanced Reactivity API

26 of 43

Dynamic Lifecycle Hook Injection

vuejs/rfcs#23

27 of 43

import { onMounted, onUnmounted } from 'vue'

export default {

beforeCreate() {

onMounted(() => {

console.log('mounted')

})

onUnmounted(() => {

console.log('unmounted')

})

}

}

Dynamic Lifecycle Injection

28 of 43

Advanced Reactivity API

+

Dynamic Lifecycle Injection

=

New Composition Pattern

29 of 43

Case Study: Mouse Position

30 of 43

Mixins

const mousePositionMixin = {

data() {

return {

x: 0,

y: 0

}

},

mounted() {

window.addEventListener('mousemove', this.update)

},

destroyed() {

window.removeEventListener('mousemove', this.update)

},

methods: {

update(e) {

this.x = e.pageX

this.y = e.pageY

}

}

}

31 of 43

  • When overused:
    • ❌ Namespace clash (all options)
    • ❌ Unclear property source

Mixins

32 of 43

Higher-order Components

const Demo = withMousePosition({

props: ['x', 'y'],

template: `<div>Mouse position: x {{ x }} / y {{ y }}</div>`

})

33 of 43

  • When overused:
    • ❌ Namespace clash (props only)
    • ❌ Unclear props source
    • ❌ Extra component instances

Higher-order Components

34 of 43

Renderless Components

<mouse v-slot="{ x, y }">

Mouse position: x {{ x }} / y {{ y }}

</mouse>

35 of 43

  • ✅ No namespace clashing
  • ✅ Clear sources of variables
  • ❌ Extra component instances

Renderless Components

36 of 43

new Vue({

template: `

<div>

Mouse position: x {{ mouse.x }} / y {{ mouse.y }}

</div>

`,

data() {

return {

mouse: useMousePosition(this)

}

}

})

Hooks?

37 of 43

function useMousePosition(vm) {

const mousePosition = Vue.observable({

x: 0,

y: 0

})

const update = e => {

mousePosition.x = e.pageX

mousePosition.y = e.pageY

}

vm.$on('hook:mounted', () => {

window.addEventListener('mousemove', update)

})

vm.$on('hook:destroyed', () => {

window.removeEventListener('mousemove', update)

})

return mousePosition

}

Hooks?

38 of 43

  • ✅ No namespace clashing
  • ✅ Clear sources of variables
  • ✅ No extra component instances

39 of 43

function useMousePosition() {

const x = value(0)

const y = value(0)

const update = e => {

x.value = e.pageX

y.value = e.pageY

}

onMounted(() => {

window.addEventListener('mousemove', update)

})

onUnmounted(() => {

window.removeEventListener('mousemove', update)

})

return { x, y }

}

With new API

40 of 43

new Vue({

template: `

<div>

Mouse position: x {{ x }} / y {{ y }}

</div>

`,

data() {

const { x, y } = useMousePosition()

return {

x,

y,

// ... other data

}

}

})

With new API

41 of 43

  • React-hooks like composability
  • Recommended over mixins
  • Only called once
    • Closer to standard JS intuition
    • No call-order constraint
    • No stale closures

42 of 43

More 3.0 RFCs to be published soon…

  • Global API re-design
  • Render function API change
  • Functional and Async components API change
  • Optional Props Declaration
  • Attribute fallthrough behavior change

43 of 43

Thank you!