mcpField
B
best-practices

best-practices

github.com/davila7テスト・品質33.0k398 回インストール1 日前に更新
リポジトリ

best-practices について

Lighthouse のベストプラクティス監査に基づく Web 開発向けリファレンススキルです。セキュリティ、ブラウザー互換性、パフォーマンス、コード品質、ユーザー体験を実践例とチェックリストで確認できます。

主な機能

  1. 01セキュリティヘッダーと入力処理
  2. 02ブラウザー互換性のガイド
  3. 03パフォーマンスとメモリ管理の実践
  4. 04エラー処理とコード品質の確認
  5. 05監査チェックリストとツールの参照

活用シーン

  1. 01サイトのセキュリティ設定の確認
  2. 02ブラウザー互換性と非推奨 API の調査
  3. 03パフォーマンスと本番環境のエラーの監査

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/davila7/claude-code-templates --skill best-practices

インストール後、Claude Code で/best-practicesを入力して読み込まれたか確認します。

詳細

ベストプラクティス

Lighthouseのベストプラクティス監査に基づく、最新のWeb開発標準です。セキュリティ、ブラウザ互換性、コード品質のパターンを扱います。

セキュリティ

すべてのページでHTTPSを使用

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ヘッダー:

Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
コンテンツセキュリティポリシー (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ヘッダー(推奨):

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';

インラインスクリプトでのnonceの使用:

<script nonce="abc123">
  // This inline script is allowed
</script>
セキュリティヘッダー
# 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=()
脆弱なライブラリを使用しない
# Check for vulnerabilities
npm audit
yarn audit

# Auto-fix when possible
npm audit fix

# Check specific package
npm ls lodash

依存関係を最新の状態に保つ:

// package.json
{
  "scripts": {
    "audit": "npm audit --audit-level=moderate",
    "update": "npm update && npm audit fix"
  }
}

避けるべき既知の脆弱なパターン:

// ❌ Prototype pollution vulnerable patterns
Object.assign(target, userInput);
_.merge(target, userInput);

// ✅ Safer alternatives
const safeData = JSON.parse(JSON.stringify(userInput));
入力のサニタイズ
// ❌ XSS vulnerable
element.innerHTML = userInput;
document.write(userInput);

// ✅ Safe text content
element.textContent = userInput;

// ✅ If HTML needed, sanitize
import DOMPurify from 'dompurify';
element.innerHTML = DOMPurify.sanitize(userInput);
安全なCookie
// ❌ Insecure cookie
document.cookie = "session=abc123";

// ✅ Secure cookie (server-side)
Set-Cookie: session=abc123; Secure; HttpOnly; SameSite=Strict; Path=/

ブラウザ互換性

Doctype宣言

<HTML>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">


<!DOCTYPE html>
<html lang="en">
文字エンコーディング

<html>
<head>
  <title>Page</title>
  <meta charset="UTF-8">
</head>


<html>
<head>
  <meta charset="UTF-8">
  <title>Page</title>
</head>
viewportメタタグ

<head>
  <title>Page</title>
</head>


<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Page</title>
</head>
機能検出
// ❌ Browser detection (brittle)
if (navigator.userAgent.includes('Chrome')) {
  // Chrome-specific code
}

// ✅ Feature detection
if ('IntersectionObserver' in window) {
  // Use IntersectionObserver
} else {
  // Fallback
}

// ✅ Using @supports in CSS
@supports (display: grid) {
  .container {
    display: grid;
  }
}

@supports not (display: grid) {
  .container {
    display: flex;
  }
}
ポリフィル(必要な場合)

<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>

非推奨のAPI

使用を避けるもの
// ❌ document.write (blocks parsing)
document.write('<script src="..."></script>');

// ✅ Dynamic script loading
const script = document.createElement('script');
script.src = '...';
document.head.appendChild(script);

// ❌ Synchronous XHR (blocks main thread)
const xhr = new XMLHttpRequest();
xhr.open('GET', url, false); // false = synchronous

// ✅ Async fetch
const response = await fetch(url);

// ❌ Application Cache (deprecated)
<html manifest="cache.manifest">

// ✅ Service Workers
if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('/sw.js');
}
イベントリスナーのpassive
// ❌ Non-passive touch/wheel (may block scrolling)
element.addEventListener('touchstart', handler);
element.addEventListener('wheel', handler);

// ✅ Passive listeners (allows smooth scrolling)
element.addEventListener('touchstart', handler, { passive: true });
element.addEventListener('wheel', handler, { passive: true });

