| name | best-practices |
| description | Apply modern web development best practices for security, compatibility, and code quality. Use when asked to "apply best practices", "security audit", "modernize code", "code quality review", or "check for vulnerabilities". Do NOT use for accessibility (use web-accessibility), SEO (use seo), performance (use core-web-vitals), or comprehensive multi-area audits (use web-quality-audit). |
| license | MIT |
| metadata | {"author":"web-quality-skills","version":"1.0"} |
Best practices
Modern web development standards based on Lighthouse best practices audits. Covers security, browser compatibility, and code quality patterns.
Security
HTTPS everywhere
Enforce HTTPS:
<img src="http://example.com/image.jpg" />
<script src="http://cdn.example.com/script.js"></script>
<img src="https://example.com/image.jpg" />
<script src="https://cdn.example.com/script.js"></script>
<img src="//example.com/image.jpg" />
HSTS Header:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
Content Security Policy (CSP)
<meta
http-equiv="Content-Security-Policy"
content="default-src 'self';
script-src 'self' https://trusted-cdn.com;
style-src 'self' 'unsafe-inline';
img-src 'self' data: https:;
connect-src 'self' https://api.example.com;"
/>
CSP Header (recommended):
Content-Security-Policy:
default-src 'self';
script-src 'self' 'nonce-abc123' https://trusted.com;
style-src 'self' 'nonce-abc123';
img-src 'self' data: https:;
connect-src 'self' https://api.example.com;
frame-ancestors 'self';
base-uri 'self';
form-action 'self';
Using nonces for inline scripts:
<script nonce="abc123">
</script>
Security headers
# Prevent clickjacking
X-Frame-Options: DENY
# Prevent MIME type sniffing
X-Content-Type-Options: nosniff
# Enable XSS filter (legacy browsers)
X-XSS-Protection: 1; mode=block
# Control referrer information
Referrer-Policy: strict-origin-when-cross-origin
# Permissions policy (formerly Feature-Policy)
Permissions-Policy: geolocation=(), microphone=(), camera=()
No vulnerable libraries
npm audit
yarn audit
npm audit fix
npm ls lodash
Keep dependencies updated:
{
"scripts": {
"audit": "npm audit --audit-level=moderate",
"update": "npm update && npm audit fix"
}
}
Known vulnerable patterns to avoid:
Object.assign(target, userInput)
_.merge(target, userInput)
const safeData = JSON.parse(JSON.stringify(userInput))
Input sanitization
element.innerHTML = userInput
document.write(userInput)
element.textContent = userInput
import DOMPurify from 'dompurify'
element.innerHTML = DOMPurify.sanitize(userInput)
Secure cookies
document.cookie = "session=abc123";
Set-Cookie: session=abc123; Secure; HttpOnly; SameSite=Strict; Path=/
Browser compatibility
Doctype declaration
<html lang="en">
<head>
<title>Page</title>
</head>
<body></body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<title>Page</title>
</head>
<body></body>
</html>
Character encoding
<!DOCTYPE html>
<html lang="en">
<head>
<title>Page</title>
<meta charset="UTF-8" />
</head>
<body></body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Page</title>
</head>
<body></body>
</html>
Viewport meta tag
<head>
<title>Page</title>
</head>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Page</title>
</head>
Feature detection
if (navigator.userAgent.includes('Chrome')) {
}
if ('IntersectionObserver' in window) {
} else {
}
@supports (display: grid) {
.container {
display: grid;
}
}
@supports not (display: grid) {
.container {
display: flex;
}
}
Polyfills (when needed)
<script>
if (!('fetch' in window)) {
document.write('<script src="/polyfills/fetch.js"><\/script>')
}
</script>
<script src="https://polyfill.io/v3/polyfill.min.js?features=fetch,IntersectionObserver"></script>
Deprecated APIs
Avoid these
document.write('<script src="..."></script>');
const script = document.createElement('script');
script.src = '...';
document.head.appendChild(script);
const xhr = new XMLHttpRequest();
xhr.open('GET', url, false);
const response = await fetch(url);
<html manifest="cache.manifest">
// ✅ Service Workers
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js');
}
Event listener passive
element.addEventListener('touchstart', handler)
element.addEventListener('wheel', handler)
element.addEventListener('touchstart', handler, { passive: true })
element.addEventListener('wheel', handler, { passive: true })
element.addEventListener('touchstart', handler, { passive: false })
Console & errors
No console errors
console.log('Debug info')
throw new Error('Unhandled')
try {
riskyOperation()
} catch (error) {
errorTracker.captureException(error)
showErrorMessage('Something went wrong. Please try again.')
}
Error boundaries (React)
class ErrorBoundary extends React.Component {
state = { hasError: false }
static getDerivedStateFromError(error) {
return { hasError: true }
}
componentDidCatch(error, info) {
errorTracker.captureException(error, { extra: info })
}
render() {
if (this.state.hasError) {
return <FallbackUI />
}
return this.props.children
}
}
;<ErrorBoundary>
<App />
</ErrorBoundary>
Global error handler
window.addEventListener('error', (event) => {
errorTracker.captureException(event.error)
})
window.addEventListener('unhandledrejection', (event) => {
errorTracker.captureException(event.reason)
})
Source maps
Production configuration
module.exports = {
devtool: 'source-map',
}
module.exports = {
devtool: 'hidden-source-map',
}
module.exports = {
devtool: process.env.NODE_ENV === 'production' ? false : 'source-map',
}
Performance best practices
Avoid blocking patterns
<script src="heavy-library.js"></script>
<script defer src="heavy-library.js"></script>
@import url('other-styles.css');
<link rel="stylesheet" href="styles.css">
<link rel="stylesheet" href="other-styles.css">
Efficient event handlers
items.forEach((item) => {
item.addEventListener('click', handleClick)
})
container.addEventListener('click', (e) => {
if (e.target.matches('.item')) {
handleClick(e)
}
})
Memory management
const handler = () => {
}
window.addEventListener('resize', handler)
const handler = () => {
}
window.addEventListener('resize', handler)
window.removeEventListener('resize', handler)
const controller = new AbortController()
window.addEventListener('resize', handler, { signal: controller.signal })
controller.abort()
Code quality
Valid HTML
<div id="header">
<div id="header">
</div>
<ul>
<div>Item</div>
</ul>
<a href="/"><button>Click</button></a>
</div>
<header id="site-header"></header>
<ul>
<li>Item</li>
</ul>
<a href="/" class="button">Click</a>
Semantic HTML
<div class="header">
<div class="nav">
<div class="nav-item">Home</div>
</div>
</div>
<div class="main">
<div class="article">
<div class="title">Headline</div>
</div>
</div>
<header>
<nav>
<a href="/">Home</a>
</nav>
</header>
<main>
<article>
<h1>Headline</h1>
</article>
</main>
Image aspect ratios
<img src="photo.jpg" width="300" height="100" />
<img src="photo.jpg" width="300" height="225" />
<img src="photo.jpg" style="width: 300px; height: 200px; object-fit: cover;" />
Permissions & privacy
Request permissions properly
navigator.geolocation.getCurrentPosition(success, error)
findNearbyButton.addEventListener('click', async () => {
if (await showPermissionExplanation()) {
navigator.geolocation.getCurrentPosition(success, error)
}
})
Permissions policy
<meta http-equiv="Permissions-Policy" content="geolocation=(), camera=(), microphone=()" />
<meta http-equiv="Permissions-Policy" content="geolocation=(self 'https://maps.example.com')" />
Audit checklist
Security (critical)
Compatibility
Code quality
UX
Tools
References