performance-optimization by akillness/oh-my-skills
npx skills add https://github.com/akillness/oh-my-skills --skill performance-optimizationLighthouse (Chrome DevTools) :
# CLI
npm install -g lighthouse
lighthouse https://example.com --view
# Automate in CI
lighthouse https://example.com --output=json --output-path=./report.json
测量 Web Vitals (React):
import { getCLS, getFID, getFCP, getLCP, getTTFB } from 'web-vitals';
function sendToAnalytics(metric: any) {
// 发送到 Google Analytics, Datadog 等
console.log(metric);
}
getCLS(sendToAnalytics);
getFID(sendToAnalytics);
getFCP(sendToAnalytics);
getLCP(sendToAnalytics);
getTTFB(sendToAnalytics);
React.memo (防止不必要的重新渲染) :
// ❌ 不好: 父组件重新渲染时,子组件也会重新渲染
function ExpensiveComponent({ data }: { data: Data }) {
return <div>{/* complex rendering */}</div>;
}
// ✅ 好: 仅在 props 改变时重新渲染
const ExpensiveComponent = React.memo(({ data }: { data: Data }) => {
return <div>{/* complex rendering */}</div>;
});
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
useMemo & useCallback:
function ProductList({ products, category }: Props) {
// ✅ 缓存过滤结果
const filteredProducts = useMemo(() => {
return products.filter(p => p.category === category);
}, [products, category]);
// ✅ 缓存回调函数
const handleAddToCart = useCallback((id: string) => {
addToCart(id);
}, []);
return (
<div>
{filteredProducts.map(product => (
<ProductCard key={product.id} product={product} onAdd={handleAddToCart} />
))}
</div>
);
}
懒加载与代码分割:
import { lazy, Suspense } from 'react';
// ✅ 基于路由的代码分割
const Dashboard = lazy(() => import('./pages/Dashboard'));
const Profile = lazy(() => import('./pages/Profile'));
const Settings = lazy(() => import('./pages/Settings'));
function App() {
return (
<Suspense fallback={<div>Loading...</div>}>
<Routes>
<Route path="/dashboard" element={<Dashboard />} />
<Route path="/profile" element={<Profile />} />
<Route path="/settings" element={<Settings />} />
</Routes>
</Suspense>
);
}
// ✅ 基于组件的懒加载
const HeavyChart = lazy(() => import('./components/HeavyChart'));
function Dashboard() {
return (
<div>
<h1>Dashboard</h1>
<Suspense fallback={<Skeleton />}>
<HeavyChart data={data} />
</Suspense>
</div>
);
}
Webpack Bundle Analyzer :
npm install --save-dev webpack-bundle-analyzer
# package.json
{
"scripts": {
"analyze": "webpack-bundle-analyzer build/stats.json"
}
}
Tree Shaking (移除未使用的代码) :
// ❌ 不好: 导入整个库
import _ from 'lodash';
// ✅ 好: 仅导入需要的部分
import debounce from 'lodash/debounce';
动态导入 :
// ✅ 仅在需要时加载
button.addEventListener('click', async () => {
const { default: Chart } = await import('chart.js');
new Chart(ctx, config);
});
Next.js Image 组件 :
import Image from 'next/image';
function ProductImage() {
return (
<Image
src="/product.jpg"
alt="Product"
width={500}
height={500}
priority // 用于 LCP 图片
placeholder="blur" // 模糊占位符
sizes="(max-width: 768px) 100vw, 50vw"
/>
);
}
使用 WebP 格式 :
<picture>
<source srcset="image.webp" type="image/webp">
<source srcset="image.jpg" type="image/jpeg">
<img src="image.jpg" alt="Fallback">
</picture>
解决 N+1 查询问题 :
// ❌ 不好: N+1 查询
const posts = await db.post.findMany();
for (const post of posts) {
const author = await db.user.findUnique({ where: { id: post.authorId } });
// 101 次查询 (1 + 100)
}
// ✅ 好: 使用 JOIN 或 include
const posts = await db.post.findMany({
include: {
author: true
}
});
// 1 次查询
添加索引 :
-- 识别慢查询
EXPLAIN ANALYZE SELECT * FROM users WHERE email = 'test@example.com';
-- 添加索引
CREATE INDEX idx_users_email ON users(email);
-- 复合索引
CREATE INDEX idx_orders_user_date ON orders(user_id, created_at);
缓存 (Redis) :
async function getUserProfile(userId: string) {
// 1. 检查缓存
const cached = await redis.get(`user:${userId}`);
if (cached) {
return JSON.parse(cached);
}
// 2. 查询数据库
const user = await db.user.findUnique({ where: { id: userId } });
// 3. 存入缓存 (1 小时)
await redis.setex(`user:${userId}`, 3600, JSON.stringify(user));
return user;
}
## 前端
- [ ] 使用 React.memo 防止不必要的重新渲染
- [ ] 适当使用 useMemo/useCallback
- [ ] 懒加载与代码分割
- [ ] 优化图片 (WebP, 懒加载)
- [ ] 分析并减少打包体积
## 后端
- [ ] 移除 N+1 查询
- [ ] 添加数据库索引
- [ ] Redis 缓存
- [ ] 压缩 API 响应 (gzip)
- [ ] 使用 CDN
## 测量
- [ ] Lighthouse 分数 90+
- [ ] LCP < 2.5s
- [ ] FID < 100ms
- [ ] CLS < 0.1
#performance #optimization #React #caching #lazy-loading #web-vitals #code-quality
每周安装数
1
代码仓库
GitHub 星标数
3
首次出现
1 天前
安全审计
安装于
mcpjam1
claude-code1
junie1
windsurf1
zencoder1
crush1
Lighthouse (Chrome DevTools) :
# CLI
npm install -g lighthouse
lighthouse https://example.com --view
# Automate in CI
lighthouse https://example.com --output=json --output-path=./report.json
Measure Web Vitals (React):
import { getCLS, getFID, getFCP, getLCP, getTTFB } from 'web-vitals';
function sendToAnalytics(metric: any) {
// Send to Google Analytics, Datadog, etc.
console.log(metric);
}
getCLS(sendToAnalytics);
getFID(sendToAnalytics);
getFCP(sendToAnalytics);
getLCP(sendToAnalytics);
getTTFB(sendToAnalytics);
React.memo (prevent unnecessary re-renders) :
// ❌ Bad: child re-renders whenever the parent re-renders
function ExpensiveComponent({ data }: { data: Data }) {
return <div>{/* complex rendering */}</div>;
}
// ✅ Good: re-render only when props change
const ExpensiveComponent = React.memo(({ data }: { data: Data }) => {
return <div>{/* complex rendering */}</div>;
});
useMemo & useCallback:
function ProductList({ products, category }: Props) {
// ✅ Memoize filtered results
const filteredProducts = useMemo(() => {
return products.filter(p => p.category === category);
}, [products, category]);
// ✅ Memoize callback
const handleAddToCart = useCallback((id: string) => {
addToCart(id);
}, []);
return (
<div>
{filteredProducts.map(product => (
<ProductCard key={product.id} product={product} onAdd={handleAddToCart} />
))}
</div>
);
}
Lazy Loading & Code Splitting:
import { lazy, Suspense } from 'react';
// ✅ Route-based code splitting
const Dashboard = lazy(() => import('./pages/Dashboard'));
const Profile = lazy(() => import('./pages/Profile'));
const Settings = lazy(() => import('./pages/Settings'));
function App() {
return (
<Suspense fallback={<div>Loading...</div>}>
<Routes>
<Route path="/dashboard" element={<Dashboard />} />
<Route path="/profile" element={<Profile />} />
<Route path="/settings" element={<Settings />} />
</Routes>
</Suspense>
);
}
// ✅ Component-based lazy loading
const HeavyChart = lazy(() => import('./components/HeavyChart'));
function Dashboard() {
return (
<div>
<h1>Dashboard</h1>
<Suspense fallback={<Skeleton />}>
<HeavyChart data={data} />
</Suspense>
</div>
);
}
Webpack Bundle Analyzer :
npm install --save-dev webpack-bundle-analyzer
# package.json
{
"scripts": {
"analyze": "webpack-bundle-analyzer build/stats.json"
}
}
Tree Shaking (remove unused code) :
// ❌ Bad: import entire library
import _ from 'lodash';
// ✅ Good: import only what you need
import debounce from 'lodash/debounce';
Dynamic Imports :
// ✅ Load only when needed
button.addEventListener('click', async () => {
const { default: Chart } = await import('chart.js');
new Chart(ctx, config);
});
Next.js Image component :
import Image from 'next/image';
function ProductImage() {
return (
<Image
src="/product.jpg"
alt="Product"
width={500}
height={500}
priority // for the LCP image
placeholder="blur" // blur placeholder
sizes="(max-width: 768px) 100vw, 50vw"
/>
);
}
Use WebP format :
<picture>
<source srcset="image.webp" type="image/webp">
<source srcset="image.jpg" type="image/jpeg">
<img src="image.jpg" alt="Fallback">
</picture>
Fix the N+1 query problem :
// ❌ Bad: N+1 queries
const posts = await db.post.findMany();
for (const post of posts) {
const author = await db.user.findUnique({ where: { id: post.authorId } });
// 101 queries (1 + 100)
}
// ✅ Good: JOIN or include
const posts = await db.post.findMany({
include: {
author: true
}
});
// 1 query
Add indexes :
-- Identify slow queries
EXPLAIN ANALYZE SELECT * FROM users WHERE email = 'test@example.com';
-- Add index
CREATE INDEX idx_users_email ON users(email);
-- Composite index
CREATE INDEX idx_orders_user_date ON orders(user_id, created_at);
Caching (Redis) :
async function getUserProfile(userId: string) {
// 1. Check cache
const cached = await redis.get(`user:${userId}`);
if (cached) {
return JSON.parse(cached);
}
// 2. Query DB
const user = await db.user.findUnique({ where: { id: userId } });
// 3. Store in cache (1 hour)
await redis.setex(`user:${userId}`, 3600, JSON.stringify(user));
return user;
}
## Frontend
- [ ] Prevent unnecessary re-renders with React.memo
- [ ] Use useMemo/useCallback appropriately
- [ ] Lazy loading & Code splitting
- [ ] Optimize images (WebP, lazy loading)
- [ ] Analyze and reduce bundle size
## Backend
- [ ] Remove N+1 queries
- [ ] Add database indexes
- [ ] Redis caching
- [ ] Compress API responses (gzip)
- [ ] Use a CDN
## Measurement
- [ ] Lighthouse score 90+
- [ ] LCP < 2.5s
- [ ] FID < 100ms
- [ ] CLS < 0.1
#performance #optimization #React #caching #lazy-loading #web-vitals #code-quality
Weekly Installs
1
Repository
GitHub Stars
3
First Seen
1 day ago
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
mcpjam1
claude-code1
junie1
windsurf1
zencoder1
crush1
TanStack Query v5 完全指南:React 数据管理、乐观更新、离线支持
2,500 周安装
DSPy.rb - Ruby LLM 开发框架:类型安全、模块化、自动优化
206 周安装
Fabro Workflow Factory:Rust 开源 AI 编码工作流编排器,用 Graphviz DOT 定义智能体流水线
206 周安装
SEO 网站审核与关键词研究工具:全面分析、内容差距识别与竞争对手比较
206 周安装
Zotero论文阅读器 - 自动从Zotero文献库读取PDF并转换为Markdown格式的学术工具
206 周安装
视频营销策略与脚本创作指南:短视频长视频优化、吸引钩子技巧、平台SEO
206 周安装
customaize-agent:create-command - 创建与管理AI助手命令的元命令工具
206 周安装