Vue Lazy Loading

簡介

  • 在 SPA 模式中,隨著專案規模變大,JS 檔案的加載時間也隨之變長
  • 使用懶加載可以分割程式碼,需要時再載入,減少首次進入頁面加載時間
  • 依靠於打包工具(Vite, Webpack) 代碼分割(Code Splitting)的功能
  • 目的都是為了優化使用者體驗

路由懶加載

  • 將每個路由頁面(Vue 檔案)分割成不同的塊(chunks),在訪問相應路由時才加載

不使用懶加載

  • 所有頁面會在應用載入時一次性加載
import Home from './components/Home.vue'
import About from './components/About.vue'
import Contact from './components/Contact.vue'

const routes = [
  { path: '/', component: Home },
  { path: '/about', component: About },
  { path: '/contact', component: Contact }
]

使用懶加載

  • 當進入該路由時,再加載對應檔案
const Home = () => import('./components/Home.vue')
const About = () => import('./components/About.vue')
const Contact = () => import('./components/Contact.vue')

const routes = [
  { path: '/', component: Home },
  { path: '/about', component: About },
  { path: '/contact', component: Contact }
]

元件懶加載

  • 當有用到該元件的需求時,再進行載入,減少首次進入頁面加載時間

不使用懶加載

  • 會在首次進入頁面時,一次性全部加載元件

創建MyComponent.vue元件

// MyComponent.vue
<template>
  <div>
    <!-- MyComponent的內容 -->
  </div>
</template>

<script>
export default {
  // MyComponent的邏輯
}
</script>

在父元件中引入

// App.vue
<template>
  <div>
    <MyComponent />
  </div>
</template>

<script>
import MyComponent from './components/MyComponent.vue'

export default {
  components: {
    MyComponent
  }
}
</script>

使用懶加載

  • 在父元件中,使用動態引入,在使用到該元件時才會被加載
<template>
  <div>
    <MyComponent v-if="isComponentVisible" />
  </div>
</template>

<script>
export default {
  data() {
    return {
      isComponentVisible: false
    }
  },
  mounted() {
    // 假設某些條件或事件觸發顯示
    setTimeout(() => {
      this.isComponentVisible = true
    }, 3000)
  },
  components: {
    MyComponent: () => import('./components/MyComponent.vue')
  }
}
</script>

defineAsyncComponent

  • 在 Vue3 當中新增的 API,用於更簡便處理異步元件的 Lazy Loading
  1. 創建異步元件
// AsyncComponent.vue
<template>
  <div>
    <h2>
      {{ title }}
    </h2>
  </div>
</template>

<script setup>
import { ref } from 'vue'
  // 異步元件的邏輯
  const title = ref('大家好')
  ......
</script>
  1. 在父元件中引入
// App.vue
<template>
  <AsyncComponent v-if="show" />
  <button @click="show = true">Show Component</button>
</template>

<script setup>
import { ref } from 'vue'
import { defineAsyncComponent } from 'vue'

const show = ref(false)

const AsyncComponent = defineAsyncComponent(() => import('./components/AsyncComponent.vue'))
</script>
  • 使用defineAsyncComponent時可以自定義一些設定
const AsyncComponent = defineAsyncComponent({
  // the loader function
  loader: () => import('./components/AsyncComponent.vue'),

  // A component to use while the async component is loading
  loadingComponent: LoadingComponent,
  // Delay before showing the loading component. Default: 200ms.
  delay: 200,

  // A component to use if the load fails
  errorComponent: ErrorComponent,
  // The error component will be displayed if a timeout is
  // provided and exceeded. Default: Infinity.
  timeout: 3000
})
  • 可以和Suspense一起使用
  • 加載過程中會顯示#fallback的 Loading...,優先於defineAsyncComponent的設定
<template>
  <Suspense v-if="show">
    <template #default>
      <AsyncComponent />
    </template>
    <template #fallback> Loading... </template>
  </Suspense>
  <button @click="show = true">Show Component</button>
</template>

Webpack 的 Lazy Loading

  • 允許開發者使用特定的語法(如 import())來標記代碼中的分割點
  • 這些分割點告訴 Webpack 在這裡需要將代碼分割成不同的chunks
  • 這些chunks可以被單獨加載
  • 在開發階段和生產階段都會進行完整的應用打包

例如:在 Vue Router 中新增一個路由

  • 會將 Home.vue 及其依賴的代碼打包成一個獨立的chunk
  • 這個chunk在用戶訪問相應路由時才會被加載
const Home = () => import('./Home.vue')

參考資料

# Vue # LazyLoading