vue3 + vite implements asynchronous component and route lazy loading

In Vue2, asynchronous component processing can be easily implemented using import. However, in Vue 3.x, the use of asynchronous components is completely different from Vue 2.x.

  • There are three main changes:
  1. Change of asynchronous component declaration method: Vue 3.x adds an auxiliary function defineAsyncComponent to display and declare asynchronous components
  2. The component option in the asynchronous component advanced declaration method is renamed loader
  3. The component loading function bound by loader no longer receives the resolve and reject parameters, and must return a Promise

Auxiliary function defineAsyncComponent

In Vue 2.x, to declare an asynchronous component, you only need to:

const asyncPage = () => import('./views/home.vue')

However, when it comes to Vue 3.x, the above usage does not apply.

  • example:
<template>
	<div>
		<h1>Async Components</h1>
		<p>Asynchronous component testing</p>
    <child></child>
	</div>
</template>

<script>
const child = () => import('@/components/async-component-child.vue')

export default {
  name: 'async-components',
  components:{
    'child': child
  }
};
</script>

Asynchronously loaded components will no longer be displayed on the page, and the console will report an error.

In Vue 3.x, the import of asynchronous components needs to be explicitly declared using the auxiliary function defineAsyncComponent. As follows:

<template>
	<div>
		<h1>Async Components</h1>
		<p>Asynchronous component testing</p>
    <child></child>
	</div>
</template>

<script>
import { defineAsyncComponent } from 'vue'
const child = defineAsyncComponent(() => import('@/components/async-component-child.vue'))

export default {
  name: 'async-components',
  components:{
    'child': child
  }
};
</script>
  • Vue 3.x introduces the defineAsyncComponent helper function for the following reasons:
    Translated as follows:

      Now, in Vue 3 Because function components are defined as pure functions, asynchronous component definitions need to be wrapped in a new defineAsyncComponent helper To explicitly define.
    

The component option is renamed loader

Asynchronous components in Vue 2.x are declared in a more advanced manner.

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

Therefore, the following asynchronous component declaration

const asyncPage = () => import('./views/home.vue')

Equivalent to

const asyncPageWithOptions  = {
  component: () => import('./views/home.vue')
}

Similarly, asynchronous components can be declared in Vue 3.x. However, the component needs to be changed to loader.

const asyncPageWithOptions  = defineAsyncComponent({
  loader: () => import('./views/home.vue'),
  delay: 200,
  timeout: 3000,
  error: ErrorComponent,
  loading: LoadingComponent
})

The component loading function no longer receives the resolve and reject parameters, and must return a Promise

In addition, the asynchronous component loading function of Vue 3.x will no longer receive resolve and reject, and must always return Promise

// 2.x version
const oldAsyncComponent = (resolve, reject) => {
  /* ... */
}

// 3.x version
const asyncComponent = defineAsyncComponent(
  () =>
    new Promise((resolve, reject) => {
      /* ... */
    })
)

That is, the factory function defines the way to receive the resolve callback. Asynchronous components cannot be used in Vue 3.x:

export default {
  components: {
    asyncPage: resolve => require(['@/components/list.vue'], resolve)
  },
}

Distinction between lazy loading and routing

However, if the project is built with vite tool and import ed for lazy loading in local development, it can be loaded normally, but a warning will be reported; An error will be reported when packaging to the production environment, and the page will not be displayed normally.

Implementation method of route lazy loading:

  1. defineAsyncComponent method
// router/index.js
import { defineAsyncComponent } from 'vue'
const _import = (path) => defineAsyncComponent(() => import(`../views/${path}.vue`));

const routes = [
	{
		path: '/async-component',
		name: 'asyncComponent',
		component: _import('home'),
	}
];
  1. import.meta.glob method
// 1. The above method is equivalent to loading all. vue files in the views directory at one time and returning an object
const modules = import.meta.glob('../views/*/*.vue');
const modules ={
    "../views/about/index.vue": () => import("./src/views/about/index.vue")
}

// 2. Direct reference during dynamic import
const router = createRouter({
  history: createWebHistory(),
  routes: [
    // ...
    {
      path: 'xxxx',
      name: 'xxxxx',
      // The original method is feasible in development, but not in production
      // component: () => import(`../views${menu.file}`),
      // Change to the following
      component: modules[`../views${filename}`]
    }
    // ...          
  ],
})

Writing of asynchronous components

<template>
	<div>
		<h1>Async Components</h1>
		<p>Asynchronous component testing</p>
    <child></child>
	</div>
</template>

<script>
import { defineAsyncComponent } from 'vue'
const child = defineAsyncComponent(() => import('@/components/async-component-child.vue'))

export default {
  name: 'async-components',
  components:{
    'child': child
  }
};
</script>

Summary: in short, the asynchronous loading written in the routing configuration file is the use of lazy routing loading, and the asynchronous loading written in the component is the use of asynchronous components.

Welcome to: Personal blog address

Tags: Javascript Front-end Vue.js

Posted on Wed, 13 Oct 2021 17:20:54 -0400 by mrmom