React 项目构建与部署
概述
本章将学习如何构建和部署 React 应用,包括生产环境优化、构建配置、部署策略以及性能监控等内容。
🔧 项目构建
生产构建
bash
# Create React App 构建命令
npm run build
# 构建输出分析
npm install -g serve
serve -s build
# 构建分析
npm install --save-dev webpack-bundle-analyzer
npm run build -- --analyze环境变量配置
bash
# .env 文件
REACT_APP_API_URL=http://localhost:3001
REACT_APP_VERSION=1.0.0
# .env.production
REACT_APP_API_URL=https://api.production.com
REACT_APP_VERSION=1.0.0jsx
// 环境变量使用
function EnvironmentConfig() {
const config = {
apiUrl: process.env.REACT_APP_API_URL,
version: process.env.REACT_APP_VERSION,
isDevelopment: process.env.NODE_ENV === 'development',
isProduction: process.env.NODE_ENV === 'production'
};
return (
<div style={{ padding: '20px' }}>
<h2>环境配置</h2>
<pre>{JSON.stringify(config, null, 2)}</pre>
</div>
);
}⚡ 性能优化
代码分割
jsx
import { Suspense, lazy } from 'react';
// 懒加载组件
const LazyComponent = lazy(() => import('./LazyComponent'));
function CodeSplittingExample() {
const [showLazy, setShowLazy] = React.useState(false);
return (
<div>
<h2>代码分割演示</h2>
<button onClick={() => setShowLazy(!showLazy)}>
{showLazy ? '隐藏' : '显示'}懒加载组件
</button>
{showLazy && (
<Suspense fallback={<div>加载中...</div>}>
<LazyComponent />
</Suspense>
)}
</div>
);
}资源优化
jsx
// 图片懒加载
function LazyImage({ src, alt, ...props }) {
const [isLoaded, setIsLoaded] = React.useState(false);
const [isInView, setIsInView] = React.useState(false);
const imgRef = React.useRef();
React.useEffect(() => {
const observer = new IntersectionObserver(
([entry]) => {
if (entry.isIntersecting) {
setIsInView(true);
observer.disconnect();
}
},
{ threshold: 0.1 }
);
if (imgRef.current) {
observer.observe(imgRef.current);
}
return () => observer.disconnect();
}, []);
return (
<div ref={imgRef} style={{ minHeight: '200px', backgroundColor: '#f8f9fa' }}>
{isInView && (
<img
src={src}
alt={alt}
onLoad={() => setIsLoaded(true)}
style={{
opacity: isLoaded ? 1 : 0,
transition: 'opacity 0.3s',
...props.style
}}
{...props}
/>
)}
</div>
);
}🚀 部署策略
静态文件部署
json
{
"scripts": {
"build": "react-scripts build",
"deploy": "npm run build && cp -r build/* /var/www/html/",
"deploy:s3": "aws s3 sync build/ s3://my-bucket --delete",
"deploy:gh-pages": "gh-pages -d build"
}
}Nginx 配置
nginx
server {
listen 80;
server_name example.com;
root /var/www/html;
index index.html;
# 处理客户端路由
location / {
try_files $uri $uri/ /index.html;
}
# 静态资源缓存
location /static/ {
expires 1y;
add_header Cache-Control "public, immutable";
}
# API 代理
location /api/ {
proxy_pass http://localhost:3001;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}Docker 部署
dockerfile
# Dockerfile
FROM node:18-alpine as build
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
RUN npm run build
FROM nginx:alpine
COPY --from=build /app/build /usr/share/nginx/html
COPY nginx.conf /etc/nginx/nginx.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]yaml
# docker-compose.yml
version: '3.8'
services:
app:
build: .
ports:
- "80:80"
environment:
- NODE_ENV=production
restart: unless-stoppedCI/CD 配置
yaml
# .github/workflows/deploy.yml
name: Deploy to Production
on:
push:
branches: [main]
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup Node.js
uses: actions/setup-node@v2
with:
node-version: '18'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test -- --coverage --watchAll=false
- name: Build application
run: npm run build
env:
REACT_APP_API_URL: ${{ secrets.API_URL }}
- name: Deploy to S3
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: us-east-1
- name: Sync to S3
run: aws s3 sync build/ s3://my-bucket --delete
- name: Invalidate CloudFront
run: aws cloudfront create-invalidation --distribution-id ${{ secrets.CLOUDFRONT_ID }} --paths "/*"📊 监控和分析
性能监控
jsx
// Web Vitals 监控
function performanceMonitoring() {
// 模拟 web-vitals 库
const getCLS = (onPerfEntry) => {
// Cumulative Layout Shift
if (onPerfEntry && onPerfEntry instanceof Function) {
onPerfEntry({ name: 'CLS', value: 0.1 });
}
};
const getFID = (onPerfEntry) => {
// First Input Delay
if (onPerfEntry && onPerfEntry instanceof Function) {
onPerfEntry({ name: 'FID', value: 100 });
}
};
const getFCP = (onPerfEntry) => {
// First Contentful Paint
if (onPerfEntry && onPerfEntry instanceof Function) {
onPerfEntry({ name: 'FCP', value: 1500 });
}
};
const getLCP = (onPerfEntry) => {
// Largest Contentful Paint
if (onPerfEntry && onPerfEntry instanceof Function) {
onPerfEntry({ name: 'LCP', value: 2500 });
}
};
const getTTFB = (onPerfEntry) => {
// Time to First Byte
if (onPerfEntry && onPerfEntry instanceof Function) {
onPerfEntry({ name: 'TTFB', value: 200 });
}
};
return { getCLS, getFID, getFCP, getLCP, getTTFB };
}
// 错误边界和错误报告
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false, error: null };
}
static getDerivedStateFromError(error) {
return { hasError: true, error };
}
componentDidCatch(error, errorInfo) {
// 发送错误到监控服务
this.reportError(error, errorInfo);
}
reportError = (error, errorInfo) => {
// 模拟错误报告
const errorReport = {
message: error.message,
stack: error.stack,
componentStack: errorInfo.componentStack,
timestamp: new Date().toISOString(),
userAgent: navigator.userAgent,
url: window.location.href
};
console.error('Error reported:', errorReport);
// 实际项目中发送到错误监控服务
// fetch('/api/errors', {
// method: 'POST',
// body: JSON.stringify(errorReport)
// });
};
render() {
if (this.state.hasError) {
return (
<div style={{ padding: '20px', textAlign: 'center' }}>
<h2>出现错误</h2>
<p>应用遇到了一个错误,请刷新页面重试。</p>
<button onClick={() => window.location.reload()}>
刷新页面
</button>
</div>
);
}
return this.props.children;
}
}分析工具集成
jsx
// Google Analytics 集成
function useAnalytics() {
React.useEffect(() => {
// 模拟 GA 初始化
if (process.env.NODE_ENV === 'production') {
console.log('Google Analytics initialized');
}
}, []);
const trackEvent = (action, category, label, value) => {
if (process.env.NODE_ENV === 'production') {
// gtag('event', action, {
// event_category: category,
// event_label: label,
// value: value
// });
console.log('Event tracked:', { action, category, label, value });
}
};
const trackPageView = (path) => {
if (process.env.NODE_ENV === 'production') {
// gtag('config', 'GA_MEASUREMENT_ID', {
// page_path: path
// });
console.log('Page view tracked:', path);
}
};
return { trackEvent, trackPageView };
}
// 使用分析
function AnalyticsExample() {
const { trackEvent, trackPageView } = useAnalytics();
React.useEffect(() => {
trackPageView('/analytics-example');
}, [trackPageView]);
const handleButtonClick = () => {
trackEvent('click', 'button', 'analytics-example', 1);
};
return (
<div style={{ padding: '20px' }}>
<h2>分析集成示例</h2>
<button onClick={handleButtonClick}>
追踪点击事件
</button>
</div>
);
}🔐 安全最佳实践
安全配置
jsx
// 内容安全策略
function SecurityHeaders() {
React.useEffect(() => {
// 在生产环境中,这些应该在服务器级别设置
const securityHeaders = {
'Content-Security-Policy': "default-src 'self'; script-src 'self' 'unsafe-inline'",
'X-Frame-Options': 'DENY',
'X-Content-Type-Options': 'nosniff',
'Referrer-Policy': 'strict-origin-when-cross-origin'
};
console.log('Security headers should be set:', securityHeaders);
}, []);
return null;
}
// 敏感信息处理
function SecureDataHandling() {
const [sensitiveData, setSensitiveData] = React.useState(null);
const fetchSecureData = async () => {
try {
// 安全的 API 调用
const token = localStorage.getItem('authToken');
const response = await fetch('/api/secure-data', {
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
}
});
if (!response.ok) {
throw new Error('Unauthorized');
}
const data = await response.json();
setSensitiveData(data);
} catch (error) {
console.error('Security error:', error);
// 处理安全错误
}
};
return (
<div style={{ padding: '20px' }}>
<h2>安全数据处理</h2>
<button onClick={fetchSecureData}>
获取安全数据
</button>
{sensitiveData && (
<div>数据已安全获取</div>
)}
</div>
);
}📝 本章小结
通过本章学习,你应该掌握了:
构建和部署
- ✅ 生产环境构建优化
- ✅ 环境变量配置
- ✅ 静态文件部署
- ✅ Docker 容器化部署
性能和监控
- ✅ 代码分割和懒加载
- ✅ 性能指标监控
- ✅ 错误追踪和报告
- ✅ 用户行为分析
最佳实践
- 构建优化:启用压缩、代码分割
- 缓存策略:合理设置静态资源缓存
- 监控告警:实时监控应用性能
- 安全防护:设置安全头、数据加密
- 持续部署:自动化 CI/CD 流程