Light & Lazy Asynchronous patterns for Vue Apps

Toronto 16th Nov 2018

GitHub icon
Twitter icon

Eduardo

San Martin Morote

Vue core team

Remote Freelance Developer

ย 

GitHub icon

Prototyping is fun

ReBuild plugins in Vue

Code Splitting

You should split your code

It all starts with webpack

Dynamic Import

import('a_package').then(module => module.default)
import('./utils.js').then(module => module.log)
const aPackage = () => import('a_package')
const utils = () => import('./utils.js')

Configure Webpack

SplitChunksPlugin

๐Ÿ“šDocs

Prefetch

import(/* webpackPrefetch: true */ 'LoginModal')
<link rel="prefetch" href="login-modal-chunk.js" />

Preload

import(/* webpackPreload: true */ 'ChartingLibrary')
<link rel="preload" href="chunk.js" />

Lazy-Loading components

โœจAnywhere

import Calendar from '@/components/Calendar.vue'
const Calendar = () => import('@/components/Calendar.vue')

Per-Page

// router.js
const Home = () => import('@/views/Home')
const User = () => import('@/views/User')

const routes = [
  { path: '/', component: Home },
  { path: '/users/:id', component: User },
]

in-componenT

// App.vue
const Search = () => import('@/components/Search')

export default {
  components: { Search }
}

Chunks

Search.vue

The real deal

โœ‚๏ธ vendors

Lazy load Recipee ๐Ÿฅ˜

  • Local imports
  • Lazy load view components

PROFIT ๐Ÿ”ฅ

Dynamic Components

in-template

<component :is="dynamicComponent"/>
// inside of a component method

// local or global component
this.dynamicComponent = 'UserCard'

// component descriptor
// import UserCard from './UserCard'
this.dynamicComponent = UserCard

In-Render functions

export default {
  render (h) {
    return h(this.dynamicComponent)
  },
  methods: {
    changeDisplayedComponent () {
      this.dynamicComponent = 'UserCard'
      // or
      this.dynamicComponent = UserCard
    }
  }
}

โœจAnywhere

import Calendar from '@/components/Calendar.vue'
const Calendar = () => import('@/components/Calendar.vue')

Dynamic Lazy components

<component :is="dynamicComponent"/>
// inside of a component method
this.dynamicComponent = () => import('./UserCard')
render(h) { return h(this.dynamicComponnet) }

Dynamic Imports with Expressions

import(`@/components/async/${name}.vue`)

let webpack creates chunks ๐Ÿ‘Œ

Careful...

import(myComponentPath) // ๐Ÿ˜ฑ โ˜ ๏ธ

your app

Hint Webpack the best you can

import(myComponentPath) // ๐Ÿ˜ฑ โ˜ ๏ธ
import(`@/components/Lazy${name}.vue`) // ๐Ÿ™Œ
import(`@/components/async/${name}.vue`) // ๐Ÿ’ฏ

Lazy loading Dynamic Components

USage

<ExamplePreview name="counter"/>

dynamic components + computed = ๐Ÿ‘Œ

computed: {
  demoComponent() {
    // make demoComponent depend on name
    const name = this.name
    return () =>
      import(`@docs/examples/${name}/index.js`)
  }
}
<component :is="demoComponent"/>

Analyzing your app

Monster

when your app is unmaintainable but you still care

vue ui

Lazy Load

  • Local imports
  • Always lazy load views
  • Lazy load big local components

Dynamic import expressions

  • As precise as possible
  • Prefetch flag (can wait)
  • Preload (needed now)

Handling Errors

โŒ Error

// in a component method
this.error = null
return import('./Component.vue').catch(err => {
  this.error = err
})
<p class="danger" v-if="error">{{ error }}</p>

โณ LOading

this.error = null
this.pending = true
return import('./Component.vue').then(module => {
  this.pending = false
  return module
}).catch(err => this.error = err)
<p class="danger" v-if="error">{{ error }}</p>
<p class="info" v-else-if="pending">Loading...</p>

when you realize you have been writing the same thing over and over

Async component factory

const AsyncComponent = () => ({
  component: import('./MyComponent.vue'),
  loading: LoadingComponent,
  error: ErrorComponent,
  delay: 200,
  timeout: 3000
})

๐Ÿ’ Vue-promised

<Promised :promise="componentPromise">
  <p slot="pending">Loading component</p>
  <component
    slot-scope="module"
    :is="module.default"
  />
  <p slot="rejected" slot-scope="error">
    {{ error.message}}
  </p>
</Promised>

๐Ÿ‘‰ Github repo

Thanks! ๐Ÿ––

GitHub icon

Light, lazy asynchronous patterns for Vue Apps

By Eduardo San Martin Morote

Light, lazy asynchronous patterns for Vue Apps

We keep shipping more and more features in our Web applications, and as a result, we ship heavier apps that take more time to load. So we use bundlers like webpack to split our application code into multiple bundles and load them asynchronously. As a result, we end up having asynchronous code pretty much everywhere in our apps. This means that we need to handle unexpected errors that were otherwise impossible, like network ones, handle loading state and make sure the application is able to recover from these errors. During this talk, we will take a look at different patterns about handling asynchronous request correctly in Vue applications in order to make our Apps feel light, fast and reliable everywhere.

  • 3,022