Введение
Производительность веб-приложений напрямую влияет на пользовательский опыт и SEO. В этой статье мы рассмотрим комплексный подход к оптимизации.
Почему важна производительность?
- Пользовательский опыт: Быстрая загрузка и отзывчивость
- SEO: Высокие метрики Core Web Vitals
- Конверсия: Увеличение конверсии при хорошей производительности
- Затраты: Оптимизация использования ресурсов
Оптимизация фронтенда
1. Оптимизация загрузки
Минификация и сжатие
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| // webpack.config.js
module.exports = {
optimization: {
minimize: true,
minimizer: [
new TerserPlugin(),
new CssMinimizerPlugin()
]
},
plugins: [
new CompressionPlugin({
algorithm: 'gzip'
})
]
};
|
Код-сплиттинг
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| // React Router с ленивой загрузкой
const Dashboard = React.lazy(() => import('./Dashboard'));
const Profile = React.lazy(() => import('./Profile'));
function App() {
return (
<Suspense fallback={<Loading />}>
<Routes>
<Route path="/dashboard" element={<Dashboard />} />
<Route path="/profile" element={<Profile />} />
</Routes>
</Suspense>
);
}
|
2. Оптимизация изображений
Ленивая загрузка
1
2
3
4
5
6
| <img
src="placeholder.jpg"
data-src="actual-image.jpg"
loading="lazy"
alt="Description"
>
|
Оптимизация форматов
1
2
3
4
5
6
| // Использование современных форматов
<picture>
<source srcset="image.webp" type="image/webp">
<source srcset="image.jpg" type="image/jpeg">
<img src="image.jpg" alt="Description">
</picture>
|
3. Кэширование
Service Worker
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| // service-worker.js
const CACHE_NAME = 'v1';
const urlsToCache = [
'/',
'/styles.css',
'/script.js'
];
self.addEventListener('install', event => {
event.waitUntil(
caches.open(CACHE_NAME)
.then(cache => cache.addAll(urlsToCache))
);
});
|
HTTP кэширование
1
2
3
4
5
| # nginx.conf
location /static/ {
expires 1y;
add_header Cache-Control "public, no-transform";
}
|
Оптимизация бэкенда
1. Оптимизация базы данных
Индексация
1
2
3
4
5
| -- Создание индекса
CREATE INDEX idx_users_email ON users(email);
-- Составной индекс
CREATE INDEX idx_orders_user_date ON orders(user_id, created_at);
|
Оптимизация запросов
1
2
3
4
5
| // Использование проекций
const user = await User.findById(id).select('name email');
// Использование lean()
const users = await User.find().lean();
|
2. Кэширование на сервере
Redis кэширование
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| const redis = require('redis');
const client = redis.createClient();
async function getUser(id) {
// Проверка кэша
const cached = await client.get(`user:${id}`);
if (cached) return JSON.parse(cached);
// Получение из БД
const user = await User.findById(id);
// Сохранение в кэш
await client.set(`user:${id}`, JSON.stringify(user), 'EX', 3600);
return user;
}
|
Кэширование в памяти
1
2
3
4
5
6
7
8
9
10
11
| const NodeCache = require('node-cache');
const cache = new NodeCache({ stdTTL: 600 });
function getCachedData(key) {
let data = cache.get(key);
if (!data) {
data = fetchData();
cache.set(key, data);
}
return data;
}
|
Мониторинг производительности
1. Метрики Core Web Vitals
Измерение LCP
1
2
3
4
5
6
7
| new PerformanceObserver((entryList) => {
for (const entry of entryList.getEntries()) {
console.log('LCP:', entry.startTime);
// Отправка метрики
sendToAnalytics('LCP', entry.startTime);
}
}).observe({ entryTypes: ['largest-contentful-paint'] });
|
Измерение FID
1
2
3
4
5
6
7
| new PerformanceObserver((entryList) => {
for (const entry of entryList.getEntries()) {
console.log('FID:', entry.processingStart - entry.startTime);
// Отправка метрики
sendToAnalytics('FID', entry.processingStart - entry.startTime);
}
}).observe({ entryTypes: ['first-input'] });
|
2. Мониторинг сервера
Метрики Node.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| const promClient = require('prom-client');
// Создание метрик
const httpRequestDuration = new promClient.Histogram({
name: 'http_request_duration_seconds',
help: 'Duration of HTTP requests in seconds',
labelNames: ['method', 'route', 'status']
});
// Использование в middleware
app.use((req, res, next) => {
const start = Date.now();
res.on('finish', () => {
const duration = Date.now() - start;
httpRequestDuration
.labels(req.method, req.route.path, res.statusCode.toString())
.observe(duration / 1000);
});
next();
});
|
Оптимизация сети
1. HTTP/2
Настройка Nginx
1
2
3
4
| # nginx.conf
http2 on;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
|
2. CDN
Настройка CDN
1
2
3
4
5
6
| // Использование CDN для статических ресурсов
const CDN_URL = 'https://cdn.example.com';
// В HTML
<link rel="stylesheet" href="${CDN_URL}/styles.css">
<script src="${CDN_URL}/script.js"></script>
|
Оптимизация сборки
1. Tree Shaking
Настройка webpack
1
2
3
4
5
6
7
| // webpack.config.js
module.exports = {
optimization: {
usedExports: true,
sideEffects: true
}
};
|
2. Оптимизация бандлов
Анализ бандлов
1
2
3
4
5
6
7
8
9
10
11
| # Установка анализатора
npm install --save-dev webpack-bundle-analyzer
# Добавление в webpack
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = {
plugins: [
new BundleAnalyzerPlugin()
]
};
|
Оптимизация изображений
1. Оптимизация на этапе сборки
Настройка image-webpack-loader
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
| // webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.(png|jpe?g|gif|svg)$/i,
use: [
{
loader: 'image-webpack-loader',
options: {
mozjpeg: {
progressive: true,
quality: 65
},
optipng: {
enabled: false
},
pngquant: {
quality: [0.65, 0.90],
speed: 4
}
}
}
]
}
]
}
};
|
2. Оптимизация на лету
Использование Sharp
1
2
3
4
5
6
7
8
9
10
11
| const sharp = require('sharp');
async function optimizeImage(input, output) {
await sharp(input)
.resize(800, 600, {
fit: 'inside',
withoutEnlargement: true
})
.webp({ quality: 80 })
.toFile(output);
}
|
Заключение
Оптимизация производительности - это комплексный процесс, который требует внимания к различным аспектам разработки. Используйте инструменты мониторинга, следите за метриками и постоянно улучшайте производительность вашего приложения.
Полезные ресурсы