🎯 Рекомендуемые коллекции
Балансированные коллекции примеров кода из различных категорий, которые вы можете исследовать
Примеры Netlify Deployment
Примеры конфигурации Netlify deployment, включая netlify.toml, edge functions и обработку форм
💻 Netlify Базовая Конфигурация toml
🟢 simple
⭐
Базовая конфигурация Netlify с настройками сборки, перенаправлениями и заголовками
⏱️ 10 min
🏷️ netlify, configuration, deployment
Prerequisites:
Netlify basics, TOML syntax, Static site concepts
[build]
publish = "build"
command = "npm run build"
functions = "functions"
[build.environment]
NODE_VERSION = "18"
NPM_VERSION = "9"
[[redirects]]
from = "/api/*"
to = "/.netlify/functions/:splat"
status = 200
[[redirects]]
from = "/*"
to = "/index.html"
status = 200
[[headers]]
for = "/*"
[headers.values]
X-Frame-Options = "DENY"
X-XSS-Protection = "1; mode=block"
X-Content-Type-Options = "nosniff"
Referrer-Policy = "strict-origin-when-cross-origin"
[[headers]]
for = "/static/*"
[headers.values]
Cache-Control = "public, max-age=31536000, immutable"
[context.production]
command = "npm run build:prod"
[context.deploy-preview]
command = "npm run build:preview"
💻 Netlify Next.js Конфигурация toml
🟡 intermediate
⭐⭐⭐
Оптимизированная конфигурация Next.js приложений с ISR и edge functions
⏱️ 20 min
🏷️ netlify, next.js, framework
Prerequisites:
Next.js, Netlify plugin system, Edge functions
[build]
publish = ".next"
command = "npm run build"
environment = { NODE_VERSION = "18" }
[[plugins]]
package = "@netlify/plugin-nextjs"
[[redirects]]
from = "/_next/static/*"
to = "/_next/static/:splat"
status = 200
force = true
[[redirects]]
from = "/api/*"
to = "/.netlify/functions/:splat"
status = 200
[[redirects]]
from = "/_next/data/*/blog/*.json"
to = "/.netlify/functions/__ isr-blog?slug=:splat&:splat"
status = 200
[[redirects]]
from = "/blog/*"
to = "/.netlify/functions/__ isr-blog?slug=:splat"
status = 200
[[headers]]
for = "/api/*"
[headers.values]
Access-Control-Allow-Origin = "*"
Access-Control-Allow-Methods = "GET, POST, PUT, DELETE, OPTIONS"
Access-Control-Allow-Headers = "Content-Type, Authorization"
[[headers]]
for = "/_next/static/*"
[headers.values]
Cache-Control = "public, max-age=31536000, immutable"
[[headers]]
for = "/_next/image/*"
[headers.values]
Cache-Control = "public, max-age=86400, must-revalidate"
[context.production.environment]
NEXT_PUBLIC_API_URL = "https://api.example.com"
NEXT_PUBLIC_SITE_URL = "https://example.com"
[context.branch-deploy.environment]
NEXT_PUBLIC_API_URL = "https://dev-api.example.com"
NEXT_PUBLIC_SITE_URL = "https://dev--example.netlify.app"
[context.deploy-preview.environment]
NEXT_PUBLIC_API_URL = "https://preview-api.example.com"
NEXT_PUBLIC_SITE_URL = "https://deploy-preview-1--example.netlify.app"
[functions]
node_version = "18"
[[functions]]
directory = "functions"
node_bundler = "esbuild"
[[edge_functions]]
function = "geo-redirect"
path = "/geo-check"
💻 Netlify Edge Functions javascript
🟡 intermediate
⭐⭐⭐⭐
Примеры edge functions для геолокации, A/B тестирования и пользовательского middleware
⏱️ 30 min
🏷️ netlify, edge functions, middleware
Prerequisites:
JavaScript, Edge computing concepts, Netlify edge functions
// Netlify Edge Functions Examples
// 1. Geolocation-based redirect
// edge-functions/geo-redirect.js
export default async (request, context) => {
const url = new URL(request.url);
const country = request.geo?.country?.code?.toLowerCase();
// Redirect based on country
if (country === 'us') {
const usUrl = new URL('/us', url);
return Response.redirect(usUrl, 302);
} else if (country === 'uk') {
const ukUrl = new URL('/uk', url);
return Response.redirect(ukUrl, 302);
} else if (country === 'de') {
const deUrl = new URL('/de', url);
return Response.redirect(deUrl, 302);
}
// Add country data to headers
const response = await context.next();
response.headers.set('x-user-country', country || 'unknown');
return response;
};
// 2. A/B testing edge function
// edge-functions/ab-test.js
export default async (request, context) => {
const url = new URL(request.url);
// Skip A/B test for API routes
if (url.pathname.startsWith('/api/')) {
return context.next();
}
// Check for existing A/B test variant
const variant = request.headers.get('x-ab-variant') ||
Math.random() < 0.5 ? 'A' : 'B';
// Redirect to variant-specific path
if (variant === 'B' && !url.pathname.includes('/variant-b')) {
const variantUrl = new URL('/variant-b' + url.pathname, url);
const response = Response.redirect(variantUrl, 302);
response.headers.set('x-ab-variant', variant);
return response;
}
const response = await context.next();
response.headers.set('x-ab-variant', variant);
return response;
};
// 3. Authentication middleware
// edge-functions/auth.js
export default async (request, context) => {
const url = new URL(request.url);
// Skip auth for public routes
const publicPaths = ['/login', '/signup', '/forgot-password', '/api/auth'];
if (publicPaths.some(path => url.pathname.startsWith(path))) {
return context.next();
}
// Check for authentication token
const authCookie = request.headers.get('cookie')?.split(';')
?.find(cookie => cookie.trim().startsWith('auth_token='))
?.split('=')[1];
if (!authCookie) {
// Redirect to login
const loginUrl = new URL('/login', url);
loginUrl.searchParams.set('redirect', url.pathname);
return Response.redirect(loginUrl, 302);
}
// Validate token (mock validation)
try {
const isValid = await validateToken(authCookie);
if (!isValid) {
throw new Error('Invalid token');
}
// Add user info to headers for downstream functions
const response = await context.next();
response.headers.set('x-user-authenticated', 'true');
return response;
} catch (error) {
const loginUrl = new URL('/login', url);
loginUrl.searchParams.set('error', 'invalid_token');
loginUrl.searchParams.set('redirect', url.pathname);
return Response.redirect(loginUrl, 302);
}
};
async function validateToken(token) {
// Mock validation - replace with real token validation
return token.length > 10;
}
// 4. Rate limiting edge function
// edge-functions/rate-limit.js
export default async (request, context) => {
const url = new URL(request.url);
const clientIP = request.headers.get('x-nf-client-connection-ip') ||
request.headers.get('x-forwarded-for') ||
'unknown';
// Simple rate limiting logic (in production, use Redis or similar)
const RATE_LIMIT = 100; // requests per minute
const key = `rate-limit-${clientIP}`;
// This is a mock implementation
// In production, you'd use a proper rate limiting store
const now = Date.now();
const windowStart = now - 60000; // 1 minute ago
// Check rate limit (mock logic)
const requestCount = await getRequestCount(key, windowStart);
if (requestCount >= RATE_LIMIT) {
return new Response('Rate limit exceeded', {
status: 429,
headers: {
'Retry-After': '60',
'Content-Type': 'text/plain'
}
});
}
// Increment request count
await incrementRequestCount(key);
const response = await context.next();
response.headers.set('x-rate-limit-remaining', String(RATE_LIMIT - requestCount));
return response;
};
// Mock functions for rate limiting (replace with real implementation)
async function getRequestCount(key, windowStart) {
// Mock implementation
return Math.floor(Math.random() * 150);
}
async function incrementRequestCount(key) {
// Mock implementation
return Promise.resolve();
}
// 5. Content personalization edge function
// edge-functions/personalize.js
export default async (request, context) => {
const url = new URL(request.url);
// Skip personalization for API routes
if (url.pathname.startsWith('/api/')) {
return context.next();
}
// Get user preferences from cookie or headers
const preferences = getUserPreferences(request);
const response = await context.next();
// Inject personalization script
const personalizationScript = `
<script>
window.userPreferences = ${JSON.stringify(preferences)};
// Trigger personalization
window.dispatchEvent(new CustomEvent('userPreferencesLoaded', {
detail: window.userPreferences
}));
</script>
`;
// Insert script before closing body tag
const html = await response.text();
const personalizedHtml = html.replace(
'</body>',
personalizationScript + '</body>'
);
return new Response(personalizedHtml, {
headers: response.headers
});
};
function getUserPreferences(request) {
const cookieHeader = request.headers.get('cookie') || '';
// Parse preferences from cookies
const preferences = {
theme: 'light',
language: 'en',
region: 'us'
};
cookieHeader.split(';').forEach(cookie => {
const [name, value] = cookie.trim().split('=');
if (name === 'theme') preferences.theme = value || 'light';
if (name === 'language') preferences.language = value || 'en';
if (name === 'region') preferences.region = value || 'us';
});
// Override with geo data if available
if (request.geo?.country?.code) {
preferences.region = request.geo.country.code.toLowerCase();
}
return preferences;
}
// 6. Content security policy edge function
// edge-functions/csp.js
export default async (request, context) => {
const response = await context.next();
// Set Content Security Policy headers
const csp = [
"default-src 'self'",
"script-src 'self' 'unsafe-inline' 'unsafe-eval' https://cdn.jsdelivr.net https://vercel.live",
"style-src 'self' 'unsafe-inline' https://fonts.googleapis.com",
"font-src 'self' https://fonts.gstatic.com",
"img-src 'self' data: https: blob:",
"connect-src 'self' https://api.example.com",
"frame-ancestors 'none'",
"base-uri 'self'",
"form-action 'self'"
].join('; ');
response.headers.set('Content-Security-Policy', csp);
response.headers.set('X-Content-Type-Options', 'nosniff');
response.headers.set('X-Frame-Options', 'DENY');
response.headers.set('X-XSS-Protection', '1; mode=block');
response.headers.set('Referrer-Policy', 'strict-origin-when-cross-origin');
return response;
};
💻 Netlify Формы и Analytics html
🔴 complex
⭐⭐⭐⭐
Полная обработка форм, аналитика и автоматизированные рабочие процессы
⏱️ 40 min
🏷️ netlify, forms, analytics, frontend
Prerequisites:
HTML, JavaScript, Netlify forms, Analytics
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Netlify Forms & Analytics Example</title>
<style>
.form-container {
max-width: 600px;
margin: 2rem auto;
padding: 2rem;
border: 1px solid #ddd;
border-radius: 8px;
}
.form-group {
margin-bottom: 1rem;
}
label {
display: block;
margin-bottom: 0.5rem;
font-weight: bold;
}
input, textarea, select {
width: 100%;
padding: 0.5rem;
border: 1px solid #ccc;
border-radius: 4px;
}
button {
background: #007cba;
color: white;
padding: 0.75rem 1.5rem;
border: none;
border-radius: 4px;
cursor: pointer;
}
button:hover {
background: #005a87;
}
.form-netlify {
display: none;
}
.analytics-data {
background: #f5f5f5;
padding: 1rem;
border-radius: 4px;
margin: 2rem 0;
}
</style>
</head>
<body>
<!-- 1. Contact Form with Netlify Forms -->
<div class="form-container">
<h2>Contact Form</h2>
<form name="contact" method="POST" data-netlify="true" netlify-honeypot="bot-field">
<!-- Hidden field for spam protection -->
<input type="hidden" name="form-name" value="contact">
<div class="form-netlify">
<label>Don't fill this out if you're human: <input name="bot-field" /></label>
</div>
<div class="form-group">
<label for="name">Name *</label>
<input type="text" id="name" name="name" required>
</div>
<div class="form-group">
<label for="email">Email *</label>
<input type="email" id="email" name="email" required>
</div>
<div class="form-group">
<label for="subject">Subject</label>
<input type="text" id="subject" name="subject">
</div>
<div class="form-group">
<label for="message">Message *</label>
<textarea id="message" name="message" rows="5" required></textarea>
</div>
<div class="form-group">
<label for="interest">Area of Interest</label>
<select id="interest" name="interest">
<option value="">Select an option</option>
<option value="web-development">Web Development</option>
<option value="mobile-apps">Mobile Apps</option>
<option value="consulting">Consulting</option>
<option value="other">Other</option>
</select>
</div>
<div class="form-group">
<label>
<input type="checkbox" name="newsletter" value="yes">
Subscribe to newsletter
</label>
</div>
<button type="submit">Send Message</button>
</form>
</div>
<!-- 2. File Upload Form -->
<div class="form-container">
<h2>File Upload Form</h2>
<form name="upload" method="POST" data-netlify="true" enctype="multipart/form-data">
<input type="hidden" name="form-name" value="upload">
<div class="form-group">
<label for="file-name">Name</label>
<input type="text" id="file-name" name="name" required>
</div>
<div class="form-group">
<label for="file-email">Email</label>
<input type="email" id="file-email" name="email" required>
</div>
<div class="form-group">
<label for="file">Upload File (max 2MB)</label>
<input type="file" id="file" name="file" accept=".pdf,.doc,.docx,.txt" required>
</div>
<div class="form-group">
<label for="description">Description</label>
<textarea id="description" name="description" rows="3"></textarea>
</div>
<button type="submit">Upload File</button>
</form>
</div>
<!-- 3. Multi-step Form with Progressive Enhancement -->
<div class="form-container">
<h2>Multi-step Registration Form</h2>
<form name="registration" method="POST" data-netlify="true">
<input type="hidden" name="form-name" value="registration">
<!-- Step 1: Basic Information -->
<div id="step-1" class="form-step">
<h3>Step 1: Basic Information</h3>
<div class="form-group">
<label for="reg-name">Full Name *</label>
<input type="text" id="reg-name" name="full_name" required>
</div>
<div class="form-group">
<label for="reg-email">Email Address *</label>
<input type="email" id="reg-email" name="email_address" required>
</div>
<div class="form-group">
<label for="reg-phone">Phone Number</label>
<input type="tel" id="reg-phone" name="phone_number">
</div>
<button type="button" onclick="nextStep(2)">Next</button>
</div>
<!-- Step 2: Professional Information -->
<div id="step-2" class="form-step" style="display: none;">
<h3>Step 2: Professional Information</h3>
<div class="form-group">
<label for="company">Company</label>
<input type="text" id="company" name="company">
</div>
<div class="form-group">
<label for="position">Position</label>
<input type="text" id="position" name="position">
</div>
<div class="form-group">
<label for="experience">Years of Experience</label>
<select id="experience" name="experience">
<option value="0-1">0-1 years</option>
<option value="2-5">2-5 years</option>
<option value="6-10">6-10 years</option>
<option value="10+">10+ years</option>
</select>
</div>
<button type="button" onclick="nextStep(1)">Previous</button>
<button type="button" onclick="nextStep(3)">Next</button>
</div>
<!-- Step 3: Preferences -->
<div id="step-3" class="form-step" style="display: none;">
<h3>Step 3: Preferences</h3>
<div class="form-group">
<label for="interests">Areas of Interest</label>
<div>
<label>
<input type="checkbox" name="interests" value="design"> Design
</label>
<label>
<input type="checkbox" name="interests" value="development"> Development
</label>
<label>
<input type="checkbox" name="interests" value="marketing"> Marketing
</label>
</div>
</div>
<div class="form-group">
<label for="hear-about">How did you hear about us?</label>
<select id="hear-about" name="hear_about">
<option value="">Select an option</option>
<option value="search">Search Engine</option>
<option value="social">Social Media</option>
<option value="referral">Referral</option>
<option value="advertisement">Advertisement</option>
<option value="other">Other</option>
</select>
</div>
<div class="form-group">
<label for="comments">Additional Comments</label>
<textarea id="comments" name="comments" rows="4"></textarea>
</div>
<button type="button" onclick="nextStep(2)">Previous</button>
<button type="submit">Submit Registration</button>
</div>
</form>
</div>
<!-- 4. Analytics Data Display -->
<div class="analytics-data">
<h3>Real-time Analytics Data</h3>
<div id="visitor-info">
<p><strong>Location:</strong> <span id="location">Loading...</span></p>
<p><strong>Device:</strong> <span id="device">Loading...</span></p>
<p><strong>Browser:</strong> <span id="browser">Loading...</span></p>
<p><strong>Session ID:</strong> <span id="session-id">Loading...</span></p>
</div>
</div>
<!-- Netlify Analytics Script -->
<script>
// Initialize Netlify Analytics
if (typeof netlifyAnalytics !== 'undefined') {
netlifyAnalytics.on('routeChange', ({ path }) => {
console.log('Route changed to:', path);
});
}
</script>
<!-- 5. Form Handling Script -->
<script>
// Multi-step form logic
function nextStep(stepNumber) {
// Hide all steps
document.querySelectorAll('.form-step').forEach(step => {
step.style.display = 'none';
});
// Show selected step
document.getElementById(`step-${stepNumber}`).style.display = 'block';
}
// Form submission handling
document.querySelectorAll('form').forEach(form => {
form.addEventListener('submit', function(e) {
// Show loading state
const submitBtn = this.querySelector('button[type="submit"]');
const originalText = submitBtn.textContent;
submitBtn.textContent = 'Submitting...';
submitBtn.disabled = true;
// Track form submission
if (typeof netlifyAnalytics !== 'undefined') {
netlifyAnalytics.track({
eventName: 'form_submission',
data: {
formName: this.getAttribute('name'),
timestamp: new Date().toISOString()
}
});
}
// Let the form submit normally to Netlify
setTimeout(() => {
submitBtn.textContent = originalText;
submitBtn.disabled = false;
}, 3000);
});
});
// Load visitor information
async function loadVisitorInfo() {
try {
// Simulate visitor data (in real app, this would come from Netlify Functions)
const visitorData = {
location: await getLocation(),
device: getDeviceInfo(),
browser: getBrowserInfo(),
sessionId: getSessionId()
};
document.getElementById('location').textContent = visitorData.location;
document.getElementById('device').textContent = visitorData.device;
document.getElementById('browser').textContent = visitorData.browser;
document.getElementById('session-id').textContent = visitorData.sessionId;
} catch (error) {
console.error('Error loading visitor info:', error);
}
}
async function getLocation() {
// In production, you'd use Netlify Functions to get geo data
// For now, return a mock location
return 'San Francisco, CA, USA';
}
function getDeviceInfo() {
const userAgent = navigator.userAgent;
if (/Mobile|Android|iPhone|iPad/.test(userAgent)) {
return 'Mobile';
} else if (/Tablet/.test(userAgent)) {
return 'Tablet';
} else {
return 'Desktop';
}
}
function getBrowserInfo() {
const userAgent = navigator.userAgent;
if (userAgent.includes('Chrome')) return 'Chrome';
if (userAgent.includes('Firefox')) return 'Firefox';
if (userAgent.includes('Safari')) return 'Safari';
if (userAgent.includes('Edge')) return 'Edge';
return 'Unknown';
}
function getSessionId() {
// Get or create session ID from local storage
let sessionId = localStorage.getItem('netlify_session_id');
if (!sessionId) {
sessionId = 'session_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
localStorage.setItem('netlify_session_id', sessionId);
}
return sessionId;
}
// Load visitor info when page loads
document.addEventListener('DOMContentLoaded', loadVisitorInfo);
// Track page view
if (typeof netlifyAnalytics !== 'undefined') {
netlifyAnalytics.track({
eventName: 'page_view',
data: {
path: window.location.pathname,
title: document.title,
timestamp: new Date().toISOString()
}
});
}
// Track form interactions
document.querySelectorAll('input, textarea, select').forEach(field => {
field.addEventListener('focus', function() {
if (typeof netlifyAnalytics !== 'undefined') {
netlifyAnalytics.track({
eventName: 'form_field_focus',
data: {
fieldName: this.name,
fieldType: this.type,
timestamp: new Date().toISOString()
}
});
}
});
});
</script>
</body>
</html>