Gensics

Back to Home

Vue 3 Performance Optimization Tips

Vue Developer17 ธันวาคม 2567Performance
VuePerformanceOptimizationVue 3

การปรับปรุงประสิทธิภาพใน Vue 3 มีหลายเทคนิคที่ช่วยให้แอปพลิเคชันทำงานได้ราบรื่นและเร็วขึ้น

1. ใช้ v-memo สำหรับ Expensive Renders

<template> <!-- จะ re-render เฉพาะเมื่อ item.id หรือ item.selected เปลี่ยน --> <div v-for="item in list" :key="item.id" v-memo="[item.id, item.selected]"> <ExpensiveComponent :item="item" /> </div> </template>

2. Lazy Loading Components

// defineAsyncComponent import { defineAsyncComponent } from 'vue' const AsyncComp = defineAsyncComponent({ loader: () => import('./MyComponent.vue'), loadingComponent: LoadingComponent, errorComponent: ErrorComponent, delay: 200, timeout: 3000 }) // Router lazy loading const routes = [ { path: '/heavy-page', component: () => import('./views/HeavyPage.vue') } ]

3. Virtual Scrolling

<template> <VirtualList class="virtual-list" :data-key="'id'" :data-sources="items" :data-component="ItemComponent" :estimate-size="50" :item-class="'list-item'" /> </template> <script> import VirtualList from '@tanstack/vue-virtual' import ItemComponent from './ItemComponent.vue' export default { components: { VirtualList }, data() { return { ItemComponent, items: [] // Large array } } } </script>

4. KeepAlive สำหรับ Component Caching

<template> <KeepAlive :include="['ComponentA', 'ComponentB']"> <component :is="currentComponent" /> </KeepAlive> </template> <script setup> import { ref, shallowRef } from 'vue' import ComponentA from './ComponentA.vue' import ComponentB from './ComponentB.vue' const currentComponent = shallowRef(ComponentA) </script>

5. Optimize Reactivity

import { ref, reactive, shallowRef, shallowReactive, readonly } from 'vue' // ใช้ shallowRef สำหรับ large objects ที่ไม่ต้องการ deep reactivity const shallowState = shallowRef({ deeply: { nested: { object: 'value' } } }) // ใช้ shallowReactive สำหรับ objects ที่มี properties เยอะ const shallowObj = shallowReactive({ prop1: 'value1', prop2: 'value2', // ... many props }) // ใช้ readonly สำหรับ data ที่ไม่เปลี่ยนแปลง const immutableData = readonly({ config: { apiUrl: 'https://api.example.com', version: '1.0.0' } })

6. Computed Properties Optimization

import { computed, ref } from 'vue' const users = ref([]) const filter = ref('') // ใช้ computed แทนการ filter ใน template const filteredUsers = computed(() => { if (!filter.value) return users.value return users.value.filter(user => user.name.toLowerCase().includes(filter.value.toLowerCase()) ) }) // Cache expensive computations const expensiveValue = computed(() => { console.log('Computing expensive value...') return users.value.reduce((sum, user) => sum + user.score, 0) })

7. Event Handling Optimization

<template> <!-- ใช้ event delegation สำหรับ large lists --> <ul @click="handleListClick"> <li v-for="item in items" :key="item.id" :data-id="item.id"> {{ item.name }} </li> </ul> <!-- ใช้ .once modifier สำหรับ events ที่เกิดครั้งเดียว --> <button @click.once="trackFirstClick">Track First Click</button> <!-- ใช้ .passive สำหรับ scroll events --> <div @scroll.passive="handleScroll">Scrollable content</div> </template> <script setup> const handleListClick = (event) => { const itemId = event.target.closest('li')?.dataset.id if (itemId) { selectItem(itemId) } } const handleScroll = (event) => { // Handle scroll without blocking } </script>

8. Bundle Optimization

// vite.config.js export default { build: { rollupOptions: { output: { manualChunks: { vendor: ['vue', 'vue-router'], ui: ['@headlessui/vue', '@heroicons/vue'] } } } }, optimizeDeps: { include: ['vue', 'vue-router'] } }

9. Image Optimization

<template> <!-- Lazy loading images --> <img :src="imageSrc" loading="lazy" :alt="imageAlt" @load="onImageLoad" /> <!-- Responsive images --> <picture> <source media="(min-width: 768px)" :srcset="desktopImage"> <source media="(min-width: 480px)" :srcset="tabletImage"> <img :src="mobileImage" :alt="imageAlt"> </picture> </template>

10. Web Workers

// worker.js self.addEventListener('message', (event) => { const { data, type } = event.data if (type === 'PROCESS_DATA') { const result = processLargeDataset(data) self.postMessage({ type: 'RESULT', result }) } }) // Component import { ref, onMounted, onUnmounted } from 'vue' export default { setup() { const worker = ref(null) const result = ref(null) onMounted(() => { worker.value = new Worker('/worker.js') worker.value.addEventListener('message', (event) => { if (event.data.type === 'RESULT') { result.value = event.data.result } }) }) onUnmounted(() => { worker.value?.terminate() }) const processData = (data) => { worker.value.postMessage({ type: 'PROCESS_DATA', data }) } return { result, processData } } }

Performance Monitoring

// Performance tracking import { nextTick } from 'vue' const trackComponentRender = async (componentName) => { const start = performance.now() await nextTick() const end = performance.now() console.log(`${componentName} render time: ${end - start}ms`) } // Memory leak detection const trackMemoryUsage = () => { if (performance.memory) { console.log({ used: Math.round(performance.memory.usedJSHeapSize / 1048576), total: Math.round(performance.memory.totalJSHeapSize / 1048576), limit: Math.round(performance.memory.jsHeapSizeLimit / 1048576) }) } }

Best Practices

  1. ใช้ Vue DevTools - ตรวจสอบ component performance
  2. Lighthouse Audits - วัดประสิทธิภาพโดยรวม
  3. Bundle Analysis - ตรวจสอบขนาด bundle
  4. Code Splitting - แยก code ตาม routes หรือ features
  5. Tree Shaking - ใช้ ES modules และ remove unused code

สรุป

การปรับปรุงประสิทธิภาพใน Vue 3 ต้องทำอย่างมีแผนและวัดผลอย่างสม่ำเสมอ เริ่มจากการระบุ bottlenecks แล้วใช้เทคนิคที่เหมาะสม