第42期 | 项目1续:部署与优化——让你的AI知识库上线全网
第42期 | 项目1续:部署与优化——让你的AI知识库上线全网
🎯 今天你将学会
- 用 Vercel 一键部署全栈应用,零配置上线
- 掌握前端性能优化的6个关键维度
- SEO 基础:让搜索引擎收录你的项目
- 用 AI 辅助分析性能瓶颈和生成优化方案
📖 核心知识
上期我们完成了 AI 知识库产品 TechAssist 的核心功能开发。代码在本地跑得好好的,但如果没有部署上线,它就永远只是你电脑上的一个文件夹。
部署上线,是教程项目和生产项目的分水岭。
今天我们把 TechAssist 部署到 Vercel,然后做一轮性能优化和 SEO 配置。最终效果:任何人通过一个 URL 就能访问你的 AI 知识库。
一、Vercel 部署:从本地到全网
1.1 为什么选 Vercel?
| 平台 | 适合场景 | 免费额度 | 前端友好度 |
|---|---|---|---|
| Vercel | Next.js / React SPA | 100GB带宽/月 | ⭐⭐⭐⭐⭐ |
| Netlify | 静态站 / JAMstack | 100GB带宽/月 | ⭐⭐⭐⭐ |
| GitHub Pages | 纯静态 | 无限 | ⭐⭐⭐ |
| Cloudflare Pages | 静态 + Edge Functions | 无限带宽 | ⭐⭐⭐⭐ |
Vercel 的核心优势:
- 零配置:检测到框架自动配置构建
- Edge Network:全球 CDN,访问速度快
- Serverless Functions:前端项目也能写后端 API
- 预览部署:每个 PR 自动生成预览链接
1.2 部署前的准备
// package.json — 确保构建脚本正确
{
"name": "tech-assist",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
// ...其他配置
}
// vite.config.ts — 添加生产优化
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
export default defineConfig({
plugins: [react()],
build: {
// 代码分包
rollupOptions: {
output: {
manualChunks: {
'react-vendor': ['react', 'react-dom', 'react-router-dom'],
'ai-vendor': ['openai', 'ai'],
'ui-vendor': ['@radix-ui/react-dialog', '@radix-ui/react-dropdown-menu'],
},
},
},
// chunk 大小警告阈值
chunkSizeWarningLimit: 1000,
// 启用 sourcemap(生产环境用于错误追踪)
sourcemap: false,
},
})
// src/config/env.ts — 环境变量管理
const env = {
// 前端可见的变量(VITE_ 前缀)
SUPABASE_URL: import.meta.env.VITE_SUPABASE_URL,
SUPABASE_ANON_KEY: import.meta.env.VITE_SUPABASE_ANON_KEY,
API_BASE_URL: import.meta.env.VITE_API_BASE_URL || '/api',
IS_PROD: import.meta.env.PROD,
}
// 启动时校验必要变量
function validateEnv() {
const required = ['SUPABASE_URL', 'SUPABASE_ANON_KEY']
const missing = required.filter(key => !env[key])
if (missing.length > 0) {
console.error(`Missing env vars: ${missing.join(', ')}`)
if (env.IS_PROD) {
throw new Error(`Environment configuration error: ${missing.join(', ')}`)
}
}
}
validateEnv()
export default env
1.3 Vercel 部署流程
方式一:CLI 部署
# 安装 Vercel CLI
npm i -g vercel
# 在项目根目录执行
vercel
# 交互式配置:
# ? Set up and deploy "tech-assist"? → Y
# ? Which scope do you want to deploy to? → 选择你的账号
# ? Link to existing project? → N
# ? What's your project's name? → tech-assist
# ? In which directory is your code located? → ./
# ? Want to modify these settings? → N
# 部署到生产环境
vercel --prod
方式二:GitHub 关联自动部署(推荐)
1. 推送代码到 GitHub
2. 登录 vercel.com → New Project → Import Git Repository
3. 选择你的仓库 → 自动检测 Vite 框架
4. 配置环境变量:
VITE_SUPABASE_URL = https://xxx.supabase.co
VITE_SUPABASE_ANON_KEY = eyJxxx...
5. 点击 Deploy → 等 1-2 分钟
6. 得到 https://tech-assist.vercel.app
1.4 Serverless API Routes
Vercel 支持在 api/ 目录下创建 Serverless Functions,这样前端项目也能有后端能力——而且 OpenAI API Key 可以安全地存在服务端。
// api/chat.ts — 后端代理 OpenAI 调用
import { OpenAI } from 'openai'
import type { VercelRequest, VercelResponse } from '@vercel/node'
const openai = new OpenAI({
apiKey: process.env.OPENAI_API_KEY, // 服务端环境变量,前端看不到
})
export default async function handler(req: VercelRequest, res: VercelResponse) {
if (req.method !== 'POST') {
return res.status(405).json({ error: 'Method not allowed' })
}
const { messages, model = 'gpt-4o-mini' } = req.body
try {
const stream = await openai.chat.completions.create({
model,
messages,
stream: true,
})
// 设置 SSE 响应头
res.setHeader('Content-Type', 'text/event-stream')
res.setHeader('Cache-Control', 'no-cache')
res.setHeader('Connection', 'keep-alive')
// 转发流式响应
for await (const chunk of stream) {
const content = chunk.choices[0]?.delta?.content
if (content) {
res.write(`data: ${JSON.stringify({ content })}\n\n`)
}
}
res.write('data: [DONE]\n\n')
res.end()
} catch (error) {
console.error('Chat API error:', error)
res.status(500).json({ error: 'Internal server error' })
}
}
// api/embed.ts — 文档向量化 API
import { OpenAI } from 'openai'
import type { VercelRequest, VercelResponse } from '@vercel/node'
const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY })
export default async function handler(req: VercelRequest, res: VercelResponse) {
if (req.method !== 'POST') {
return res.status(405).json({ error: 'Method not allowed' })
}
const { text } = req.body as { text: string }
if (!text || text.length > 8000) {
return res.status(400).json({ error: 'Invalid text input' })
}
try {
const response = await openai.embeddings.create({
model: 'text-embedding-3-small',
input: text,
})
return res.status(200).json({
embedding: response.data[0].embedding,
tokens: response.usage.total_tokens,
})
} catch (error) {
console.error('Embed API error:', error)
return res.status(500).json({ error: 'Embedding failed' })
}
}
为什么用 API Route 而不是前端直连?
- API Key 安全:Key 存在服务端环境变量,前端代码里看不到
- 请求控制:可以在服务端做限流、内容审核
- CORS 无忧:同域请求,没有跨域问题
- 灵活降级:可以加缓存、切换模型,前端无感知
1.5 自定义域名
Vercel Dashboard → Settings → Domains → Add Domain
# 如果你有域名 tech-assist.com:
1. 添加域名
2. 在域名服务商处配置 DNS:
- A 记录: @ → 76.76.21.21
- CNAME: www → cname.vercel-dns.com
3. 等 DNS 生效(几分钟到几小时)
4. Vercel 自动签发 SSL 证书
# 最终访问地址:
# https://tech-assist.com (主域名)
# https://www.tech-assist.com (www 跳转到主域名)
二、性能优化:6个关键维度
部署上线只是第一步。如果用户打开页面要等 5 秒,他们会直接关掉。
2.1 性能指标:Lighthouse 评分体系
# 安装 Lighthouse CLI
npm i -g lighthouse
# 运行审计
lighthouse https://tech-assist.vercel.app --view
# 五个维度:
# Performance(性能) — 目标 90+
# Accessibility(可访问性) — 目标 95+
# Best Practices(最佳实践) — 目标 100
# SEO — 目标 95+
# PWA(渐进式 Web 应用)— 可选
核心性能指标(Core Web Vitals):
| 指标 | 含义 | 目标值 |
|---|---|---|
| LCP (Largest Contentful Paint) | 最大内容渲染时间 | < 2.5s |
| FID/INP (Interaction to Next Paint) | 首次交互延迟 | < 200ms |
| CLS (Cumulative Layout Shift) | 累积布局偏移 | < 0.1 |
| FCP (First Contentful Paint) | 首次内容渲染 | < 1.8s |
| TTFB (Time to First Byte) | 首字节时间 | < 800ms |
2.2 维度一:资源加载优化
// 1. 图片懒加载 + WebP 格式
import { useState, useEffect, useRef } from 'react'
function LazyImage({ src, alt, width, height }: ImageProps) {
const [isLoaded, setIsLoaded] = useState(false)
const [currentSrc, setCurrentSrc] = useState('')
const ref = useRef<HTMLImageElement>(null)
useEffect(() => {
const observer = new IntersectionObserver(
([entry]) => {
if (entry.isIntersecting) {
// 根据设备像素比选择合适尺寸
const dpr = window.devicePixelRatio || 1
const optimized = `${src}?w=${width * dpr}&format=webp`
setCurrentSrc(optimized)
observer.disconnect()
}
},
{ rootMargin: '50px' }
)
if (ref.current) observer.observe(ref.current)
return () => observer.disconnect()
}, [src, width])
return (
<div
style={{ width, height, background: '#f0f0f0' }}
className="image-placeholder"
>
{currentSrc && (
<img
ref={ref}
src={currentSrc}
alt={alt}
width={width}
height={height}
loading="lazy"
onLoad={() => setIsLoaded(true)}
style={{ opacity: isLoaded ? 1 : 0, transition: 'opacity 0.3s' }}
/>
)}
</div>
)
}
// 2. 字体优化:使用 font-display: swap
// index.css
@font-face {
font-family: 'Inter';
src: url('/fonts/Inter.woff2') format('woff2');
font-weight: 400 700;
font-display: swap; /* 用系统字体先渲染,字体加载后替换 */
}
/* 或者用 Google Fonts 的预连接 */
// index.html
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap"
rel="stylesheet"
/>
// 3. 第三方脚本异步加载
// 不阻塞渲染
<script async src="https://www.googletagmanager.com/gtag/js?id=GA_ID"></script>
// 如果依赖关系重要,用 defer
<script defer src="/js/analytics.js"></script>
2.3 维度二:代码分包与懒加载
// React.lazy 懒加载路由组件
import { lazy, Suspense } from 'react'
import { BrowserRouter, Routes, Route } from 'react-router-dom'
import Layout from './components/Layout'
import LoadingSpinner from './components/LoadingSpinner'
// 首页直接加载
import Home from './pages/Home'
// 其他页面懒加载
const Chat = lazy(() => import('./pages/Chat'))
const KnowledgeBase = lazy(() => import('./pages/KnowledgeBase'))
const Settings = lazy(() => import('./pages/Settings'))
export default function App() {
return (
<BrowserRouter>
<Layout>
<Suspense fallback={<LoadingSpinner />}>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/chat" element={<Chat />} />
<Route path="/kb" element={<KnowledgeBase />} />
<Route path="/settings" element={<Settings />} />
</Routes>
</Suspense>
</Layout>
</BrowserRouter>
)
}
// 动态导入大依赖
async function exportData() {
// 只在用户点击导出时才加载 jszip
const JSZip = (await import('jszip')).default
const zip = new JSZip()
// ...打包逻辑
const blob = await zip.generateAsync({ type: 'blob' })
return blob
}
2.4 维度三:渲染性能优化
// 1. 长列表虚拟化:react-window
import { FixedSizeList as List } from 'react-window'
interface Message {
id: string
role: 'user' | 'assistant'
content: string
}
function MessageList({ messages }: { messages: Message[] }) {
const Row = ({ index, style }: { index: number; style: React.CSSProperties }) => (
<div style={style}>
<MessageBubble message={messages[index]} />
</div>
)
return (
<List
height={600}
itemCount={messages.length}
itemSize={120}
width="100%"
>
{Row}
</List>
)
}
// 10000 条消息也丝滑——只渲染可视区域的 ~7 条
// 2. useMemo / useCallback 避免不必要的渲染
import { useMemo, useCallback, memo } from 'react'
// ✅ 用 memo 包裹子组件
const MessageBubble = memo(({ message }: { message: Message }) => {
return <div className="bubble">{message.content}</div>
})
function ChatRoom({ messages, onSend }: ChatRoomProps) {
// ✅ 只在 messages 变化时重新计算统计
const stats = useMemo(() => {
const userCount = messages.filter(m => m.role === 'user').length
const assistantCount = messages.filter(m => m.role === 'assistant').length
return { userCount, assistantCount, total: messages.length }
}, [messages])
// ✅ onSend 引用稳定,子组件不会因父组件重渲染而重渲染
const handleSend = useCallback(
(text: string) => {
onSend(text)
},
[onSend]
)
return (
<div>
<StatsBar stats={stats} />
<MessageList messages={messages} />
<InputBox onSend={handleSend} />
</div>
)
}
2.5 维度四:网络请求优化
// 1. 请求缓存:SWR / TanStack Query
import useSWR from 'swr'
const fetcher = (url: string) => fetch(url).then(res => res.json())
function useDocuments() {
const { data, error, isLoading, mutate } = useSWR('/api/documents', fetcher, {
revalidateOnFocus: false, // 切回标签页不重新请求
dedupingInterval: 60000, // 60秒内相同请求去重
})
return { documents: data, isLoading, error, refresh: mutate }
}
// 2. 请求合并:多个请求并行
async function loadDashboardData(userId: string) {
// ❌ 串行:慢
// const profile = await fetchProfile(userId)
// const docs = await fetchDocuments(userId)
// const usage = await fetchUsage(userId)
// ✅ 并行:快
const [profile, docs, usage] = await Promise.all([
fetchProfile(userId),
fetchDocuments(userId),
fetchUsage(userId),
])
return { profile, docs, usage }
}
// 3. 防抖搜索
function useDebouncedSearch(query: string, delay = 300) {
const [results, setResults] = useState([])
useEffect(() => {
if (!query.trim()) {
setResults([])
return
}
const timer = setTimeout(async () => {
const res = await fetch(`/api/search?q=${encodeURIComponent(query)}`)
const data = await res.json()
setResults(data)
}, delay)
return () => clearTimeout(timer)
}, [query, delay])
return results
}
2.6 维度五:构建产物分析
# 安装包分析工具
npm i -D rollup-plugin-visualizer
// vite.config.ts
import { visualizer } from 'rollup-plugin-visualizer'
export default defineConfig({
plugins: [
react(),
visualizer({
open: true, // 构建后自动打开
filename: 'stats.html',
gzipSize: true,
brotliSize: true,
}),
],
})
# 分析结果示例
dist/assets/
├── react-vendor.js 142KB (32%) ← 框架,无法减小
├── ai-vendor.js 89KB (20%) ← openai SDK
├── ui-vendor.js 45KB (10%) ← Radix UI
├── index.js 67KB (15%) ← 业务代码
├── Chat.js 34KB (8%) ← 懒加载 chunk
├── KnowledgeBase.js 28KB (6%)
├── index.css 22KB (5%)
└── 其他 18KB (4%)
# 优化决策:
# - openai SDK 太大?→ 改用直接 fetch 调用 API,去掉 SDK
# - Radix UI 只用了 3 个组件?→ 按需导入
# - 业务代码 67KB?→ 检查是否有死代码
2.7 维度六:缓存策略
// Vercel 静态资源缓存配置
// vercel.json
{
"headers": [
{
"source": "/assets/(.*)",
"headers": [
{
"key": "Cache-Control",
"value": "public, max-age=31536000, immutable"
}
]
},
{
"source": "/(.*)",
"headers": [
{
"key": "Cache-Control",
"value": "public, max-age=0, must-revalidate"
}
]
}
]
}
// Vite 构建的文件名带 hash(如 index.abc123.js)
// 所以静态资源可以永久缓存,文件变了 hash 就变,浏览器会重新请求
// HTML 文件不缓存,确保用户总是拿到最新的入口
三、SEO 基础
SEO 对 AI 应用同样重要——如果你的 AI 知识库被搜索引擎收录,会带来自然流量。
3.1 基础 meta 标签
<!-- index.html -->
<head>
<title>TechAssist - AI 知识库助手 | 智能问答与文档管理</title>
<meta
name="description"
content="TechAssist 是一个基于 RAG 的 AI 知识库助手,支持文档上传、智能问答和知识管理。"
/>
<meta name="keywords" content="AI知识库,RAG,智能问答,文档管理,AI助手" />
<meta name="author" content="你的名字" />
<!-- Open Graph(社交分享卡片) -->
<meta property="og:title" content="TechAssist - AI 知识库助手" />
<meta property="og:description" content="基于 RAG 的智能问答与文档管理平台" />
<meta property="og:image" content="https://tech-assist.vercel.app/og-image.png" />
<meta property="og:url" content="https://tech-assist.vercel.app" />
<meta property="og:type" content="website" />
<!-- Twitter Card -->
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content="TechAssist - AI 知识库助手" />
<meta name="twitter:image" content="https://tech-assist.vercel.app/og-image.png" />
<!-- canonical URL(防止重复内容) -->
<link rel="canonical" href="https://tech-assist.vercel.app" />
</head>
3.2 动态 meta 标签(React)
// hooks/useSEO.ts — 动态 SEO Hook
import { useEffect } from 'react'
interface SEOProps {
title: string
description?: string
image?: string
url?: string
}
function useSEO({ title, description, image, url }: SEOProps) {
useEffect(() => {
document.title = title
const setMeta = (name: string, content: string, attr: 'name' | 'property' = 'name') => {
let tag = document.querySelector(`meta[${attr}="${name}"]`)
if (!tag) {
tag = document.createElement('meta')
tag.setAttribute(attr, name)
document.head.appendChild(tag)
}
tag.setAttribute('content', content)
}
if (description) setMeta('description', description)
if (image) {
setMeta('og:image', image, 'property')
setMeta('twitter:image', image)
}
if (url) {
setMeta('og:url', url, 'property')
}
setMeta('og:title', title, 'property')
setMeta('twitter:title', title)
}, [title, description, image, url])
}
// 使用
function ChatPage() {
useSEO({
title: 'AI 对话 | TechAssist',
description: '与你的 AI 知识库助手对话,获取基于文档的精准回答。',
url: 'https://tech-assist.vercel.app/chat',
})
return <ChatInterface />
}
3.3 sitemap.xml 和 robots.txt
<!-- public/sitemap.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>https://tech-assist.vercel.app</loc>
<changefreq>weekly</changefreq>
<priority>1.0</priority>
</url>
<url>
<loc>https://tech-assist.vercel.app/chat</loc>
<changefreq>weekly</changefreq>
<priority>0.8</priority>
</url>
<url>
<loc>https://tech-assist.vercel.app/kb</loc>
<changefreq>daily</changefreq>
<priority>0.8</priority>
</url>
</urlset>
# public/robots.txt
User-agent: *
Allow: /
Disallow: /settings
Disallow: /api/
Sitemap: https://tech-assist.vercel.app/sitemap.xml
3.4 SPA 的 SEO 痛点
SPA(单页应用)的内容是 JS 渲染的,搜索引擎爬虫可能看不到内容。解决方案:
| 方案 | 难度 | 效果 | 适合场景 |
|---|---|---|---|
| SSR(服务端渲染) | 高 | ⭐⭐⭐⭐⭐ | 用 Next.js 重构 |
| 预渲染(prerender) | 中 | ⭐⭐⭐⭐ | 内容相对静态 |
| 动态渲染 | 中 | ⭐⭐⭐⭐ | 爬虫来时返回 HTML |
| 基础 meta 优化 | 低 | ⭐⭐⭐ | 大多数 SPA |
对于 TechAssist 这种交互密集的应用,先做基础 meta 优化就够了。如果后续要做落地页(Landing Page),可以用 Next.js 或 Astro 做预渲染。
🤖 AI协作实战
场景:用 AI 做 Lighthouse 性能分析
我的 Prompt:
我有一个 React + Vite 项目部署在 Vercel 上,Lighthouse 性能评分 62 分。
主要问题:
- LCP: 4.2s(目标 < 2.5s)
- CLS: 0.25(目标 < 0.1)
- TBT: 380ms(目标 < 200ms)
项目信息:
- 框架:React 18 + Vite
- 主要依赖:react-router-dom, openai, @radix-ui, react-markdown
- 首页内容:导航栏 + Hero区域 + 功能卡片 + Footer
- 图片:3张 png(未压缩),1张 gif(2.5MB)
请按优先级列出优化方案,每项说明:1)做什么 2)预期改善 3)实现代码
AI 的输出(节选):
按优先级排序的优化方案:
### P0:图片优化(预计 LCP -1.5s)
问题分析:
- 2.5MB 的 gif 是 LCP 的元凶
- 3张未压缩 png 总计 1.8MB
方案:
1. gif → WebM 视频(体积减 80%+)
2. png → WebP(体积减 50-70%)
3. 添加 width/height 属性防止 CLS
### P1:减少 JS 阻塞(预计 TBT -150ms)
问题分析:
- openai SDK 在首页并不需要,但被打进了主 chunk
- @radix-ui 全量导入
方案:
1. openai SDK 动态导入
2. Radix 按需导入
3. 首页非关键组件懒加载
### P2:CLS 修复(预计 CLS → 0.05)
问题分析:
- 图片无尺寸属性
- 字体加载导致文字跳动
方案:
1. 所有图片添加 width/height
2. 字体使用 font-display: swap + size-adjust
3. 骨架屏占位
我的审查和修改:
AI 给的方案方向正确,但有几处需要调整:
- gif → WebM:AI 建议转 WebM,但考虑到兼容性,我改用
<picture>标签同时提供 WebM 和 fallback - openai SDK:实际上我在第41期已经把 OpenAI 调用移到了后端 API Route,前端不需要这个 SDK——确认 package.json 中已移除
- size-adjust:AI 给了一个固定的
size-adjust: 95%,但这个值需要根据实际字体调试,不是通用的
/* 我的最终字体配置 */
@font-face {
font-family: 'Inter';
src: url('/fonts/Inter.woff2') format('woff2');
font-weight: 400 700;
font-display: swap;
/* 逐字调试后的 size-adjust */
size-adjust: 97.5%;
ascent-override: 92%;
}
学到了什么:
- AI 给的性能优化方案 方向通常正确,但具体数值需要实测
size-adjust这种细调值,AI 只能给个起始值,需要用 Font Style Matcher 工具精确调试- 让 AI 分析时,给它越多的数据(Lighthouse 报告、包分析结果),方案越精准
- AI 不会知道你的项目已经做了什么优化——你需要在 prompt 中说明当前状态
AI 辅助 SEO 优化
Prompt 模板:
我有一个 AI 知识库产品 TechAssist,请帮我生成以下 SEO 内容:
1. 5 个目标关键词(长尾词优先)
2. 首页 title 标签(60字符以内)
3. 首页 description(155字符以内)
4. 3 篇引流文章的标题和摘要(发布在技术社区)
5. Open Graph 卡片的文案
产品信息:
- 核心功能:RAG知识库 + AI对话 + 文档管理
- 目标用户:开发者、技术团队
- 差异化:本地部署友好的轻量级 AI 知识库
AI 能帮你快速生成 SEO 文案矩阵,但要注意:
- 关键词密度不要堆砌——搜索引擎会惩罚
- title 和 description 要吸引人点击——排名高但没人点击也没用
- 引流文章要真有干货——别只是标题党
💻 动手练习
练习1:部署你的项目(简单)
把第41期的 TechAssist 项目部署到 Vercel:
- 推送代码到 GitHub
- 在 Vercel 导入项目
- 配置环境变量
- 部署成功后,用手机打开链接——感受移动端体验
练习2:跑一次 Lighthouse(中等)
部署后运行 Lighthouse 审计:
- 用 Chrome DevTools → Lighthouse 面板
- 记录五项评分
- 根据建议优化至少 3 项
- 重新部署后对比评分变化
练习3:性能优化挑战(挑战)
目标:Lighthouse Performance 评分从初始值提升 20 分以上。
必做项:
- 图片懒加载 + WebP 转换
- 至少 2 个路由懒加载
- 第三方脚本 async/defer
- CLS 降至 0.1 以下
选做项:
- react-window 虚拟列表
- SWR 请求缓存
- 构建产物包分析,去掉无用依赖
📌 本期要点
- Vercel 部署:GitHub 关联 + 环境变量配置 = 零配置上线。API Route 让前端项目也能安全调用 OpenAI
- 性能指标:LCP < 2.5s / CLS < 0.1 / INP < 200ms 是核心 Web Vitals 及格线
- 六维优化:资源加载、代码分包、渲染性能、网络请求、构建分析、缓存策略——系统化提升
- SEO 三件套:meta 标签 + sitemap.xml + robots.txt 是基础三件套,动态页面用 Hook 管理
- AI 辅助优化:给 AI 提供 Lighthouse 报告和包分析数据,它能给出精准的优先级排序
🔗 下期预告
第43期:项目2——AI 工作流编排工具。我们来实现一个可视化的流程编辑器,让用户拖拽节点来编排 AI 工作流。涉及画布交互、React Flow、复杂状态管理,是前端交互能力的集中展示。
如果你没有苹果电脑,需要上传ios到APPStore可以访问以下网站
iPA上传工具 - IPA解析与AppStore提交
更多推荐

所有评论(0)