This episode covers application security and speed: Content Security Policy and secure headers, caching strategies and resource optimization, image optimization with lazy loading, and network performance monitoring.

A fast page and a secure page aren't two separate things. Good caching strategies reduce server load, while a Content Security Policy blocks malicious scripts before they can run. Both require deliberate configuration.
This episode covers Content Security Policy and secure headers, caching strategies and resource optimization, image optimization with lazy loading, and how to monitor network performance.
When you're done, you can lock your pages away from unknown resources while making them load faster. The security and performance covered here reinforce each other rather than conflict.
CSP tells the browser which sources are allowed to load — scripts, styles, images, and more. Scripts from unlisted domains get blocked, so injection attacks like XSS lose their main tool.
SvelteKit provides built-in CSP configuration through kit.csp in svelte.config.js:
const config = {
kit: {
csp: {
mode: "auto",
directives: {
"default-src": ["self"],
"script-src": ["self"],
"img-src": ["self", "https://cdn.example.com"],
"style-src": ["self", "unsafe-inline"],
},
},
},
}
export default config"script-src": ["self"] forbids scripts from outside the app's domain. mode: "auto" automatically adds a nonce for legitimate scripts, so you don't have to edit HTML by hand.
Beyond CSP, several headers are worth setting: Strict-Transport-Security enforces HTTPS, X-Content-Type-Options: nosniff prevents MIME sniffing, and Referrer-Policy limits what leaks through the referrer. On many hosting platforms these headers are configured in a panel or a dedicated config file.
Deliberate caching lets returning users skip reloading everything. For data that rarely changes, set the Cache-Control header on a server endpoint:
export function GET() {
const laporan = { versi: 3, disusun: "2026-08-10" }
return new Response(JSON.stringify(laporan), {
headers: {
"Cache-Control": "public, max-age=3600, stale-while-revalidate=60",
},
})
}public, max-age=3600 allows caching for one hour. stale-while-revalidate=60 serves the old version while updating in the background — a combination that makes the UI feel fast without sacrificing data freshness.
The JavaScript bundle is the heaviest resource. Cut unused libraries, support tree-shaking with named imports, and only load the polyfills you actually need. Small assets can also be inlined to reduce the number of requests.
Images are the largest asset on most pages. Load only the images near the viewport:
<img
src="/series/tutorial/hero.png"
alt="Ilustrasi hero"
loading="lazy"
decoding="async"
width="1200"
height="630"
/>loading="lazy" defers the image download until it's near the viewport. decoding="async" lets the browser display other content while decoding the image. Adding width and height prevents layout shifts that hurt performance scores.
Prepare images in several sizes and let the browser choose via srcset and sizes. Smaller images for small screens save expensive mobile bandwidth.
The browser records every stage of page load. You can read that data directly from performance.getEntriesByType("navigation"):
export function ukurWaktu() {
const entry = performance.getEntriesByType("navigation")[0]
return {
ttfB: entry.responseStart - entry.requestStart,
domComplete: entry.domComplete,
}
}performance.getEntriesByType("navigation") returns the navigation record. Metrics like Time to First Byte and domComplete give a rough picture and can be sent to a backend for reporting.
Lighthouse and the Network panel in DevTools are visual tools for catching slow or unnecessary requests. Combine both with the real-user monitoring covered in episode 22.
Key takeaways:
kit.csp with automatic nonce mode.Cache-Control on server endpoints.decoding="async" for below-the-fold images.srcset for various screen sizes.Next, in episode 15 we will discuss performance optimization — profiling with browser tools and benchmarks, minimizing the bundle with tree-shaking, reducing runtime overhead and reactivity costs, and lazy loading components and code splitting. The habit of measuring first, then optimizing, will be the main theme.