DesQTA is optimized for fast load times, smooth interactions, and efficient resource usage. This guide covers optimization strategies and best practices.
SvelteKit automatically splits code by route:
// Lazy load heavy components
const HeavyComponent = lazy (() => import ( './HeavyComponent.svelte' ));
// Dynamic imports for routes
const module = await import ( './heavy-module.js' );
< script lang = "ts" >
import { onMount } from 'svelte' ;
let ChartComponent : any = null ;
onMount ( async () => {
// Load only when needed
const module = await import ( './Chart.svelte' );
ChartComponent = module .default;
});
</ script >
{# if ChartComponent}
< svelte : component this ={ChartComponent} { data } />
{/ if }
For long lists, use virtual scrolling:
< script lang = "ts" >
import { VirtualList } from 'svelte-virtual-list' ;
let items = $ state < Item []>([]);
</ script >
< VirtualList
items ={items}
itemHeight ={ 50 }
let : item
>
< div >{item.name}</ div >
</ VirtualList >
Debounce expensive operations:
< script lang = "ts" >
import { debounce } from '$lib/utils/helpers' ;
let searchQuery = $ state ( '' );
const debouncedSearch = debounce (( query : string ) => {
performSearch (query);
}, 300 );
function handleInput ( e : Event ) {
const target = e.target as HTMLInputElement ;
searchQuery = target.value;
debouncedSearch (searchQuery);
}
</ script >
< input type = "text" oninput ={handleInput} />
Use $derived for computed values:
< script lang = "ts" >
let items = $ state < Item []>([]);
let filter = $ state ( '' );
// ✅ Good - Memoized
let filteredItems = $ derived (
items. filter ( item => item.name. includes (filter))
);
// ❌ Avoid - Recomputes every render
let filteredItems = items. filter ( item => item.name. includes (filter));
</ script >
Use in-memory cache for frequently accessed data:
import { cache } from '$lib/utils/cache' ;
async function getData ( key : string ) {
// Check cache first
if (cache. has (key)) {
return cache. get (key);
}
// Fetch and cache
const data = await fetchData ();
cache. set (key, data, 5 * 60 * 1000 ); // 5 minutes
return data;
}
Persistent cache for offline support:
import { idbCache } from '$lib/services/idbCache' ;
async function getCachedData ( key : string ) {
const cached = await idbCache. get (key);
if (cached && ! isExpired (cached)) {
return cached.data;
}
const data = await fetchData ();
await idbCache. set (key, data, Date. now () + 60 * 60 * 1000 );
return data;
}
Cache static assets and API responses:
// Cache API responses
self. addEventListener ( 'fetch' , ( event ) => {
if (event.request.url. includes ( '/api/' )) {
event. respondWith (
caches. match (event.request). then (( response ) => {
return response || fetch (event.request). then (( response ) => {
const clone = response. clone ();
caches. open ( 'api-cache' ). then (( cache ) => {
cache. put (event.request, clone);
});
return response;
});
})
);
}
});
< img
src ={imageUrl}
loading = "lazy"
alt = "Description"
/>
< img
srcset = "
image-small.jpg 480w,
image-medium.jpg 768w,
image-large.jpg 1200w
"
sizes = "(max-width: 480px) 100vw, (max-width: 768px) 50vw, 33vw"
src = "image-medium.jpg"
alt = "Description"
/>
Use optimized image formats:
WebP : Modern format with better compressionAVIF : Next-generation format (when supported)Lazy load : Load images only when visibleRemove unused code:
// ✅ Good - Import only what you need
import { debounce } from '$lib/utils/helpers' ;
// ❌ Avoid - Import entire module
import * as utils from '$lib/utils/helpers' ;
// ✅ Good - Lightweight alternative
import { format } from 'date-fns' ;
// ❌ Avoid - Heavy library
import moment from 'moment' ;
// Load features on demand
if (featureEnabled) {
const FeatureModule = await import ( './Feature.svelte' );
}
< script lang = "ts" >
// ✅ Good - Stable reference
const config = { theme: 'dark' };
// ❌ Avoid - New object every render
const config = { theme: 'dark' }; // Creates new object
</ script >
<!-- ✅ Good - Keyed -->
{# each items as item (item.id)}
< ItemComponent { item } />
{/ each }
<!-- ❌ Avoid - Not keyed -->
{# each items as item}
< ItemComponent { item } />
{/ each }
<!-- ✅ Good - Early return -->
{# if ! loading}
{# if data}
< DataComponent { data } />
{: else }
< EmptyState />
{/ if }
{/ if }
<!-- ❌ Avoid - Nested conditions -->
{# if loading}
< LoadingSpinner />
{: else if data}
< DataComponent { data } />
{: else }
< EmptyState />
{/ if }
Prevent duplicate requests:
const pendingRequests = new Map < string , Promise < any >>();
async function fetchData ( key : string ) {
if (pendingRequests. has (key)) {
return pendingRequests. get (key);
}
const promise = fetch (key). then ( res => res. json ());
pendingRequests. set (key, promise);
try {
const result = await promise;
return result;
} finally {
pendingRequests. delete (key);
}
}
Batch multiple requests:
async function batchRequests ( requests : Promise < any >[]) {
return Promise . all (requests);
}
Reuse HTTP connections (handled by Tauri backend).
< script lang = "ts" >
import { onDestroy } from 'svelte' ;
const unsubscribe = store. subscribe ( value => {
// Handle update
});
onDestroy (() => {
unsubscribe ();
});
</ script >
< script lang = "ts" >
import { onMount, onDestroy } from 'svelte' ;
let handler : (() => void ) | null = null ;
onMount (() => {
handler = () => {
// Handle event
};
window. addEventListener ( 'resize' , handler);
});
onDestroy (() => {
if (handler) {
window. removeEventListener ( 'resize' , handler);
}
});
</ script >
< script lang = "ts" >
import { onMount, onDestroy } from 'svelte' ;
let interval : ReturnType < typeof setInterval>;
onMount (() => {
interval = setInterval (() => {
// Update
}, 1000 );
});
onDestroy (() => {
clearInterval (interval);
});
</ script >
Track key metrics:
// Time to Interactive (TTI)
const tti = performance.timing.domInteractive - performance.timing.navigationStart;
// First Contentful Paint (FCP)
const fcp = performance. getEntriesByType ( 'paint' )[ 0 ].startTime;
// Largest Contentful Paint (LCP)
const lcp = performance. getEntriesByType ( 'largest-contentful-paint' )[ 0 ].startTime;
// Mark start
performance. mark ( 'data-load-start' );
// Load data
await loadData ();
// Mark end and measure
performance. mark ( 'data-load-end' );
performance. measure ( 'data-load' , 'data-load-start' , 'data-load-end' );
// Get measurement
const measure = performance. getEntriesByName ( 'data-load' )[ 0 ];
console. log ( `Data load took ${ measure . duration }ms` );
import { logger } from '$lib/utils/logger' ;
async function loadData () {
const startTime = performance. now ();
try {
const data = await fetchData ();
const endTime = performance. now ();
logger. logPerformance ( 'service' , 'loadData' , startTime, endTime);
return data;
} catch (error) {
logger. error ( 'service' , 'loadData' , 'Failed' , { error });
throw error;
}
}
// Profile first
console. time ( 'operation' );
await expensiveOperation ();
console. timeEnd ( 'operation' );
Focus on:
Initial page load User interactions Data fetching
# Development - Not optimized
npm run dev
# Production - Optimized
npm run build
# Analyze bundle
npm run build -- --analyze
// Performance tests
test ( 'loads page in under 2 seconds' , async () => {
const start = performance. now ();
await page. goto ( '/' );
const duration = performance. now () - start;
expect (duration). toBeLessThan ( 2000 );
});