// ✅ If you need preventDefault, be explicit
element.addEventListener('touchstart', handler, { passive: false });

コンソールとエラー

コンソールエラーをなくす
// ❌ Errors in production
console.log('Debug info'); // Remove in production
throw new Error('Unhandled'); // Catch all errors

// ✅ Proper error handling
try {
  riskyOperation();
} catch (error) {
  // Log to error tracking service
  errorTracker.captureException(error);
  // Show user-friendly message
  showErrorMessage('Something went wrong. Please try again.');
}
エラー境界(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;
  }
}

// Usage
<ErrorBoundary>
  <App />
</ErrorBoundary>
グローバルエラーハンドラー
// Catch unhandled errors
window.addEventListener('error', (event) => {
  errorTracker.captureException(event.error);
});

// Catch unhandled promise rejections
window.addEventListener('unhandledrejection', (event) => {
  errorTracker.captureException(event.reason);
});

ソースマップ

本番環境での設定
// ❌ Source maps exposed in production
// webpack.config.js
module.exports = {
  devtool: 'source-map', // Exposes source code
};

// ✅ Hidden source maps (uploaded to error tracker)
module.exports = {
  devtool: 'hidden-source-map',
};

// ✅ Or no source maps in production
module.exports = {
  devtool: process.env.NODE_ENV === 'production' ? false : 'source-map',
};

パフォーマンスのベストプラクティス

ブロッキングパターンを避ける
// ❌ Blocking script
<script src="heavy-library.js"></script>

// ✅ Deferred script
<script defer src="heavy-library.js"></script>

// ❌ Blocking CSS import
@import url('other-styles.css');

// ✅ Link tags (parallel loading)
<link rel="stylesheet" href="styles.css">
<link rel="stylesheet" href="other-styles.css">
効率的なイベントハンドラー
// ❌ Handler on every element
items.forEach(item => {
  item.addEventListener('click', handleClick);
});

// ✅ Event delegation
container.addEventListener('click', (e) => {
  if (e.target.matches('.item')) {
    handleClick(e);
  }
});
メモリ管理
// ❌ Memory leak (never removed)
const handler = () => { /* ... */ };
window.addEventListener('resize', handler);

// ✅ Cleanup when done
const handler = () => { /* ... */ };
window.addEventListener('resize', handler);

// Later, when component unmounts:
window.removeEventListener('resize', handler);

// ✅ Using AbortController
const controller = new AbortController();
window.addEventListener('resize', handler, { signal: controller.signal });

// Cleanup:
controller.abort();

コード品質

有効なHTML

<div id="header">
<div id="header"> 

<ul>
  <div>Item</div> 
</ul>

<a href="/"><button>Click</button></a> 


<header id="site-header">
</header>

<ul>
  <li>Item</li>
</ul>

<a href="/" class="button">Click</a>
セマンティック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>
画像のアスペクト比

<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;">

権限とプライバシー

権限を適切にリクエストする
// ❌ Request on page load (bad UX, often denied)
navigator.geolocation.getCurrentPosition(success, error);

// ✅ Request in context, after user action
findNearbyButton.addEventListener('click', async () => {
  // Explain why you need it
  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')">

監査チェックリスト

セキュリティ(重要)
  • HTTPSが有効で、混在コンテンツがない
  • 脆弱な依存関係がない(npm audit)
  • CSPヘッダーが設定されている
  • セキュリティヘッダーが存在する
  • ソースマップが公開されていない
互換性
  • 有効なHTML5のDoctype
  • 文字セットがheadの先頭で宣言されている
  • viewportメタタグが存在する
  • 非推奨のAPIを使用していない
  • スクロール/タッチにpassiveイベントリスナーを使用している
コード品質
  • コンソールエラーがない
  • 有効なHTML(重複するIDがない)
  • セマンティックHTML要素を使用している
  • 適切なエラー処理がある
  • コンポーネント内のメモリがクリーンアップされている
UX
  • 邪魔になるインタースティシャルがない
  • 権限リクエストが文脈に沿って行われている
  • エラーメッセージが分かりやすい
  • 画像のアスペクト比が適切である

ツール

ツール用途
npm audit依存関係の脆弱性
SecurityHeaders.comヘッダー分析
W3C ValidatorHTML検証
Lighthouseベストプラクティス監査
Observatoryセキュリティスキャン

参考資料

コメント