All quizzesHard
Bundle Optimization
Preview — 3 of 10 questions
What are the two main strategies for virtual scrolling and what are their tradeoffs?
javascript
<script setup>
import { useVirtualizer } from '@tanstack/vue-virtual'
import { ref } from 'vue'
const parentRef = ref(null)
const items = ref(generateItems(100000))
// Strategy 1: Fixed-size (all items same height — simpler, faster)
const fixedVirtualizer = useVirtualizer({
count: items.value.length,
getScrollElement: () => parentRef.value,
estimateSize: () => 56, // All rows are exactly 56px
overscan: 5, // Render 5 extra items above/below viewport
})
// Strategy 2: Variable-size (items have different heights — measured at runtime)
const variableVirtualizer = useVirtualizer({
count: items.value.length,
getScrollElement: () => parentRef.value,
estimateSize: (i) => items.value[i].type === 'header' ? 80 : 48,
// measureElement: (el) => el.getBoundingClientRect().height — for dynamic
})
</script>
<template>
<div ref="parentRef" class="scroll-container" style="height: 500px; overflow-y: auto;">
<!-- Total height spacer — makes the scrollbar proportional to total items -->
<div :style="{ height: `${fixedVirtualizer.getTotalSize()}px`, position: 'relative' }">
<div
v-for="row in fixedVirtualizer.getVirtualItems()"
:key="row.key"
:style="{
position: 'absolute',
top: `${row.start}px`,
left: 0,
width: '100%',
height: `${row.size}px`
}"
>
<ItemRow :item="items[row.index]" />
</div>
</div>
</div>
</template>ADOM recycling vs. element caching — DOM recycling is always faster
BCSS-based virtualization vs. JavaScript-based virtualization — CSS is always preferred
CFixed-size virtualization (known item height) vs. variable-size virtualization (measured at runtime) — fixed is simpler and faster; variable requires measurement
DColumn virtualization vs. row virtualization — use column for wide tables, row for long lists
How do you preload async components before the user navigates to them?
javascript
// Strategy 1: Vite's build-level prefetch
// vite.config.ts
export default defineConfig({
build: {
modulePreload: {
polyfill: true,
resolveDependencies: (filename, deps, context) => {
return deps // Preload all dependencies
}
}
}
})
// Strategy 2: Hover-based prefetch in router-link
// On user hover, preload the chunk before they click
const AdminView = defineAsyncComponent(() => import('./views/AdminView.vue'))
function prefetchAdminRoute() {
import('./views/AdminView.vue') // Trigger download
}
// Strategy 3: IntersectionObserver-based prefetch
// When a nav item scrolls into view, prefetch its route
const useRoutePrefetch = (routeLoader) => {
const linkRef = ref(null)
useIntersectionObserver(linkRef, ([{ isIntersecting }]) => {
if (isIntersecting) {
routeLoader() // Trigger dynamic import
}
})
return linkRef
}
// Strategy 4: requestIdleCallback — prefetch when browser is idle
if ('requestIdleCallback' in window) {
requestIdleCallback(() => {
import('./views/LikelyNextRoute.vue')
}, { timeout: 2000 })
}AUse <link rel="prefetch"> for route-level chunks or call import() on user interaction signals (hover, focus)
BSet preload: true in defineAsyncComponent options
CVue automatically preloads all async components on initial page load
DUse router.prefetch() — a built-in Vue Router method for preloading route components
What is the optimal chunk splitting strategy for a large Vue application?
javascript
// vite.config.ts — production chunk strategy
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
export default defineConfig({
build: {
rollupOptions: {
output: {
manualChunks(id) {
// Chunk 1: Vue core (rarely changes — long cache lifetime)
if (id.includes('node_modules/vue') ||
id.includes('node_modules/@vue')) {
return 'vue-core'
}
// Chunk 2: Large vendor libraries (Monaco editor, Chart.js)
if (id.includes('node_modules/monaco-editor')) {
return 'monaco'
}
if (id.includes('node_modules/chart.js')) {
return 'charts'
}
// Chunk 3: Utility vendors (lodash, date-fns)
if (id.includes('node_modules/lodash') ||
id.includes('node_modules/date-fns')) {
return 'utils'
}
// Chunk 4: Admin routes (rarely visited by most users)
if (id.includes('/views/admin/') ||
id.includes('/components/admin/')) {
return 'admin'
}
// Everything else stays in the main bundle
}
}
}
}
})ANever split — one large bundle is faster because it requires only one HTTP request
BOnly split when the bundle exceeds 5MB — smaller bundles don't need splitting
CSplit every component into its own chunk for maximum granularity
DSplit vendor libs from app code; split rarely-visited routes into separate chunks; keep frequently visited routes in the main bundle
Sign up free to play
Answer all 10 questions (7 more), see explanations for every answer, and track your score.