netlify-deployment-platform
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseNetlify Platform Skill
Netlify 平台技能
progressive_disclosure: entry_point: summary: "JAMstack deployment platform with serverless functions, forms, and identity" when_to_use: - "When deploying static sites and SPAs" - "When building JAMstack applications" - "When needing serverless functions" - "When requiring built-in forms and auth" quick_start: - "npm install -g netlify-cli" - "netlify login" - "netlify init" - "netlify deploy --prod" token_estimate: entry: 70-85 full: 3800-4800
progressive_disclosure: entry_point: summary: "JAMstack 部署平台,包含无服务器函数、表单和身份验证功能" when_to_use: - "部署静态网站和单页应用(SPA)时" - "构建JAMstack应用程序时" - "需要无服务器函数时" - "需要内置表单和身份验证时" quick_start: - "npm install -g netlify-cli" - "netlify login" - "netlify init" - "netlify deploy --prod" token_estimate: entry: 70-85 full: 3800-4800
Netlify Fundamentals
Netlify 基础概念
Core Concepts
核心概念
- Sites: Static sites deployed to Netlify's global CDN
- Builds: Automated build process triggered by Git commits
- Deploy Contexts: production, deploy-preview, branch-deploy
- Atomic Deploys: All-or-nothing deployments with instant rollback
- Instant Cache Invalidation: CDN cache cleared automatically
- Sites: 部署到Netlify全球CDN的静态网站
- Builds: 由Git提交触发的自动化构建流程
- Deploy Contexts: production(生产环境)、deploy-preview(部署预览)、branch-deploy(分支部署)
- Atomic Deploys: 全量生效或回退的原子化部署,支持即时回滚
- Instant Cache Invalidation: CDN缓存自动清除
Platform Benefits
平台优势
- Global CDN: Built-in content delivery network
- Continuous Deployment: Auto-deploy from Git
- HTTPS by Default: Free SSL certificates
- Deploy Previews: Preview every pull request
- Serverless Functions: Backend logic without servers
- Forms & Identity: Built-in features for common needs
- Global CDN: 内置内容分发网络
- Continuous Deployment: 从Git自动部署
- HTTPS by Default: 免费SSL证书
- Deploy Previews: 预览每个拉取请求的效果
- Serverless Functions: 无需服务器的后端逻辑
- Forms & Identity: 满足常见需求的内置功能
Static Site Deployment
静态站点部署
Supported Frameworks
支持的框架
bash
undefinedbash
undefinedReact (Create React App, Vite)
React (Create React App, Vite)
Build command: npm run build
Publish directory: build (CRA) or dist (Vite)
Build command: npm run build
Publish directory: build (CRA) or dist (Vite)
Next.js (Static Export)
Next.js (Static Export)
Build command: npm run build && npm run export
Publish directory: out
Build command: npm run build && npm run export
Publish directory: out
Vue.js
Vue.js
Build command: npm run build
Publish directory: dist
Build command: npm run build
Publish directory: dist
Gatsby
Gatsby
Build command: gatsby build
Publish directory: public
Build command: gatsby build
Publish directory: public
Hugo
Hugo
Build command: hugo
Publish directory: public
Build command: hugo
Publish directory: public
Svelte/SvelteKit
Svelte/SvelteKit
Build command: npm run build
Publish directory: build
undefinedBuild command: npm run build
Publish directory: build
undefinedManual Deployment
手动部署
bash
undefinedbash
undefinedInstall Netlify CLI
安装Netlify CLI
npm install -g netlify-cli
npm install -g netlify-cli
Login to Netlify
登录Netlify
netlify login
netlify login
Initialize site
初始化站点
netlify init
netlify init
Deploy draft (preview URL)
部署草稿版本(预览URL)
netlify deploy
netlify deploy
Deploy to production
部署到生产环境
netlify deploy --prod
netlify deploy --prod
Deploy with build
构建并部署
netlify deploy --build --prod
undefinednetlify deploy --build --prod
undefinednetlify.toml Configuration
netlify.toml 配置
Basic Configuration
基础配置
toml
undefinedtoml
undefinednetlify.toml
netlify.toml
[build]
Build command
command = "npm run build"
Publish directory
publish = "dist"
Functions directory
functions = "netlify/functions"
[build]
构建命令
command = "npm run build"
发布目录
publish = "dist"
函数目录
functions = "netlify/functions"
Production context
生产环境上下文
[context.production]
command = "npm run build:prod"
[context.production.environment]
NODE_ENV = "production"
API_URL = "https://api.example.com"
[context.production]
command = "npm run build:prod"
[context.production.environment]
NODE_ENV = "production"
API_URL = "https://api.example.com"
Deploy Preview context
部署预览上下文
[context.deploy-preview]
command = "npm run build:preview"
[context.deploy-preview]
command = "npm run build:preview"
Branch deploys
分支部署
[context.branch-deploy]
command = "npm run build"
undefined[context.branch-deploy]
command = "npm run build"
undefinedBuild Settings
构建设置
toml
[build]
command = "npm run build"
publish = "dist"
# Base directory for monorepos
base = "packages/web"
# Ignore builds on certain changes
ignore = "git diff --quiet $CACHED_COMMIT_REF $COMMIT_REF packages/web"
[build.environment]
NODE_VERSION = "18"
NPM_VERSION = "9"
RUBY_VERSION = "3.1"toml
[build]
command = "npm run build"
publish = "dist"
# 单仓库多项目(Monorepo)的基础目录
base = "packages/web"
# 特定变更时跳过构建
ignore = "git diff --quiet $CACHED_COMMIT_REF $COMMIT_REF packages/web"
[build.environment]
NODE_VERSION = "18"
NPM_VERSION = "9"
RUBY_VERSION = "3.1"Advanced Build Configuration
高级构建配置
toml
[build]
command = "npm run build"
publish = "dist"
# Build processing
[build.processing]
skip_processing = false
[build.processing.css]
bundle = true
minify = true
[build.processing.js]
bundle = true
minify = true
[build.processing.images]
compress = truetoml
[build]
command = "npm run build"
publish = "dist"
# 构建处理
[build.processing]
skip_processing = false
[build.processing.css]
bundle = true
minify = true
[build.processing.js]
bundle = true
minify = true
[build.processing.images]
compress = trueEnvironment Variables
环境变量
Setting Variables
设置变量
bash
undefinedbash
undefinedVia CLI
通过CLI设置
netlify env:set API_KEY "secret-value"
netlify env:set NODE_ENV "production"
netlify env:set API_KEY "secret-value"
netlify env:set NODE_ENV "production"
List variables
列出变量
netlify env:list
netlify env:list
Import from .env file
从.env文件导入
netlify env:import .env
undefinednetlify env:import .env
undefinedVariable Scopes
变量作用域
toml
undefinedtoml
undefinednetlify.toml
netlify.toml
[context.production.environment]
API_URL = "https://api.production.com"
ENABLE_ANALYTICS = "true"
[context.deploy-preview.environment]
API_URL = "https://api.staging.com"
ENABLE_ANALYTICS = "false"
[context.branch-deploy.environment]
API_URL = "https://api.dev.com"
undefined[context.production.environment]
API_URL = "https://api.production.com"
ENABLE_ANALYTICS = "true"
[context.deploy-preview.environment]
API_URL = "https://api.staging.com"
ENABLE_ANALYTICS = "false"
[context.branch-deploy.environment]
API_URL = "https://api.dev.com"
undefinedAccessing in Build
构建时访问变量
javascript
// During build
const apiUrl = process.env.API_URL;
// Client-side (must be prefixed)
const publicKey = process.env.REACT_APP_PUBLIC_KEY;javascript
// 构建过程中访问
const apiUrl = process.env.API_URL;
// 客户端访问(必须添加前缀)
const publicKey = process.env.REACT_APP_PUBLIC_KEY;Serverless Functions
无服务器函数
Function Structure
函数结构
javascript
// netlify/functions/hello.js
exports.handler = async (event, context) => {
return {
statusCode: 200,
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
message: 'Hello from Netlify Function',
path: event.path,
method: event.httpMethod,
}),
};
};javascript
// netlify/functions/hello.js
exports.handler = async (event, context) => {
return {
statusCode: 200,
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
message: 'Hello from Netlify Function',
path: event.path,
method: event.httpMethod,
}),
};
};TypeScript Functions
TypeScript 函数
typescript
// netlify/functions/api.ts
import { Handler, HandlerEvent, HandlerContext } from '@netlify/functions';
interface RequestBody {
name: string;
email: string;
}
export const handler: Handler = async (
event: HandlerEvent,
context: HandlerContext
) => {
if (event.httpMethod !== 'POST') {
return {
statusCode: 405,
body: 'Method Not Allowed',
};
}
const { name, email }: RequestBody = JSON.parse(event.body || '{}');
return {
statusCode: 200,
body: JSON.stringify({
message: `Hello ${name}`,
email,
}),
};
};typescript
// netlify/functions/api.ts
import { Handler, HandlerEvent, HandlerContext } from '@netlify/functions';
interface RequestBody {
name: string;
email: string;
}
export const handler: Handler = async (
event: HandlerEvent,
context: HandlerContext
) => {
if (event.httpMethod !== 'POST') {
return {
statusCode: 405,
body: 'Method Not Allowed',
};
}
const { name, email }: RequestBody = JSON.parse(event.body || '{}');
return {
statusCode: 200,
body: JSON.stringify({
message: `Hello ${name}`,
email,
}),
};
};Advanced Function Patterns
高级函数模式
javascript
// netlify/functions/database.js
const { MongoClient } = require('mongodb');
let cachedDb = null;
async function connectToDatabase() {
if (cachedDb) return cachedDb;
const client = await MongoClient.connect(process.env.MONGODB_URI);
cachedDb = client.db();
return cachedDb;
}
exports.handler = async (event) => {
const db = await connectToDatabase();
const users = await db.collection('users').find({}).toArray();
return {
statusCode: 200,
body: JSON.stringify(users),
};
};javascript
// netlify/functions/database.js
const { MongoClient } = require('mongodb');
let cachedDb = null;
async function connectToDatabase() {
if (cachedDb) return cachedDb;
const client = await MongoClient.connect(process.env.MONGODB_URI);
cachedDb = client.db();
return cachedDb;
}
exports.handler = async (event) => {
const db = await connectToDatabase();
const users = await db.collection('users').find({}).toArray();
return {
statusCode: 200,
body: JSON.stringify(users),
};
};Scheduled Functions
定时函数
javascript
// netlify/functions/scheduled.js
const { schedule } = require('@netlify/functions');
const handler = async () => {
console.log('Running scheduled task');
// Your scheduled logic
await performBackup();
return {
statusCode: 200,
};
};
// Run every day at midnight
exports.handler = schedule('0 0 * * *', handler);javascript
// netlify/functions/scheduled.js
const { schedule } = require('@netlify/functions');
const handler = async () => {
console.log('Running scheduled task');
// 你的定时任务逻辑
await performBackup();
return {
statusCode: 200,
};
};
// 每天午夜运行
exports.handler = schedule('0 0 * * *', handler);Background Functions
后台函数
javascript
// netlify/functions/background-task.js
// Auto-runs in background if response is 200 within 10s
exports.handler = async (event) => {
// Long-running task
await processLargeDataset();
return {
statusCode: 200,
};
};
// Invoke: POST to /.netlify/functions/background-taskjavascript
// netlify/functions/background-task.js
// 如果10秒内返回200,则自动在后台运行
exports.handler = async (event) => {
// 长时间运行的任务
await processLargeDataset();
return {
statusCode: 200,
};
};
// 调用方式:POST请求到 /.netlify/functions/background-taskNetlify Forms
Netlify 表单
HTML Form
HTML 表单
html
<!-- Contact form -->
<form name="contact" method="POST" data-netlify="true">
<input type="hidden" name="form-name" value="contact" />
<label>Name: <input type="text" name="name" required /></label>
<label>Email: <input type="email" name="email" required /></label>
<label>Message: <textarea name="message" required></textarea></label>
<button type="submit">Send</button>
</form>html
<!-- 联系表单 -->
<form name="contact" method="POST" data-netlify="true">
<input type="hidden" name="form-name" value="contact" />
<label>姓名: <input type="text" name="name" required /></label>
<label>邮箱: <input type="email" name="email" required /></label>
<label>留言: <textarea name="message" required></textarea></label>
<button type="submit">发送</button>
</form>React Form
React 表单
jsx
// ContactForm.jsx
import { useState } from 'react';
export default function ContactForm() {
const [formData, setFormData] = useState({
name: '',
email: '',
message: '',
});
const handleSubmit = async (e) => {
e.preventDefault();
const response = await fetch('/', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
'form-name': 'contact',
...formData,
}).toString(),
});
if (response.ok) {
alert('Thank you for your message!');
}
};
return (
<form name="contact" onSubmit={handleSubmit} data-netlify="true">
<input type="hidden" name="form-name" value="contact" />
{/* Form fields */}
</form>
);
}jsx
// ContactForm.jsx
import { useState } from 'react';
export default function ContactForm() {
const [formData, setFormData] = useState({
name: '',
email: '',
message: '',
});
const handleSubmit = async (e) => {
e.preventDefault();
const response = await fetch('/', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
'form-name': 'contact',
...formData,
}).toString(),
});
if (response.ok) {
alert('感谢您的留言!');
}
};
return (
<form name="contact" onSubmit={handleSubmit} data-netlify="true">
<input type="hidden" name="form-name" value="contact" />
{/* 表单字段 */}
</form>
);
}Form Features
表单功能
html
<!-- Spam filtering with honeypot -->
<form name="contact" method="POST" data-netlify="true" data-netlify-honeypot="bot-field">
<input type="hidden" name="form-name" value="contact" />
<p class="hidden">
<label>Don't fill this out: <input name="bot-field" /></label>
</p>
<!-- Form fields -->
</form>
<!-- reCAPTCHA v2 -->
<form name="contact" method="POST" data-netlify="true" data-netlify-recaptcha="true">
<div data-netlify-recaptcha="true"></div>
<button type="submit">Submit</button>
</form>
<!-- File uploads -->
<form name="file-upload" method="POST" data-netlify="true" enctype="multipart/form-data">
<input type="file" name="file" />
<button type="submit">Upload</button>
</form>html
<!-- 使用蜜罐字段过滤垃圾信息 -->
<form name="contact" method="POST" data-netlify="true" data-netlify-honeypot="bot-field">
<input type="hidden" name="form-name" value="contact" />
<p class="hidden">
<label>请不要填写此字段: <input name="bot-field" /></label>
</p>
<!-- 表单字段 -->
</form>
<!-- reCAPTCHA v2 -->
<form name="contact" method="POST" data-netlify="true" data-netlify-recaptcha="true">
<div data-netlify-recaptcha="true"></div>
<button type="submit">提交</button>
</form>
<!-- 文件上传 -->
<form name="file-upload" method="POST" data-netlify="true" enctype="multipart/form-data">
<input type="file" name="file" />
<button type="submit">上传</button>
</form>Form Notifications
表单通知
toml
undefinedtoml
undefinednetlify.toml
netlify.toml
[[plugins]]
package = "@netlify/plugin-emails"
[plugins.inputs]
formName = "contact"
to = "admin@example.com"
subject = "New contact form submission"
undefined[[plugins]]
package = "@netlify/plugin-emails"
[plugins.inputs]
formName = "contact"
to = "admin@example.com"
subject = "新的联系表单提交"
undefinedNetlify Identity
Netlify 身份验证
Enable Identity
启用身份验证
javascript
// Add to HTML
<script src="https://identity.netlify.com/v1/netlify-identity-widget.js"></script>
// Initialize
if (window.netlifyIdentity) {
window.netlifyIdentity.on('init', user => {
if (!user) {
window.netlifyIdentity.on('login', () => {
document.location.href = '/admin/';
});
}
});
}javascript
<!-- 添加到HTML中 -->
<script src="https://identity.netlify.com/v1/netlify-identity-widget.js"></script>
<!-- 初始化 -->
if (window.netlifyIdentity) {
window.netlifyIdentity.on('init', user => {
if (!user) {
window.netlifyIdentity.on('login', () => {
document.location.href = '/admin/';
});
}
});
}React Integration
React 集成
jsx
// useNetlifyIdentity.js
import { useEffect, useState } from 'react';
export function useNetlifyIdentity() {
const [user, setUser] = useState(null);
useEffect(() => {
const netlifyIdentity = window.netlifyIdentity;
netlifyIdentity.on('init', user => setUser(user));
netlifyIdentity.on('login', user => setUser(user));
netlifyIdentity.on('logout', () => setUser(null));
netlifyIdentity.init();
}, []);
return {
user,
login: () => window.netlifyIdentity.open('login'),
logout: () => window.netlifyIdentity.logout(),
signup: () => window.netlifyIdentity.open('signup'),
};
}jsx
// useNetlifyIdentity.js
import { useEffect, useState } from 'react';
export function useNetlifyIdentity() {
const [user, setUser] = useState(null);
useEffect(() => {
const netlifyIdentity = window.netlifyIdentity;
netlifyIdentity.on('init', user => setUser(user));
netlifyIdentity.on('login', user => setUser(user));
netlifyIdentity.on('logout', () => setUser(null));
netlifyIdentity.init();
}, []);
return {
user,
login: () => window.netlifyIdentity.open('login'),
logout: () => window.netlifyIdentity.logout(),
signup: () => window.netlifyIdentity.open('signup'),
};
}Protected Functions
受保护的函数
javascript
// netlify/functions/protected.js
exports.handler = async (event, context) => {
const { user } = context.clientContext;
if (!user) {
return {
statusCode: 401,
body: 'Unauthorized',
};
}
return {
statusCode: 200,
body: JSON.stringify({
message: 'Protected data',
user: user.email,
}),
};
};javascript
// netlify/functions/protected.js
exports.handler = async (event, context) => {
const { user } = context.clientContext;
if (!user) {
return {
statusCode: 401,
body: '未授权',
};
}
return {
statusCode: 200,
body: JSON.stringify({
message: '受保护的数据',
user: user.email,
}),
};
};Redirects and Rewrites
重定向与重写
_redirects File
_redirects 文件
text
undefinedtext
undefined_redirects file in publish directory
发布目录下的_redirects文件
Redirect with status code
带状态码的重定向
/old-path /new-path 301
/old-path /new-path 301
Rewrite (proxy)
重写(代理)
/api/* https://api.example.com/:splat 200
/api/* https://api.example.com/:splat 200
SPA fallback
SPA 回退
/* /index.html 200
/* /index.html 200
Force HTTPS
强制HTTPS
Conditional redirects
条件重定向
/news/* /blog/:splat 302 Country=us
/news/* /blog/:splat 302 Country=us
Role-based redirects
基于角色的重定向
/admin/* /admin/dashboard 200! Role=admin
/admin/* /unauthorized 401
undefined/admin/* /admin/dashboard 200! Role=admin
/admin/* /unauthorized 401
undefinednetlify.toml Redirects
netlify.toml 重定向
toml
[[redirects]]
from = "/old-path"
to = "/new-path"
status = 301
[[redirects]]
from = "/api/*"
to = "https://api.example.com/:splat"
status = 200
force = true
[[redirects]]
from = "/*"
to = "/index.html"
status = 200
[[redirects]]
from = "/admin/*"
to = "/admin/dashboard"
status = 200
conditions = {Role = ["admin"]}toml
[[redirects]]
from = "/old-path"
to = "/new-path"
status = 301
[[redirects]]
from = "/api/*"
to = "https://api.example.com/:splat"
status = 200
force = true
[[redirects]]
from = "/*"
to = "/index.html"
status = 200
[[redirects]]
from = "/admin/*"
to = "/admin/dashboard"
status = 200
conditions = {Role = ["admin"]}Proxy with headers
带请求头的代理
[[redirects]]
from = "/proxy/*"
to = "https://backend.com/:splat"
status = 200
force = true
[redirects.headers]
X-From = "Netlify"
undefined[[redirects]]
from = "/proxy/*"
to = "https://backend.com/:splat"
status = 200
force = true
[redirects.headers]
X-From = "Netlify"
undefinedCustom Headers
自定义请求头
toml
[[headers]]
for = "/*"
[headers.values]
X-Frame-Options = "DENY"
X-XSS-Protection = "1; mode=block"
Content-Security-Policy = "default-src 'self'"
[[headers]]
for = "/assets/*"
[headers.values]
Cache-Control = "public, max-age=31536000, immutable"toml
[[headers]]
for = "/*"
[headers.values]
X-Frame-Options = "DENY"
X-XSS-Protection = "1; mode=block"
Content-Security-Policy = "default-src 'self'"
[[headers]]
for = "/assets/*"
[headers.values]
Cache-Control = "public, max-age=31536000, immutable"Deploy Previews
部署预览
Automatic Preview URLs
自动预览URL
toml
undefinedtoml
undefinednetlify.toml
netlify.toml
[context.deploy-preview]
command = "npm run build:preview"
[context.deploy-preview.environment]
NODE_ENV = "preview"
API_URL = "https://api-staging.example.com"
undefined[context.deploy-preview]
command = "npm run build:preview"
[context.deploy-preview.environment]
NODE_ENV = "preview"
API_URL = "https://api-staging.example.com"
undefinedBranch Deploys
分支部署
toml
undefinedtoml
undefinedDeploy specific branches
部署特定分支
[context.staging]
command = "npm run build:staging"
[context.staging.environment]
API_URL = "https://api-staging.example.com"
[context.staging]
command = "npm run build:staging"
[context.staging.environment]
API_URL = "https://api-staging.example.com"
Branch pattern matching
分支模式匹配
[context.branch-deploy]
command = "npm run build"
undefined[context.branch-deploy]
command = "npm run build"
undefinedDeploy Notifications
部署通知
bash
undefinedbash
undefinedGitHub PR comments
GitHub PR评论
Slack notifications
Slack通知
Email notifications
邮件通知
Configured in Netlify UI
在Netlify UI中配置
undefinedundefinedSplit Testing (A/B Testing)
拆分测试(A/B测试)
Configuration
配置
toml
undefinedtoml
undefinednetlify.toml
netlify.toml
[[redirects]]
from = "/*"
to = "/version-a/:splat"
status = 200
conditions = {Cookie = ["ab_test=a"]}
force = true
[[redirects]]
from = "/*"
to = "/version-b/:splat"
status = 200
conditions = {Cookie = ["ab_test=b"]}
force = true
[[redirects]]
from = "/*"
to = "/version-a/:splat"
status = 200
conditions = {Cookie = ["ab_test=a"]}
force = true
[[redirects]]
from = "/*"
to = "/version-b/:splat"
status = 200
conditions = {Cookie = ["ab_test=b"]}
force = true
50/50 split
50/50 拆分
[[redirects]]
from = "/*"
to = "/version-a/:splat"
status = 200!
percentage = 50
[[redirects]]
from = "/*"
to = "/version-b/:splat"
status = 200!
undefined[[redirects]]
from = "/*"
to = "/version-a/:splat"
status = 200!
percentage = 50
[[redirects]]
from = "/*"
to = "/version-b/:splat"
status = 200!
undefinedEdge Functions
Edge Functions
Deno Runtime
Deno 运行时
typescript
// netlify/edge-functions/hello.ts
import type { Context } from "https://edge.netlify.com";
export default async (request: Request, context: Context) => {
const url = new URL(request.url);
return new Response(`Hello from ${url.pathname}`, {
headers: { "content-type": "text/html" },
});
};
export const config = { path: "/hello" };typescript
// netlify/edge-functions/hello.ts
import type { Context } from "https://edge.netlify.com";
export default async (request: Request, context: Context) => {
const url = new URL(request.url);
return new Response(`Hello from ${url.pathname}`, {
headers: { "content-type": "text/html" },
});
};
export const config = { path: "/hello" };Geolocation
地理位置
typescript
// netlify/edge-functions/geo.ts
import type { Context } from "https://edge.netlify.com";
export default async (request: Request, context: Context) => {
const { city, country } = context.geo;
return Response.json({
location: `${city}, ${country}`,
});
};typescript
// netlify/edge-functions/geo.ts
import type { Context } from "https://edge.netlify.com";
export default async (request: Request, context: Context) => {
const { city, country } = context.geo;
return Response.json({
location: `${city}, ${country}`,
});
};Transform Response
响应转换
typescript
// netlify/edge-functions/transform.ts
import type { Context } from "https://edge.netlify.com";
export default async (request: Request, context: Context) => {
const response = await context.next();
const text = await response.text();
// Modify HTML
const modified = text.replace(
'</body>',
'<script>console.log("Injected by edge");</script></body>'
);
return new Response(modified, response);
};
export const config = { path: "/*" };typescript
// netlify/edge-functions/transform.ts
import type { Context } from "https://edge.netlify.com";
export default async (request: Request, context: Context) => {
const response = await context.next();
const text = await response.text();
// 修改HTML
const modified = text.replace(
'</body>',
'<script>console.log("由Edge函数注入");</script></body>'
);
return new Response(modified, response);
};
export const config = { path: "/*" };Custom Domains and SSL
自定义域名与SSL
Add Custom Domain
添加自定义域名
bash
undefinedbash
undefinedVia CLI
通过CLI添加
netlify domains:add example.com
netlify domains:add example.com
DNS Configuration
DNS配置
A record: 75.2.60.5
A记录: 75.2.60.5
CNAME: <site-name>.netlify.app
CNAME: <site-name>.netlify.app
Verify domain
验证域名
netlify domains:verify example.com
undefinednetlify domains:verify example.com
undefinedSSL Certificates
SSL证书
toml
undefinedtoml
undefinedAutomatic HTTPS (default)
自动HTTPS(默认开启)
Free Let's Encrypt certificates
免费的Let's Encrypt证书
Auto-renewal
自动续期
Force HTTPS redirect
强制HTTPS重定向
[[redirects]]
from = "http://example.com/*"
to = "https://example.com/:splat"
status = 301
force = true
undefined[[redirects]]
from = "http://example.com/*"
to = "https://example.com/:splat"
status = 301
force = true
undefinedAnalytics
分析功能
Netlify Analytics
Netlify 分析
html
<!-- Automatically injected, no code needed -->
<!-- Server-side analytics, no client-side JS -->html
<!-- 自动注入,无需额外代码 -->
<!-- 服务端分析,无需客户端JS -->Custom Analytics
自定义分析
javascript
// Track custom events
function trackEvent(eventName, data) {
fetch('/.netlify/functions/analytics', {
method: 'POST',
body: JSON.stringify({ event: eventName, ...data }),
});
}
trackEvent('button_click', { button: 'signup' });javascript
// 跟踪自定义事件
function trackEvent(eventName, data) {
fetch('/.netlify/functions/analytics', {
method: 'POST',
body: JSON.stringify({ event: eventName, ...data }),
});
}
trackEvent('button_click', { button: 'signup' });CLI Advanced Usage
CLI 高级用法
Development Server
开发服务器
bash
undefinedbash
undefinedRun functions locally
本地运行函数
netlify dev
netlify dev
Specific port
指定端口
netlify dev --port 3000
netlify dev --port 3000
Live session sharing
实时会话共享
netlify dev --live
netlify dev --live
Functions only
仅运行函数
netlify functions:serve
undefinednetlify functions:serve
undefinedSite Management
站点管理
bash
undefinedbash
undefinedLink existing site
关联已有站点
netlify link
netlify link
Create new site
创建新站点
netlify sites:create
netlify sites:create
List sites
列出所有站点
netlify sites:list
netlify sites:list
Site info
站点信息
netlify status
netlify status
Open site in browser
在浏览器中打开站点
netlify open
undefinednetlify open
undefinedDeploy Management
部署管理
bash
undefinedbash
undefinedList deploys
列出所有部署
netlify deploy:list
netlify deploy:list
Rollback to previous deploy
回滚到上一个部署版本
netlify rollback
netlify rollback
Cancel deploy
取消部署
netlify deploy:cancel <deploy-id>
undefinednetlify deploy:cancel <deploy-id>
undefinedGit Integration
Git 集成
Continuous Deployment
持续部署
toml
undefinedtoml
undefinednetlify.toml
netlify.toml
[build]
command = "npm run build"
publish = "dist"
[build]
command = "npm run build"
publish = "dist"
Auto-publish on Git push
Git推送时自动发布
Production: main/master branch
生产环境:main/master分支
Previews: all pull requests
预览环境:所有拉取请求
Branch deploys: configured branches
分支部署:已配置的分支
undefinedundefinedDeploy Hooks
部署钩子
bash
undefinedbash
undefinedTrigger builds via webhook
通过Webhook触发构建
curl -X POST -d {} https://api.netlify.com/build_hooks/<hook-id>
curl -X POST -d {} https://api.netlify.com/build_hooks/<hook-id>
Scheduled builds (use external cron + webhook)
定时构建(使用外部定时任务 + Webhook)
undefinedundefinedBest Practices
最佳实践
Performance Optimization
性能优化
toml
undefinedtoml
undefinedEnable processing
启用处理
[build.processing]
skip_processing = false
[build.processing.css]
bundle = true
minify = true
[build.processing.js]
bundle = true
minify = true
[build.processing.images]
compress = true
[build.processing]
skip_processing = false
[build.processing.css]
bundle = true
minify = true
[build.processing.js]
bundle = true
minify = true
[build.processing.images]
compress = true
Asset optimization
资源优化
[[headers]]
for = "/assets/*"
[headers.values]
Cache-Control = "public, max-age=31536000, immutable"
undefined[[headers]]
for = "/assets/*"
[headers.values]
Cache-Control = "public, max-age=31536000, immutable"
undefinedSecurity Headers
安全请求头
toml
[[headers]]
for = "/*"
[headers.values]
X-Frame-Options = "DENY"
X-Content-Type-Options = "nosniff"
X-XSS-Protection = "1; mode=block"
Referrer-Policy = "strict-origin-when-cross-origin"
Permissions-Policy = "geolocation=(), microphone=(), camera=()"
Content-Security-Policy = """
default-src 'self';
script-src 'self' 'unsafe-inline';
style-src 'self' 'unsafe-inline';
img-src 'self' data: https:;
font-src 'self' data:;
"""toml
[[headers]]
for = "/*"
[headers.values]
X-Frame-Options = "DENY"
X-Content-Type-Options = "nosniff"
X-XSS-Protection = "1; mode=block"
Referrer-Policy = "strict-origin-when-cross-origin"
Permissions-Policy = "geolocation=(), microphone=(), camera=()"
Content-Security-Policy = """
default-src 'self';
script-src 'self' 'unsafe-inline';
style-src 'self' 'unsafe-inline';
img-src 'self' data: https:;
font-src 'self' data:;
"""Function Best Practices
函数最佳实践
javascript
// Keep functions lightweight
// Use connection pooling
// Cache external API responses
// Set appropriate timeouts
// Handle errors gracefully
exports.handler = async (event) => {
try {
// Set timeout
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 8000);
const response = await fetch(API_URL, {
signal: controller.signal,
});
clearTimeout(timeout);
return {
statusCode: 200,
body: JSON.stringify(await response.json()),
};
} catch (error) {
console.error('Function error:', error);
return {
statusCode: 500,
body: JSON.stringify({ error: 'Internal server error' }),
};
}
};javascript
// 保持函数轻量化
// 使用连接池
// 缓存外部API响应
// 设置合适的超时时间
// 优雅处理错误
exports.handler = async (event) => {
try {
// 设置超时
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 8000);
const response = await fetch(API_URL, {
signal: controller.signal,
});
clearTimeout(timeout);
return {
statusCode: 200,
body: JSON.stringify(await response.json()),
};
} catch (error) {
console.error('函数错误:', error);
return {
statusCode: 500,
body: JSON.stringify({ error: '内部服务器错误' }),
};
}
};Build Optimization
构建优化
toml
[build]
command = "npm run build"
publish = "dist"
# Skip builds when not needed
ignore = """
git diff --quiet $CACHED_COMMIT_REF $COMMIT_REF -- . ':(exclude)docs/' ':(exclude)*.md'
"""toml
[build]
command = "npm run build"
publish = "dist"
# 无需构建时跳过
ignore = """
git diff --quiet $CACHED_COMMIT_REF $COMMIT_REF -- . ':(exclude)docs/' ':(exclude)*.md'
"""Cache dependencies
缓存依赖
[build.environment]
NPM_FLAGS = "--legacy-peer-deps"
NODE_OPTIONS = "--max-old-space-size=4096"
undefined[build.environment]
NPM_FLAGS = "--legacy-peer-deps"
NODE_OPTIONS = "--max-old-space-size=4096"
undefinedMonorepo Support
单仓库多项目(Monorepo)支持
toml
undefinedtoml
undefinednetlify.toml
netlify.toml
[build]
base = "packages/web"
command = "npm run build"
publish = "dist"
Only build when package changes
ignore = "git diff --quiet $CACHED_COMMIT_REF $COMMIT_REF packages/web"
undefined[build]
base = "packages/web"
command = "npm run build"
publish = "dist"
仅当包变更时构建
ignore = "git diff --quiet $CACHED_COMMIT_REF $COMMIT_REF packages/web"
undefinedCommon Patterns
常见模式
SPA with API Proxy
带API代理的SPA
toml
[build]
command = "npm run build"
publish = "build"
functions = "netlify/functions"
[[redirects]]
from = "/api/*"
to = "/.netlify/functions/:splat"
status = 200
[[redirects]]
from = "/*"
to = "/index.html"
status = 200toml
[build]
command = "npm run build"
publish = "build"
functions = "netlify/functions"
[[redirects]]
from = "/api/*"
to = "/.netlify/functions/:splat"
status = 200
[[redirects]]
from = "/*"
to = "/index.html"
status = 200Microsite with Subfolder
子目录微站点
toml
[[redirects]]
from = "/blog/*"
to = "https://blog.example.com/:splat"
status = 200
force = truetoml
[[redirects]]
from = "/blog/*"
to = "https://blog.example.com/:splat"
status = 200
force = trueAuthentication Gateway
身份验证网关
toml
[[redirects]]
from = "/app/*"
to = "/app/dashboard"
status = 200
conditions = {Role = ["user"]}
[[redirects]]
from = "/app/*"
to = "/login"
status = 302Summary: Netlify provides a complete JAMstack platform with static hosting, serverless functions, forms, and identity management. Key strengths include atomic deploys, instant cache invalidation, deploy previews, and built-in CDN. Configure via netlify.toml for builds, redirects, headers, and environment-specific settings. Leverage serverless functions for backend logic, forms for user input, and Edge Functions for edge computing. Best practices include performance optimization, security headers, and efficient build configurations.
toml
[[redirects]]
from = "/app/*"
to = "/app/dashboard"
status = 200
conditions = {Role = ["user"]}
[[redirects]]
from = "/app/*"
to = "/login"
status = 302总结: Netlify 提供了完整的JAMstack平台,包含静态托管、无服务器函数、表单和身份验证管理。其核心优势包括原子化部署、即时缓存失效、部署预览和内置CDN。可通过netlify.toml配置构建、重定向、请求头和环境特定设置。利用无服务器函数实现后端逻辑,表单处理用户输入,Edge Functions实现边缘计算。最佳实践包括性能优化、安全请求头和高效的构建配置。